]> AND Private Git Repository - blast.git/blob - GroupItem.cpp
Logo AND Algorithmique Numérique Distribuée

Private GIT Repository
04d7bca0aae011f4960492661bc68ad021951f0a
[blast.git] / GroupItem.cpp
1 #include "GroupItem.h"
2
3 #include "ConnectionItem.h"
4 #include "InterfaceItem.h"
5 #include "Dispatcher.h"
6 #include "Parameters.h"
7 #include "BoxItem.h"
8 #include "AbstractBlock.h"
9 #include "AbstractInterface.h"
10 #include "ConnectedInterface.h"
11 #include "GroupScene.h"
12
13
14 GroupItem::GroupItem(BoxItem *_parentItem,
15                      AbstractBlock *_refBlock,
16                      Dispatcher *_dispatcher,
17                      Parameters *_params) throw(Exception) :AbstractBoxItem( _refBlock, _dispatcher, _params) {
18
19   parentItem = _parentItem;
20
21   /*
22   minimumBoxWidth = nameWidth+2*nameMargin;
23   minimumBoxHeight = 100;
24   boxHeight = minimumBoxHeight;
25   boxWidth = minimumBoxWidth;
26   */
27   rectTitle = QRectF(0,-(nameHeight+2*nameMargin),nameWidth+2*nameMargin,nameHeight+2*nameMargin);
28   /*
29   totalHeight = boxHeight + rectTitle.height();
30   totalWidth = boxWidth;
31 */
32   selected = false;
33
34
35   setZValue(-100);
36
37   setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);  
38
39   updateGeometry();
40   QPointF initPos = QPointF(0.0,0.0) - originPoint;
41   setPos(initPos);
42   cout << "total size of group: " << totalWidth << "," << totalHeight << endl;
43   cout << "pos in scene: " << x() << "," << y() << endl;
44 }
45
46 GroupItem::~GroupItem() {
47   // since the reference block is nowhere referenced except in this class, it must be deleted here
48   delete refBlock;
49 }
50
51 bool GroupItem::isGroupItem() {
52   return true;
53 }
54
55 BoxItem* GroupItem::getParentItem() {
56   return parentItem;
57 }
58
59 void GroupItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
60   if(boxWidth > 0 && boxHeight > 0){
61     if(selected)
62       painter->setPen(Qt::red);
63     else
64       painter->setPen(Qt::black);
65
66     painter->drawRect(0,0,boxWidth,boxHeight);
67     painter->drawRect(rectTitle);
68     painter->drawText(rectTitle,Qt::AlignCenter | Qt::TextWordWrap,refBlock->getName());
69   }
70   foreach(InterfaceItem *item, interfaces){    
71     item->paint(painter);
72   }
73 }
74
75 /* NOTE:
76    Each time a new block is added in a GroupItem, it is placed
77    at an absolute position of (0,0) within the GroupItem. (NB: the absolute
78    position is computed by item.pos()+item.getOriginPoint()).
79    Thus, there are 3 cases :
80    - a single block is within the GroupItem
81    - several blocks already placed and a new one
82    - several blocks already placed and one is moving.
83
84  */
85 void GroupItem::updateMinimumSize() {
86
87   // compute place taken by blocks.
88   int marginConn = 2*(params->arrowWidth+params->arrowLineLength);
89   if (rectTitle.width() > 2*marginConn) {
90     minimumBoxWidth = rectTitle.width();
91   }
92   else {
93     minimumBoxWidth = 2*marginConn;
94   }
95   minimumBoxHeight = 2*marginConn;
96
97   if (getScene() == NULL) return;
98
99   QList<BoxItem *> blocks = getScene()->getBlockItems();
100   if(blocks.length() > 0) {
101     // first, search for blocks that are at (0,0)
102     int xMaxZero = 0;
103     int yMaxZero = 0;
104     int xMax = 0;
105     int yMax = 0;
106     bool isZeroBlocks = false;
107     bool isOtherBlocks = false;
108     foreach(BoxItem* item, blocks) {
109       QPointF p = item->pos() + item->getOriginPoint();
110       if ((p.x()==0.0) && (p.y()==0.0)) {
111         isZeroBlocks = true;
112         if (item->getTotalWidth() > xMaxZero) {
113           xMaxZero = item->getTotalWidth();
114         }
115         if (item->getTotalHeight() > yMaxZero) {
116           yMaxZero = item->getTotalHeight();
117         }
118       }
119       else {
120         isOtherBlocks = true;
121         if(p.x()+item->getTotalWidth() > xMax) {
122           xMax = p.x()+item->getTotalWidth();
123         }
124         if(p.y()+item->getTotalHeight() > yMax) {
125           yMax = p.y()+item->getTotalHeight();
126         }
127       }
128     }
129     if (isZeroBlocks) {
130       if (!isOtherBlocks) {
131         minimumBoxWidth = xMaxZero+2*marginConn;
132         minimumBoxHeight = yMaxZero+2*marginConn;
133       }
134       else {
135         if (xMaxZero+marginConn > xMax) {
136           minimumBoxWidth = xMaxZero+2*marginConn;
137         }
138         else {
139           minimumBoxWidth = xMax+marginConn;
140         }
141         if (yMaxZero+marginConn > yMax) {
142           minimumBoxHeight = yMaxZero+2*marginConn;
143         }
144         else {
145           minimumBoxHeight = yMax+marginConn;
146         }
147       }
148     }
149     else {
150       minimumBoxWidth = xMax+marginConn;
151       minimumBoxHeight = yMax+marginConn;
152     }
153   }
154   //cout << "min group size: " << minimumBoxWidth << "," << minimumBoxHeight << endl;
155 }
156
157 void GroupItem::updateShape() {
158   updateGeometry();
159 }
160
161 bool GroupItem::updateGeometry(ChangeType type) {
162
163   QPointF oldOrigin = originPoint;
164   QSize oldSize(totalWidth,totalHeight);
165
166   updateMinimumSize();
167   bool boxSizeChanged = false;
168   if (boxWidth < minimumBoxWidth) {
169     boxWidth = minimumBoxWidth;
170     boxSizeChanged = true;
171   }
172   if (boxHeight < minimumBoxHeight) {
173     boxHeight = minimumBoxHeight;
174      boxSizeChanged = true;
175   }
176   if (boxSizeChanged) {
177     updateInterfacesAndConnections();
178   }
179
180   // compute the max. width of interfaces' name for 4 orientations.  
181   int maxSouth = 0;
182   int maxNorth = 0;
183   int maxEast = 0;
184   int maxWest = 0;
185   int ifaceWidth = 0;
186
187   foreach(InterfaceItem* iface, interfaces) {
188     ifaceWidth = iface->getNameWidth();
189     if (iface->getOrientation() == Parameters::South) {
190       if (ifaceWidth > maxSouth) maxSouth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
191     }
192     else if (iface->getOrientation() == Parameters::North) {
193       if (ifaceWidth > maxNorth) maxNorth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
194     }
195     else if (iface->getOrientation() == Parameters::East) {
196       if (ifaceWidth > maxEast) maxEast = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
197     }
198     else if (iface->getOrientation() == Parameters::West) {
199       if (ifaceWidth > maxWest) maxWest = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
200     }
201   }
202   double x = 0.0;
203   double y = 0.0;
204   totalWidth = boxWidth+maxEast;
205   totalHeight = boxHeight+maxSouth;
206
207   if (maxWest > 0) {
208     x -= maxWest;
209     totalWidth += maxWest;
210   }
211   if (maxNorth > (nameHeight+2*nameMargin)) {
212     y -= maxNorth;
213     totalHeight += maxNorth;
214   }
215   else {
216     y -= nameHeight+2*nameMargin;
217     totalHeight += nameHeight+2*nameMargin;
218   }
219   QSizeF newSize(totalWidth,totalHeight);
220   originPoint.setX(x);
221   originPoint.setY(y);
222
223   if ((boxSizeChanged) || (newSize != oldSize) || (originPoint != oldOrigin)) {
224     //cout << "must change group item shape" << endl;
225     prepareGeometryChange();
226     return true;
227   }
228   return false;
229 }
230
231 void GroupItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
232
233   if(params->editState == Parameters::EditGroupMove) {
234     QPointF absPos = currentPosition + originPoint;    
235     int gapX = event->scenePos().x() - cursorPosition.x();
236     int gapY = event->scenePos().y() - cursorPosition.y();
237
238     //cout << "block abs. pos: " << absPos.x() << "," << absPos.y() << " | ";
239     //cout << "block current. pos: " << currentPosition.x() << "," << currentPosition.y() << " | ";
240 /*
241     if (absPos.x()+gapX < 0) {
242       gapX = -absPos.x();
243     }
244     if (absPos.y()+gapY < 0) {
245       gapY = -absPos.y();
246     }
247     */
248     //cout << "gap: " << gapX << "," << gapY << " | ";
249     //cout << "scene: " << getScene()->sceneRect().x() << "," << getScene()->sceneRect().y() << endl;
250     QPointF gap(gapX,gapY);
251     currentPosition = currentPosition+gap;
252     setPos(currentPosition);
253     cursorPosition = event->scenePos();
254   }
255   else if(params->editState == Parameters::EditGroupResize) {
256
257     int gapX = event->scenePos().x() - cursorPosition.x();
258     int gapY = event->scenePos().y() - cursorPosition.y();
259     //cout << "gap: " << gapX << "," << gapY << endl;
260     switch(currentBorder){
261     case BorderEast: {
262       if(boxWidth+gapX > minimumBoxWidth){
263         boxWidth += gapX;
264       }
265       break;
266     }
267     case BorderSouth: {
268       if(boxHeight+gapY > minimumBoxHeight){
269         boxHeight += gapY;
270       }
271       break;
272     }
273     case CornerSouthEast: {
274       if(boxWidth+gapX > minimumBoxWidth){
275         boxWidth += gapX;
276       }
277       if(boxHeight+gapY > minimumBoxHeight){
278         boxHeight += gapY;
279       }
280       break;
281     }
282     case NoBorder:
283       cout << "abnormal case while resizing block" << endl;
284       break;
285     }
286     updateGeometry();
287     /*
288     // recompute the geometry of the block
289     updateGeometry();
290     // update all interfaces positions
291     foreach(InterfaceItem *item, interfaces){
292       item->updatePosition();
293     }
294     // update all connections from/to this block
295     foreach(ConnectionItem *item, getScene()->getConnectionItems()){
296       if ((item->getFromInterfaceItem()->getOwner() == this) || (item->getToInterfaceItem()->getOwner() == this)) {
297         item->setPathes();
298       }
299     }
300     */
301     cursorPosition = event->scenePos();
302   }
303   else if(params->editState == Parameters::EditInterfaceMove) {
304     prepareGeometryChange();
305     deplaceInterface(event->pos());
306     // recompute the geometry of the block
307     updateGeometry();
308     // update connection from/to the selected interface
309     foreach(ConnectionItem *item, getScene()->getConnectionItems()){
310       if ((item->getFromInterfaceItem() == currentInterface) || (item->getToInterfaceItem() == currentInterface)) {
311         item->setPathes();
312       }
313     }
314     update();
315   }
316 }
317
318 void GroupItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
319
320   QPointF pos = event->pos();
321   qreal x = pos.x();
322   qreal y = pos.y();
323
324   QGraphicsItem::mousePressEvent(event);
325
326   if(event->button() == Qt::RightButton) return;
327
328   int mode = getScene()->getEditionMode();
329
330   dispatcher->setCurrentGroupWidget(getScene()->getGroupWindow());
331
332   /* NOTE : commneted because group interface are normally
333      created and the connected directly to a block within
334      the group. Furthermore, there can be a single connection
335      from a groupe interface.
336
337   if ((mode == GroupScene::AddConnection) && (params->cursorState == Parameters::CursorOnInterface)) {
338     InterfaceItem *inter = getInterfaceFromCursor(x,y);
339     if (inter != NULL) {
340
341       if (params->editState == Parameters::EditNoOperation) {
342         getScene()->setSelectedInterface(1,inter);
343         params->setEditState(Parameters::EditStartConnection);
344       }
345       else if (params->editState == Parameters::EditStartConnection) {
346         if (inter == getScene()->getSelectedInterface(1)) {
347           params->setEditState(Parameters::EditAbortConnection);
348         }
349         else {
350           getScene()->setSelectedInterface(2,inter);
351           params->setEditState(Parameters::EditCloseConnection);
352         }
353       }
354     }
355   }
356   */
357   if (mode == GroupScene::ItemEdition) {
358
359     if (params->cursorState == Parameters::CursorOnInterface) {
360       InterfaceItem *inter = getInterfaceFromCursor(x,y);
361       if (inter != NULL) {
362         currentInterface = inter;
363         params->setEditState(Parameters::EditInterfaceMove);
364       }
365     }
366     else if (params->cursorState == Parameters::CursorInGroupTitle) {
367       params->setEditState(Parameters::EditGroupMove);
368       cursorPosition = event->scenePos();
369     }
370     else if (params->cursorState == Parameters::CursorOnBorder) {
371       setFlag(ItemIsMovable, false);
372       cursorPosition = event->scenePos();
373       params->setEditState(Parameters::EditGroupResize);
374     }
375   }
376 }
377
378 void GroupItem::mouseReleaseEvent(QGraphicsSceneMouseEvent  *event) {
379
380   int mode = getScene()->getEditionMode();
381
382   /* NOTE : commneted because group interface are normally
383      created and the connected directly to a block within
384      the group. Furthermore, there can be a single connection
385      from a groupe interface.
386
387   if (mode == GroupScene::AddConnection) {
388
389     if (params->editState == Parameters::EditStartConnection) {
390       params->setEditState(Parameters::EditStartConnection);
391       InterfaceItem* iface = getScene()->getSelectedInterface(1);
392       iface->selected = true;
393       update(iface->boundingRect());
394     }
395     else if (params->editState == Parameters::EditAbortConnection) {
396       InterfaceItem* iface = getScene()->getSelectedInterface(1);
397       iface->selected = false;
398       update(iface->boundingRect());
399       getScene()->setSelectedInterface(1,NULL);
400       params->setEditState(Parameters::EditNoOperation);
401     }
402     else if (params->editState == Parameters::EditCloseConnection) {
403       InterfaceItem* iface1 = getScene()->getSelectedInterface(1);
404       InterfaceItem* iface2 = getScene()->getSelectedInterface(2);
405       bool ok = dispatcher->connect(iface1,iface2);
406       if (ok) {
407         iface1->selected = false;
408         update(iface1->boundingRect());
409         getScene()->setSelectedInterface(1,NULL);
410         getScene()->setSelectedInterface(2,NULL);
411         params->setEditState(Parameters::EditNoOperation);
412       }
413     }
414   }
415   */
416   if (mode == GroupScene::ItemEdition) {
417     currentInterface = NULL;
418     setFlag(ItemIsMovable, true);
419     params->editState = Parameters::EditNoOperation;
420   }
421   QGraphicsItem::mouseReleaseEvent(event);
422 }
423
424 void GroupItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
425   QPointF pos = event->pos();
426   qreal x = pos.x();
427   qreal y = pos.y();
428   currentBorder = NoBorder;
429   int mode = getScene()->getEditionMode();
430
431   if (mode == GroupScene::AddConnection) {
432     InterfaceItem* iface = getInterfaceFromCursor(x,y);
433     if (iface != NULL) {
434       params->cursorState = Parameters::CursorOnInterface;
435       setCursor(Qt::PointingHandCursor);
436     }
437     else {
438       params->cursorState = Parameters::CursorNowhere;
439       setCursor(Qt::ArrowCursor);
440     }
441   }
442   else if (mode == GroupScene::ItemEdition) {
443     int marginE = 5;
444     int marginS = 5;
445
446     InterfaceItem* iface = getInterfaceFromCursor(x,y);
447     if (iface != NULL) {
448       params->cursorState = Parameters::CursorOnInterface;
449       setCursor(Qt::PointingHandCursor);
450     }
451     else if ((x>boxWidth-marginE)&&(x<boxWidth)) {
452
453       params->cursorState = Parameters::CursorOnBorder;
454
455       if ((y>boxHeight-2*marginS)&&(y<boxHeight)) {
456         currentBorder = CornerSouthEast;
457         setCursor(Qt::SizeFDiagCursor);
458       }
459       else {
460         currentBorder = BorderEast;
461         setCursor(Qt::SizeHorCursor);
462       }
463     }
464     else if ((y>boxHeight-marginS)&&(y<boxHeight)) {
465
466       params->cursorState = Parameters::CursorOnBorder;
467
468       if ((x>boxWidth-2*marginE)&&(x<boxWidth)) {
469         currentBorder = CornerSouthEast;
470         setCursor(Qt::SizeFDiagCursor);
471       }
472       else {
473         currentBorder = BorderSouth;
474         setCursor(Qt::SizeVerCursor);
475       }
476     }
477     else {
478       if (rectTitle.contains(x,y)) {
479         params->cursorState = Parameters::CursorInGroupTitle;
480         setCursor(Qt::OpenHandCursor);
481       }
482       else {
483         params->cursorState = Parameters::CursorNowhere;
484         setCursor(Qt::ArrowCursor);
485       }
486     }
487   }
488   QGraphicsItem::hoverMoveEvent(event);
489 }
490
491 void GroupItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
492   QMenu menu;
493   QAction* showProperties = NULL;
494   QAction* removeAction = NULL;
495   QAction* renameAction = NULL;
496
497   InterfaceItem* ifaceItem = getInterfaceFromCursor(event->pos().x(), event->pos().y());
498   if( ifaceItem != NULL){
499     showProperties = menu.addAction("Show properties");
500     renameAction = menu.addAction("Rename");
501     menu.addSeparator();
502     /* CAUTION : the interface can be removed only if its
503       connected to only one side, i.e. connectedFrom is null
504       or connectedTo is empty.
505
506     */
507     ConnectedInterface* ref = ifaceItem->refInter;
508     if ((!ref->isConnectedFrom()) || (!ref->isConnectedTo())) {
509       removeAction = menu.addAction("Remove");
510     }
511   }
512   else {
513     renameAction = menu.addAction("Rename");
514   }
515   QAction* selectedAction = menu.exec(event->screenPos());
516
517   if(selectedAction == NULL) return;
518
519   if(selectedAction == renameAction){
520     if(ifaceItem != NULL)
521       dispatcher->rename(ifaceItem);
522     else
523       dispatcher->rename(this);
524   }
525   else if(selectedAction == showProperties){
526     dispatcher->showProperties(ifaceItem);
527   }
528   else if (selectedAction == removeAction) {
529     dispatcher->removeGroupInterface(ifaceItem);
530   }
531 }
532
533 InterfaceItem* GroupItem::isHoverInterface(QPointF point) {
534   foreach(InterfaceItem *inter, interfaces){
535     if(inter->boundingRect().contains(point))
536       return inter;
537   }
538   return NULL;
539 }
540
541 void GroupItem::save(QXmlStreamWriter &writer) {
542
543   writer.writeStartElement("group_item");
544
545   QString attrId = QString::number(id);
546   QString attrName(getRefBlock()->getName());
547   QString attrUpperItem = QString::number(-1);
548   if(parentItem != NULL){
549     attrUpperItem = QString::number(parentItem->getId());
550   }
551   QString attrPos = QString::number(pos().x()).append(",").append(QString::number(pos().y()));
552   QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight()));
553
554
555   writer.writeAttribute("id",attrId);
556   writer.writeAttribute("upper_item",attrUpperItem);
557   writer.writeAttribute("name",attrName);
558   writer.writeAttribute("position", attrPos);
559   writer.writeAttribute("dimension", attrDim);
560
561   writer.writeStartElement("group_ifaces");
562
563   writer.writeAttribute("count",QString::number(interfaces.length()));
564
565   foreach(InterfaceItem *item, interfaces){
566     writer.writeStartElement("group_iface");
567
568     writer.writeAttribute("id",QString::number(item->getId()));
569     writer.writeAttribute("name",item->getName());
570     writer.writeAttribute("level",QString(item->refInter->getLevelString()));
571     writer.writeAttribute("direction",QString(item->refInter->getDirectionString()));
572     writer.writeAttribute("orientation",item->getStrOrientation());
573     writer.writeAttribute("position",QString::number(item->getPositionRatio()));
574
575     writer.writeEndElement();
576   }
577
578   writer.writeEndElement();//</interfaces>
579
580   writer.writeEndElement();//</group_item>
581 }