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

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