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"
14 GroupItem::GroupItem(BoxItem *_parentItem,
15 AbstractBlock *_refBlock,
16 Dispatcher *_dispatcher,
17 Parameters *_params) throw(Exception) :AbstractBoxItem( _refBlock, _dispatcher, _params) {
19 parentItem = _parentItem;
22 minimumBoxWidth = nameWidth+2*nameMargin;
23 minimumBoxHeight = 100;
24 boxHeight = minimumBoxHeight;
25 boxWidth = minimumBoxWidth;
27 rectTitle = QRectF(0,-(nameHeight+2*nameMargin),nameWidth+2*nameMargin,nameHeight+2*nameMargin);
29 totalHeight = boxHeight + rectTitle.height();
30 totalWidth = boxWidth;
37 setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
40 updateGeometry(InterfaceMove);
41 QPointF initPos = QPointF(0.0,0.0) - originPoint;
43 cout << "total size of group: " << totalWidth << "," << totalHeight << endl;
44 cout << "pos in scene: " << x() << "," << y() << endl;
47 GroupItem::~GroupItem() {
48 // since the reference block is nowhere referenced except in this class, it must be deleted here
52 bool GroupItem::isGroupItem() {
56 BoxItem* GroupItem::getParentItem() {
60 void GroupItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
61 if(boxWidth > 0 && boxHeight > 0){
63 painter->setPen(Qt::red);
65 painter->setPen(Qt::black);
67 painter->drawRect(0,0,boxWidth,boxHeight);
68 painter->drawRect(rectTitle);
69 painter->drawText(rectTitle,Qt::AlignCenter | Qt::TextWordWrap,refBlock->getName());
71 foreach(InterfaceItem *item, interfaces){
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.
86 void GroupItem::updateMinimumSize() {
88 // compute place taken by blocks.
89 int marginConn = 2*(params->arrowWidth+params->arrowLineLength);
90 if (rectTitle.width() > 2*marginConn) {
91 minimumBoxWidth = rectTitle.width();
94 minimumBoxWidth = 2*marginConn;
96 minimumBoxHeight = 2*marginConn;
98 if (getScene() == NULL) return;
100 QList<BoxItem *> blocks = getScene()->getBlockItems();
101 if(blocks.length() > 0) {
102 // first, search for blocks that are at (0,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)) {
113 if (item->getTotalWidth() > xMaxZero) {
114 xMaxZero = item->getTotalWidth();
116 if (item->getTotalHeight() > yMaxZero) {
117 yMaxZero = item->getTotalHeight();
121 isOtherBlocks = true;
122 if(p.x()+item->getTotalWidth() > xMax) {
123 xMax = p.x()+item->getTotalWidth();
125 if(p.y()+item->getTotalHeight() > yMax) {
126 yMax = p.y()+item->getTotalHeight();
131 if (!isOtherBlocks) {
132 minimumBoxWidth = xMaxZero+2*marginConn;
133 minimumBoxHeight = yMaxZero+2*marginConn;
136 if (xMaxZero+marginConn > xMax) {
137 minimumBoxWidth = xMaxZero+2*marginConn;
140 minimumBoxWidth = xMax+marginConn;
142 if (yMaxZero+marginConn > yMax) {
143 minimumBoxHeight = yMaxZero+2*marginConn;
146 minimumBoxHeight = yMax+marginConn;
151 minimumBoxWidth = xMax+marginConn;
152 minimumBoxHeight = yMax+marginConn;
155 //cout << "min group size: " << minimumBoxWidth << "," << minimumBoxHeight << endl;
158 void GroupItem::updateShape() {
159 updateGeometry(InterfaceMove);
162 bool GroupItem::updateGeometry(ChangeType type) {
164 QPointF oldOrigin = originPoint;
165 QSize oldSize(totalWidth,totalHeight);
167 bool boxSizeChanged = false;
169 // whatever the change, the minimum size may have changed
172 if (type == Resize) {
173 boxSizeChanged = true;
175 // if an internal block has moved, the actual box size may be inadequate
176 if (boxWidth < minimumBoxWidth) {
177 boxWidth = minimumBoxWidth;
178 boxSizeChanged = true;
180 if (boxHeight < minimumBoxHeight) {
181 boxHeight = minimumBoxHeight;
182 boxSizeChanged = true;
185 if (boxSizeChanged) {
186 updateInterfacesAndConnections();
190 // compute the max. width of interfaces' name for 4 orientations.
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;
202 else if (iface->getOrientation() == Parameters::North) {
203 if (ifaceWidth > maxNorth) maxNorth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
205 else if (iface->getOrientation() == Parameters::East) {
206 if (ifaceWidth > maxEast) maxEast = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
208 else if (iface->getOrientation() == Parameters::West) {
209 if (ifaceWidth > maxWest) maxWest = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
214 totalWidth = boxWidth+maxEast;
215 totalHeight = boxHeight+maxSouth;
219 totalWidth += maxWest;
221 if (maxNorth > (nameHeight+2*nameMargin)) {
223 totalHeight += maxNorth;
226 y -= nameHeight+2*nameMargin;
227 totalHeight += nameHeight+2*nameMargin;
229 QSizeF newSize(totalWidth,totalHeight);
233 if ((boxSizeChanged) || (newSize != oldSize) || (originPoint != oldOrigin)) {
234 cout << "must change group item shape" << endl;
235 prepareGeometryChange();
241 void GroupItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
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();
248 //cout << "block abs. pos: " << absPos.x() << "," << absPos.y() << " | ";
249 //cout << "block current. pos: " << currentPosition.x() << "," << currentPosition.y() << " | ";
251 if (absPos.x()+gapX < 0) {
254 if (absPos.y()+gapY < 0) {
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();
265 else if(params->editState == Parameters::EditGroupResize) {
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){
272 if(boxWidth+gapX > minimumBoxWidth){
278 if(boxHeight+gapY > minimumBoxHeight){
283 case CornerSouthEast: {
284 if(boxWidth+gapX > minimumBoxWidth){
287 if(boxHeight+gapY > minimumBoxHeight){
293 cout << "abnormal case while resizing block" << endl;
296 updateGeometry(Resize);
298 // recompute the geometry of the block
300 // update all interfaces positions
301 foreach(InterfaceItem *item, interfaces){
302 item->updatePosition();
304 // update all connections from/to this block
305 foreach(ConnectionItem *item, getScene()->getConnectionItems()){
306 if ((item->getFromInterfaceItem()->getOwner() == this) || (item->getToInterfaceItem()->getOwner() == this)) {
311 cursorPosition = event->scenePos();
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)) {
328 void GroupItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
330 QPointF pos = event->pos();
334 QGraphicsItem::mousePressEvent(event);
336 if(event->button() == Qt::RightButton) return;
338 int mode = getScene()->getEditionMode();
340 dispatcher->setCurrentGroupWidget(getScene()->getGroupWindow());
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.
347 if ((mode == GroupScene::AddConnection) && (params->cursorState == Parameters::CursorOnInterface)) {
348 InterfaceItem *inter = getInterfaceFromCursor(x,y);
351 if (params->editState == Parameters::EditNoOperation) {
352 getScene()->setSelectedInterface(1,inter);
353 params->setEditState(Parameters::EditStartConnection);
355 else if (params->editState == Parameters::EditStartConnection) {
356 if (inter == getScene()->getSelectedInterface(1)) {
357 params->setEditState(Parameters::EditAbortConnection);
360 getScene()->setSelectedInterface(2,inter);
361 params->setEditState(Parameters::EditCloseConnection);
367 if (mode == GroupScene::ItemEdition) {
369 if (params->cursorState == Parameters::CursorOnInterface) {
370 InterfaceItem *inter = getInterfaceFromCursor(x,y);
372 currentInterface = inter;
373 params->setEditState(Parameters::EditInterfaceMove);
376 else if (params->cursorState == Parameters::CursorInGroupTitle) {
377 params->setEditState(Parameters::EditGroupMove);
378 cursorPosition = event->scenePos();
380 else if (params->cursorState == Parameters::CursorOnBorder) {
381 setFlag(ItemIsMovable, false);
382 cursorPosition = event->scenePos();
383 params->setEditState(Parameters::EditGroupResize);
388 void GroupItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
390 int mode = getScene()->getEditionMode();
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.
397 if (mode == GroupScene::AddConnection) {
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());
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);
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);
417 iface1->selected = false;
418 update(iface1->boundingRect());
419 getScene()->setSelectedInterface(1,NULL);
420 getScene()->setSelectedInterface(2,NULL);
421 params->setEditState(Parameters::EditNoOperation);
426 if (mode == GroupScene::ItemEdition) {
427 currentInterface = NULL;
428 setFlag(ItemIsMovable, true);
429 params->editState = Parameters::EditNoOperation;
431 QGraphicsItem::mouseReleaseEvent(event);
434 void GroupItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
435 QPointF pos = event->pos();
438 currentBorder = NoBorder;
439 int mode = getScene()->getEditionMode();
441 if (mode == GroupScene::AddConnection) {
442 InterfaceItem* iface = getInterfaceFromCursor(x,y);
444 params->cursorState = Parameters::CursorOnInterface;
445 setCursor(Qt::PointingHandCursor);
448 params->cursorState = Parameters::CursorNowhere;
449 setCursor(Qt::ArrowCursor);
452 else if (mode == GroupScene::ItemEdition) {
456 InterfaceItem* iface = getInterfaceFromCursor(x,y);
458 params->cursorState = Parameters::CursorOnInterface;
459 setCursor(Qt::PointingHandCursor);
461 else if ((x>boxWidth-marginE)&&(x<boxWidth)) {
463 params->cursorState = Parameters::CursorOnBorder;
465 if ((y>boxHeight-2*marginS)&&(y<boxHeight)) {
466 currentBorder = CornerSouthEast;
467 setCursor(Qt::SizeFDiagCursor);
470 currentBorder = BorderEast;
471 setCursor(Qt::SizeHorCursor);
474 else if ((y>boxHeight-marginS)&&(y<boxHeight)) {
476 params->cursorState = Parameters::CursorOnBorder;
478 if ((x>boxWidth-2*marginE)&&(x<boxWidth)) {
479 currentBorder = CornerSouthEast;
480 setCursor(Qt::SizeFDiagCursor);
483 currentBorder = BorderSouth;
484 setCursor(Qt::SizeVerCursor);
488 if (rectTitle.contains(x,y)) {
489 params->cursorState = Parameters::CursorInGroupTitle;
490 setCursor(Qt::OpenHandCursor);
493 params->cursorState = Parameters::CursorNowhere;
494 setCursor(Qt::ArrowCursor);
498 QGraphicsItem::hoverMoveEvent(event);
501 void GroupItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
503 QAction* showProperties = NULL;
504 QAction* removeAction = NULL;
505 QAction* renameAction = NULL;
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");
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.
517 ConnectedInterface* ref = ifaceItem->refInter;
518 if ((!ref->isConnectedFrom()) || (!ref->isConnectedTo())) {
519 removeAction = menu.addAction("Remove");
523 renameAction = menu.addAction("Rename");
525 QAction* selectedAction = menu.exec(event->screenPos());
527 if(selectedAction == NULL) return;
529 if(selectedAction == renameAction){
530 if(ifaceItem != NULL)
531 dispatcher->rename(ifaceItem);
533 dispatcher->rename(this);
535 else if(selectedAction == showProperties){
536 dispatcher->showProperties(ifaceItem);
538 else if (selectedAction == removeAction) {
539 dispatcher->removeGroupInterface(ifaceItem);
543 InterfaceItem* GroupItem::isHoverInterface(QPointF point) {
544 foreach(InterfaceItem *inter, interfaces){
545 if(inter->boundingRect().contains(point))
551 void GroupItem::save(QXmlStreamWriter &writer) {
553 writer.writeStartElement("group_item");
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());
561 QString attrPos = QString::number(pos().x()).append(",").append(QString::number(pos().y()));
562 QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight()));
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);
571 writer.writeStartElement("group_ifaces");
573 writer.writeAttribute("count",QString::number(interfaces.length()));
575 foreach(InterfaceItem *item, interfaces){
576 writer.writeStartElement("group_iface");
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()));
585 writer.writeEndElement();
588 writer.writeEndElement();//</interfaces>
590 writer.writeEndElement();//</group_item>