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

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