3 #include "ConnectionItem.h"
4 #include "InterfaceItem.h"
5 #include "Dispatcher.h"
6 #include "Parameters.h"
8 #include "AbstractBlock.h"
9 #include "AbstractInterface.h"
10 #include "ConnectedInterface.h"
11 #include "GroupScene.h"
12 #include "ParametersWindow.h"
13 #include "GroupBlock.h"
14 #include "GroupInterface.h"
17 GroupItem::GroupItem(BoxItem *_parentItem,
18 AbstractBlock *_refBlock,
19 Dispatcher *_dispatcher,
20 Parameters *_params) throw(Exception) :AbstractBoxItem( _refBlock, _dispatcher, _params) {
22 parentItem = _parentItem;
23 if (parentItem != NULL) {
24 parentItem->setChildGroupItem(this);
28 minimumBoxWidth = nameWidth+2*nameMargin;
29 minimumBoxHeight = 100;
30 boxHeight = minimumBoxHeight;
31 boxWidth = minimumBoxWidth;
33 rectTitle = QRectF(0,-(nameHeight+2*nameMargin),nameWidth+2*nameMargin,nameHeight+2*nameMargin);
35 totalHeight = boxHeight + rectTitle.height();
36 totalWidth = boxWidth;
43 setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
46 updateGeometry(InterfaceMove);
47 QPointF initPos = QPointF(0.0,0.0) - originPoint;
49 cout << "total size of group: " << totalWidth << "," << totalHeight << endl;
50 cout << "pos in scene: " << x() << "," << y() << endl;
53 GroupItem::GroupItem(Dispatcher *_dispatcher,Parameters *_params) throw(Exception) :AbstractBoxItem(_dispatcher, _params) {
56 rectTitle = QRectF(0,-(nameHeight+2*nameMargin),nameWidth+2*nameMargin,nameHeight+2*nameMargin);
59 setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
61 updateGeometry(InterfaceMove);
62 QPointF initPos = QPointF(0.0,0.0) - originPoint;
64 cout << "total size of group: " << totalWidth << "," << totalHeight << endl;
65 cout << "pos in scene: " << x() << "," << y() << endl;
68 GroupItem::~GroupItem() {
69 // since the reference block is nowhere referenced except in this class, it must be deleted here
73 bool GroupItem::isGroupItem() {
77 BoxItem* GroupItem::getParentItem() {
81 void GroupItem::setParentItem(BoxItem *_parentItem) {
82 parentItem = _parentItem;
83 if (parentItem != NULL) {
84 parentItem->setChildGroupItem(this);
88 void GroupItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
89 if(boxWidth > 0 && boxHeight > 0){
91 painter->setPen(Qt::red);
93 painter->setPen(Qt::black);
95 painter->drawRect(0,0,boxWidth,boxHeight);
96 painter->drawRect(rectTitle);
97 painter->drawText(rectTitle,Qt::AlignCenter | Qt::TextWordWrap,refBlock->getName());
99 foreach(InterfaceItem *item, interfaces){
100 item->paint(painter);
105 Each time a new block is added in a GroupItem, it is placed
106 at an absolute position of (0,0) within the GroupItem. (NB: the absolute
107 position is computed by item.pos()+item.getOriginPoint()).
108 Thus, there are 3 cases :
109 - a single block is within the GroupItem
110 - several blocks already placed and a new one
111 - several blocks already placed and one is moving.
114 void GroupItem::updateMinimumSize() {
116 // compute place taken by blocks.
117 int marginConn = 2*(params->arrowWidth+params->arrowLineLength);
118 if (rectTitle.width() > 2*marginConn) {
119 minimumBoxWidth = rectTitle.width();
122 minimumBoxWidth = 2*marginConn;
124 minimumBoxHeight = 2*marginConn;
126 if (getScene() == NULL) return;
128 QList<BoxItem *> blocks = getScene()->getBoxItems();
129 if(blocks.length() > 0) {
130 // first, search for blocks that are at (0,0)
135 bool isZeroBlocks = false;
136 bool isOtherBlocks = false;
137 foreach(BoxItem* item, blocks) {
138 QPointF p = item->pos() + item->getOriginPoint();
139 if ((p.x()==0.0) && (p.y()==0.0)) {
141 if (item->getTotalWidth() > xMaxZero) {
142 xMaxZero = item->getTotalWidth();
144 if (item->getTotalHeight() > yMaxZero) {
145 yMaxZero = item->getTotalHeight();
149 isOtherBlocks = true;
150 if(p.x()+item->getTotalWidth() > xMax) {
151 xMax = p.x()+item->getTotalWidth();
153 if(p.y()+item->getTotalHeight() > yMax) {
154 yMax = p.y()+item->getTotalHeight();
159 if (!isOtherBlocks) {
160 minimumBoxWidth = xMaxZero+2*marginConn;
161 minimumBoxHeight = yMaxZero+2*marginConn;
164 if (xMaxZero+marginConn > xMax) {
165 minimumBoxWidth = xMaxZero+2*marginConn;
168 minimumBoxWidth = xMax+marginConn;
170 if (yMaxZero+marginConn > yMax) {
171 minimumBoxHeight = yMaxZero+2*marginConn;
174 minimumBoxHeight = yMax+marginConn;
179 minimumBoxWidth = xMax+marginConn;
180 minimumBoxHeight = yMax+marginConn;
183 //cout << "min group size: " << minimumBoxWidth << "," << minimumBoxHeight << endl;
186 void GroupItem::updateShape() {
187 updateGeometry(InterfaceMove);
190 bool GroupItem::updateGeometry(ChangeType type) {
192 QPointF oldOrigin = originPoint;
193 QSize oldSize(totalWidth,totalHeight);
195 bool boxSizeChanged = false;
197 // whatever the change, the minimum size may have changed
200 if (type == Resize) {
201 boxSizeChanged = true;
203 // if an internal block has moved, the actual box size may be inadequate
204 if (boxWidth < minimumBoxWidth) {
205 boxWidth = minimumBoxWidth;
206 boxSizeChanged = true;
208 if (boxHeight < minimumBoxHeight) {
209 boxHeight = minimumBoxHeight;
210 boxSizeChanged = true;
213 if (boxSizeChanged) {
214 updateInterfacesAndConnections();
218 // compute the max. width of interfaces' name for 4 orientations.
225 foreach(InterfaceItem* iface, interfaces) {
226 ifaceWidth = iface->getNameWidth();
227 if (iface->getOrientation() == Parameters::South) {
228 if (ifaceWidth > maxSouth) maxSouth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
230 else if (iface->getOrientation() == Parameters::North) {
231 if (ifaceWidth > maxNorth) maxNorth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
233 else if (iface->getOrientation() == Parameters::East) {
234 if (ifaceWidth > maxEast) maxEast = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
236 else if (iface->getOrientation() == Parameters::West) {
237 if (ifaceWidth > maxWest) maxWest = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
242 totalWidth = boxWidth+maxEast;
243 totalHeight = boxHeight+maxSouth;
247 totalWidth += maxWest;
249 if (maxNorth > (nameHeight+2*nameMargin)) {
251 totalHeight += maxNorth;
254 y -= nameHeight+2*nameMargin;
255 totalHeight += nameHeight+2*nameMargin;
257 QSizeF newSize(totalWidth,totalHeight);
261 if ((boxSizeChanged) || (newSize != oldSize) || (originPoint != oldOrigin)) {
262 cout << "GroupItem: must change group item shape" << endl;
263 prepareGeometryChange();
269 void GroupItem::nameChanged() {
272 QFontMetrics fmId(params->defaultBlockFont);
273 nameWidth = fmId.width(refBlock->getName());
274 nameHeight = fmId.height();
275 // changing the BoxItem in the upperscene
276 if (parentItem != NULL) {
277 parentItem->nameChanged();
279 updateGeometry(InterfaceMove);
280 // force the update in case of the size has not changed
285 void GroupItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
287 if(params->editState == Parameters::EditGroupMove) {
288 QPointF absPos = currentPosition + originPoint;
289 int gapX = event->scenePos().x() - cursorPosition.x();
290 int gapY = event->scenePos().y() - cursorPosition.y();
292 //cout << "block abs. pos: " << absPos.x() << "," << absPos.y() << " | ";
293 //cout << "block current. pos: " << currentPosition.x() << "," << currentPosition.y() << " | ";
295 if (absPos.x()+gapX < 0) {
298 if (absPos.y()+gapY < 0) {
302 //cout << "gap: " << gapX << "," << gapY << " | ";
303 //cout << "scene: " << getScene()->sceneRect().x() << "," << getScene()->sceneRect().y() << endl;
304 QPointF gap(gapX,gapY);
305 currentPosition = currentPosition+gap;
306 setPos(currentPosition);
307 cursorPosition = event->scenePos();
309 else if(params->editState == Parameters::EditGroupResize) {
311 int gapX = event->scenePos().x() - cursorPosition.x();
312 int gapY = event->scenePos().y() - cursorPosition.y();
313 //cout << "gap: " << gapX << "," << gapY << endl;
314 switch(currentBorder){
316 if(boxWidth+gapX > minimumBoxWidth){
322 if(boxHeight+gapY > minimumBoxHeight){
327 case CornerSouthEast: {
328 if(boxWidth+gapX > minimumBoxWidth){
331 if(boxHeight+gapY > minimumBoxHeight){
337 cout << "abnormal case while resizing block" << endl;
340 updateGeometry(Resize);
342 // recompute the geometry of the block
344 // update all interfaces positions
345 foreach(InterfaceItem *item, interfaces){
346 item->updatePosition();
348 // update all connections from/to this block
349 foreach(ConnectionItem *item, getScene()->getConnectionItems()){
350 if ((item->getFromInterfaceItem()->getOwner() == this) || (item->getToInterfaceItem()->getOwner() == this)) {
355 cursorPosition = event->scenePos();
357 else if(params->editState == Parameters::EditInterfaceMove) {
358 prepareGeometryChange();
359 moveInterfaceTo(event->pos());
360 // recompute the geometry of the block
361 updateGeometry(InterfaceMove);
362 // update connection from/to the selected interface
363 foreach(ConnectionItem *item, getScene()->getConnectionItems()){
364 if ((item->getFromInterfaceItem() == currentInterface) || (item->getToInterfaceItem() == currentInterface)) {
372 void GroupItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
374 QPointF pos = event->pos();
378 QGraphicsItem::mousePressEvent(event);
380 if(event->button() == Qt::RightButton) return;
382 int mode = getScene()->getEditionMode();
384 dispatcher->setCurrentGroupWidget(getScene()->getGroupWidget());
386 /* NOTE : commneted because group interface are normally
387 created and the connected directly to a block within
388 the group. Furthermore, there can be a single connection
389 from a groupe interface.
391 if ((mode == GroupScene::AddConnection) && (params->cursorState == Parameters::CursorOnInterface)) {
392 InterfaceItem *inter = getInterfaceFromCursor(x,y);
395 if (params->editState == Parameters::EditNoOperation) {
396 getScene()->setSelectedInterface(1,inter);
397 params->setEditState(Parameters::EditStartConnection);
399 else if (params->editState == Parameters::EditStartConnection) {
400 if (inter == getScene()->getSelectedInterface(1)) {
401 params->setEditState(Parameters::EditAbortConnection);
404 getScene()->setSelectedInterface(2,inter);
405 params->setEditState(Parameters::EditCloseConnection);
411 if (mode == GroupScene::ItemEdition) {
413 if (params->cursorState == Parameters::CursorOnInterface) {
414 InterfaceItem *inter = getInterfaceFromCursor(x,y);
416 currentInterface = inter;
417 params->setEditState(Parameters::EditInterfaceMove);
420 else if (params->cursorState == Parameters::CursorInGroupTitle) {
421 params->setEditState(Parameters::EditGroupMove);
422 cursorPosition = event->scenePos();
424 else if (params->cursorState == Parameters::CursorOnBorder) {
425 setFlag(ItemIsMovable, false);
426 cursorPosition = event->scenePos();
427 params->setEditState(Parameters::EditGroupResize);
432 void GroupItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
434 int mode = getScene()->getEditionMode();
436 /* NOTE : commneted because group interface are normally
437 created and the connected directly to a block within
438 the group. Furthermore, there can be a single connection
439 from a groupe interface.
441 if (mode == GroupScene::AddConnection) {
443 if (params->editState == Parameters::EditStartConnection) {
444 params->setEditState(Parameters::EditStartConnection);
445 InterfaceItem* iface = getScene()->getSelectedInterface(1);
446 iface->selected = true;
447 update(iface->boundingRect());
449 else if (params->editState == Parameters::EditAbortConnection) {
450 InterfaceItem* iface = getScene()->getSelectedInterface(1);
451 iface->selected = false;
452 update(iface->boundingRect());
453 getScene()->setSelectedInterface(1,NULL);
454 params->setEditState(Parameters::EditNoOperation);
456 else if (params->editState == Parameters::EditCloseConnection) {
457 InterfaceItem* iface1 = getScene()->getSelectedInterface(1);
458 InterfaceItem* iface2 = getScene()->getSelectedInterface(2);
459 bool ok = dispatcher->connect(iface1,iface2);
461 iface1->selected = false;
462 update(iface1->boundingRect());
463 getScene()->setSelectedInterface(1,NULL);
464 getScene()->setSelectedInterface(2,NULL);
465 params->setEditState(Parameters::EditNoOperation);
470 if (mode == GroupScene::ItemEdition) {
471 currentInterface = NULL;
472 setFlag(ItemIsMovable, true);
473 params->editState = Parameters::EditNoOperation;
475 QGraphicsItem::mouseReleaseEvent(event);
478 void GroupItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
479 QPointF pos = event->pos();
482 currentBorder = NoBorder;
483 int mode = getScene()->getEditionMode();
485 if (mode == GroupScene::AddConnection) {
486 InterfaceItem* iface = getInterfaceFromCursor(x,y);
488 params->cursorState = Parameters::CursorOnInterface;
489 setCursor(Qt::PointingHandCursor);
492 params->cursorState = Parameters::CursorNowhere;
493 setCursor(Qt::ArrowCursor);
496 else if (mode == GroupScene::ItemEdition) {
500 InterfaceItem* iface = getInterfaceFromCursor(x,y);
502 params->cursorState = Parameters::CursorOnInterface;
503 setCursor(Qt::PointingHandCursor);
505 else if ((x>boxWidth-marginE)&&(x<boxWidth)) {
507 params->cursorState = Parameters::CursorOnBorder;
509 if ((y>boxHeight-2*marginS)&&(y<boxHeight)) {
510 currentBorder = CornerSouthEast;
511 setCursor(Qt::SizeFDiagCursor);
514 currentBorder = BorderEast;
515 setCursor(Qt::SizeHorCursor);
518 else if ((y>boxHeight-marginS)&&(y<boxHeight)) {
520 params->cursorState = Parameters::CursorOnBorder;
522 if ((x>boxWidth-2*marginE)&&(x<boxWidth)) {
523 currentBorder = CornerSouthEast;
524 setCursor(Qt::SizeFDiagCursor);
527 currentBorder = BorderSouth;
528 setCursor(Qt::SizeVerCursor);
532 if (rectTitle.contains(x,y)) {
533 params->cursorState = Parameters::CursorInGroupTitle;
534 setCursor(Qt::OpenHandCursor);
537 params->cursorState = Parameters::CursorNowhere;
538 setCursor(Qt::ArrowCursor);
542 QGraphicsItem::hoverMoveEvent(event);
545 void GroupItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
547 QAction* titleAction = NULL;
548 QAction* showProperties = NULL;
549 QAction* removeAction = NULL;
550 QAction* renameAction = NULL;
551 QAction* showParameters = NULL;
553 InterfaceItem* ifaceItem = getInterfaceFromCursor(event->pos().x(), event->pos().y());
555 // menu for interface
556 if( ifaceItem != NULL) {
557 titleAction = menu.addAction("Interface operations");
558 titleAction->setEnabled(false);
560 showProperties = menu.addAction("Show properties");
561 renameAction = menu.addAction("Rename");
563 /* CAUTION : the interface can be removed only if its
564 connected to only one side, i.e. connectedFrom is null
565 or connectedTo is empty.
568 ConnectedInterface* ref = ifaceItem->refInter;
569 if ((!ref->isConnectedFrom()) || (!ref->isConnectedTo())) {
570 removeAction = menu.addAction("Remove");
574 titleAction = menu.addAction("Block operations");
575 titleAction->setEnabled(false);
578 if (refBlock->nbParameters() > 0) {
579 showParameters = menu.addAction("Show parameters");
581 renameAction = menu.addAction("Rename");
583 QAction* selectedAction = menu.exec(event->screenPos());
585 if(selectedAction == NULL) return;
587 if(selectedAction == renameAction){
588 if(ifaceItem != NULL)
589 dispatcher->renameInterface(ifaceItem);
591 dispatcher->renameGroupBlock(this);
593 else if(selectedAction == showProperties){
594 dispatcher->showProperties(ifaceItem);
596 else if (selectedAction == removeAction) {
597 dispatcher->removeGroupInterface(ifaceItem);
599 else if(selectedAction == showParameters) {
600 new ParametersWindow(refBlock, params, NULL);
604 InterfaceItem* GroupItem::isHoverInterface(QPointF point) {
605 foreach(InterfaceItem *inter, interfaces){
606 if(inter->boundingRect().contains(point))
612 void GroupItem::load(QDomElement groupElement) throw(Exception) {
614 GroupBlock* groupBlock = AB_TO_GRP(refBlock);
618 int id = groupElement.attribute("id","none").toInt(&ok);
619 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
621 QString nameStr = groupElement.attribute("name","none");
622 if(nameStr == "none") throw(Exception(PROJECTFILE_CORRUPTED));
624 QStringList positionStr = groupElement.attribute("position","none").split(",");
625 if(positionStr.length() != 2) throw(Exception(PROJECTFILE_CORRUPTED));
626 int posX = positionStr.at(0).toInt(&ok);
627 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
628 int posY = positionStr.at(1).toInt(&ok);
629 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
631 QStringList dimensionStr = groupElement.attribute("dimension","none").split(",");
632 if(dimensionStr.length() != 2) throw(Exception(PROJECTFILE_CORRUPTED));
633 int dimX = dimensionStr.at(0).toInt(&ok);
634 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
635 int dimY = dimensionStr.at(1).toInt(&ok);
636 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
640 setDimension(dimX,dimY);
641 groupBlock->setName(nameStr);
643 cout << "group info : \n-id : " << id << "\n-pos : " << posX << ", " << posY << "\n-dim : " << dimX << ", " << dimY << "\n-name : " << nameStr.toStdString() << endl;
645 QDomNodeList interfaces = groupElement.elementsByTagName("group_iface");
646 for(int j=0; j<interfaces.length(); j++){
647 QDomElement currentInterfaceNode = interfaces.at(j).toElement();
649 int id = currentInterfaceNode.attribute("id","none").toInt(&ok);
650 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
652 QString name = currentInterfaceNode.attribute("name","none");
653 if(name == "none") throw(Exception(PROJECTFILE_CORRUPTED));
655 QString directionStr = currentInterfaceNode.attribute("direction","none");
656 int direction = AbstractInterface::getIntDirection(directionStr);
657 if(direction == -1) throw(Exception(PROJECTFILE_CORRUPTED));
659 QString orientationStr = currentInterfaceNode.attribute("orientation","none");
660 int orientation = InterfaceItem::getIntOrientation(orientationStr);
661 if(orientation == -1) throw(Exception(PROJECTFILE_CORRUPTED));
663 double position = currentInterfaceNode.attribute("position","none").toDouble(&ok);
664 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
666 GroupInterface *groupInterface = new GroupInterface(groupBlock,name,direction,AbstractInterface::Data);
668 InterfaceItem *interfaceItem = new InterfaceItem(position,orientation,groupInterface,this,params);
669 interfaceItem->setId(id);
671 groupBlock->addInterface(groupInterface);
672 addInterface(interfaceItem, false);
673 cout << "interface add to " << groupBlock->getName().toStdString() << endl;
678 void GroupItem::save(QXmlStreamWriter &writer) {
680 writer.writeStartElement("group_item");
682 QString attrId = QString::number(id);
683 QString attrName(getRefBlock()->getName());
684 QString attrUpperItem = QString::number(-1);
685 if(parentItem != NULL){
686 attrUpperItem = QString::number(parentItem->getId());
688 QString attrPos = QString::number((int)(pos().x())).append(",").append(QString::number((int)(pos().y())));
689 QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight()));
692 writer.writeAttribute("id",attrId);
693 writer.writeAttribute("upper_item",attrUpperItem);
694 writer.writeAttribute("name",attrName);
695 writer.writeAttribute("position", attrPos);
696 writer.writeAttribute("dimension", attrDim);
698 writer.writeStartElement("group_ifaces");
700 writer.writeAttribute("count",QString::number(interfaces.length()));
702 foreach(InterfaceItem *item, interfaces){
703 writer.writeStartElement("group_iface");
705 writer.writeAttribute("id",QString::number(item->getId()));
706 writer.writeAttribute("name",item->getName());
707 writer.writeAttribute("direction",QString(item->refInter->getDirectionString()));
708 writer.writeAttribute("orientation",item->getStrOrientation());
709 writer.writeAttribute("position",QString::number(item->getPositionRatio()));
711 writer.writeEndElement();
714 writer.writeEndElement();//</interfaces>
716 writer.writeEndElement();//</group_item>