3 #include "ConnectionItem.h"
4 #include "InterfaceItem.h"
5 #include "Dispatcher.h"
6 #include "Parameters.h"
8 #include "SourceItem.h"
9 #include "AbstractBlock.h"
10 #include "AbstractInterface.h"
11 #include "ConnectedInterface.h"
12 #include "GroupScene.h"
13 #include "ParametersWindow.h"
14 #include "GroupBlock.h"
15 #include "GroupInterface.h"
18 GroupItem::GroupItem(BoxItem *_parentItem,
19 AbstractBlock *_refBlock,
20 Dispatcher *_dispatcher,
21 Parameters *_params) throw(Exception) :AbstractBoxItem( _refBlock, _dispatcher, _params) {
23 parentItem = _parentItem;
24 if (parentItem != NULL) {
25 parentItem->setChildGroupItem(this);
29 minimumBoxWidth = nameWidth+2*nameMargin;
30 minimumBoxHeight = 100;
31 boxHeight = minimumBoxHeight;
32 boxWidth = minimumBoxWidth;
34 rectTitle = QRectF(0,-(nameHeight+2*nameMargin),nameWidth+2*nameMargin,nameHeight+2*nameMargin);
36 totalHeight = boxHeight + rectTitle.height();
37 totalWidth = boxWidth;
44 setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
47 updateGeometry(InterfaceMove);
48 QPointF initPos = QPointF(0.0,0.0) - originPoint;
50 cout << "total size of group: " << totalWidth << "," << totalHeight << endl;
51 cout << "pos in scene: " << x() << "," << y() << endl;
54 GroupItem::GroupItem(Dispatcher *_dispatcher,Parameters *_params) throw(Exception) :AbstractBoxItem(_dispatcher, _params) {
57 rectTitle = QRectF(0,-(nameHeight+2*nameMargin),nameWidth+2*nameMargin,nameHeight+2*nameMargin);
60 setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
62 updateGeometry(InterfaceMove);
63 QPointF initPos = QPointF(0.0,0.0) - originPoint;
65 cout << "total size of group: " << totalWidth << "," << totalHeight << endl;
66 cout << "pos in scene: " << x() << "," << y() << endl;
69 GroupItem::~GroupItem() {
70 // since the reference block is nowhere referenced except in this class, it must be deleted here
74 bool GroupItem::isGroupItem() {
78 BoxItem* GroupItem::getParentItem() {
82 void GroupItem::setParentItem(BoxItem *_parentItem) {
83 parentItem = _parentItem;
84 if (parentItem != NULL) {
85 parentItem->setChildGroupItem(this);
89 void GroupItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
90 if(boxWidth > 0 && boxHeight > 0){
92 painter->setPen(Qt::red);
94 painter->setPen(Qt::black);
96 painter->drawRect(0,0,boxWidth,boxHeight);
97 painter->drawRect(rectTitle);
98 painter->drawText(rectTitle,Qt::AlignCenter | Qt::TextWordWrap,refBlock->getName());
100 foreach(InterfaceItem *item, interfaces){
101 item->paint(painter);
106 Each time a new block is added in a GroupItem, it is placed
107 at an absolute position of (0,0) within the GroupItem. (NB: the absolute
108 position is computed by item.pos()+item.getOriginPoint()).
109 Thus, there are 3 cases :
110 - a single block is within the GroupItem
111 - several blocks already placed and a new one
112 - several blocks already placed and one is moving.
115 void GroupItem::updateMinimumSize() {
117 // compute place taken by blocks.
118 int marginConn = 2*(params->arrowWidth+params->arrowLineLength);
119 if (rectTitle.width() > 2*marginConn) {
120 minimumBoxWidth = rectTitle.width();
123 minimumBoxWidth = 2*marginConn;
125 minimumBoxHeight = 2*marginConn;
127 if (getScene() == NULL) return;
129 QList<BoxItem *> blocks = getScene()->getBoxItems();
130 if(blocks.length() > 0) {
131 // first, search for blocks that are at (0,0)
136 bool isZeroBlocks = false;
137 bool isOtherBlocks = false;
138 foreach(BoxItem* item, blocks) {
139 QPointF p = item->pos() + item->getOriginPoint();
140 if ((p.x()==0.0) && (p.y()==0.0)) {
142 if (item->getTotalWidth() > xMaxZero) {
143 xMaxZero = item->getTotalWidth();
145 if (item->getTotalHeight() > yMaxZero) {
146 yMaxZero = item->getTotalHeight();
150 isOtherBlocks = true;
151 if(p.x()+item->getTotalWidth() > xMax) {
152 xMax = p.x()+item->getTotalWidth();
154 if(p.y()+item->getTotalHeight() > yMax) {
155 yMax = p.y()+item->getTotalHeight();
160 if (!isOtherBlocks) {
161 minimumBoxWidth = xMaxZero+2*marginConn;
162 minimumBoxHeight = yMaxZero+2*marginConn;
165 if (xMaxZero+marginConn > xMax) {
166 minimumBoxWidth = xMaxZero+2*marginConn;
169 minimumBoxWidth = xMax+marginConn;
171 if (yMaxZero+marginConn > yMax) {
172 minimumBoxHeight = yMaxZero+2*marginConn;
175 minimumBoxHeight = yMax+marginConn;
180 minimumBoxWidth = xMax+marginConn;
181 minimumBoxHeight = yMax+marginConn;
184 //cout << "min group size: " << minimumBoxWidth << "," << minimumBoxHeight << endl;
187 void GroupItem::updateShape() {
188 updateGeometry(InterfaceMove);
191 bool GroupItem::updateGeometry(ChangeType type) {
193 QPointF oldOrigin = originPoint;
194 QSize oldSize(totalWidth,totalHeight);
196 bool boxSizeChanged = false;
198 // whatever the change, the minimum size may have changed
201 if (type == Resize) {
202 boxSizeChanged = true;
204 // if an internal block has moved, the actual box size may be inadequate
205 if (boxWidth < minimumBoxWidth) {
206 boxWidth = minimumBoxWidth;
207 boxSizeChanged = true;
209 if (boxHeight < minimumBoxHeight) {
210 boxHeight = minimumBoxHeight;
211 boxSizeChanged = true;
214 if (boxSizeChanged) {
215 updateInterfacesAndConnections();
219 // compute the max. width of interfaces' name for 4 orientations.
226 foreach(InterfaceItem* iface, interfaces) {
227 ifaceWidth = iface->getNameWidth();
228 if (iface->getOrientation() == Parameters::South) {
229 if (ifaceWidth > maxSouth) maxSouth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
231 else if (iface->getOrientation() == Parameters::North) {
232 if (ifaceWidth > maxNorth) maxNorth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
234 else if (iface->getOrientation() == Parameters::East) {
235 if (ifaceWidth > maxEast) maxEast = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
237 else if (iface->getOrientation() == Parameters::West) {
238 if (ifaceWidth > maxWest) maxWest = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
243 totalWidth = boxWidth+maxEast;
244 totalHeight = boxHeight+maxSouth;
248 totalWidth += maxWest;
250 if (maxNorth > (nameHeight+2*nameMargin)) {
252 totalHeight += maxNorth;
255 y -= nameHeight+2*nameMargin;
256 totalHeight += nameHeight+2*nameMargin;
258 QSizeF newSize(totalWidth,totalHeight);
262 if ((boxSizeChanged) || (newSize != oldSize) || (originPoint != oldOrigin)) {
263 //cout << "GroupItem: must change group item shape" << endl;
264 prepareGeometryChange();
270 void GroupItem::nameChanged() {
273 QFontMetrics fmId(params->defaultBlockFont);
274 nameWidth = fmId.width(refBlock->getName());
275 nameHeight = fmId.height();
276 // changing the BoxItem in the upperscene
277 if (parentItem != NULL) {
278 parentItem->nameChanged();
280 updateGeometry(InterfaceMove);
281 // force the update in case of the size has not changed
286 void GroupItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
288 if(params->editState == Parameters::EditGroupMove) {
289 int gapX = event->scenePos().x() - cursorPosition.x();
290 int gapY = event->scenePos().y() - cursorPosition.y();
293 if (refBlock->isTopGroupBlock()) {
294 QRectF rectGroup = boundingRectInScene();
295 rectGroup.moveTo(rectGroup.x()+gapX,rectGroup.y()+gapY);
296 foreach(SourceItem* source, getScene()->getSourceItems()) {
297 QRectF rectSource = source->boundingRectInScene();
298 if (rectGroup.intersects(rectSource)) canMove = false;
303 QPointF gap(gapX,gapY);
304 currentPosition = currentPosition+gap;
305 setPos(currentPosition);
307 // updating all connections of the scene.
308 getScene()->updateConnectionItemsShape();
310 cursorPosition = event->scenePos();
312 else if(params->editState == Parameters::EditGroupResize) {
314 int gapX = event->scenePos().x() - cursorPosition.x();
315 int gapY = event->scenePos().y() - cursorPosition.y();
316 //cout << "gap: " << gapX << "," << gapY << endl;
317 switch(currentBorder){
319 if(boxWidth+gapX > minimumBoxWidth){
325 if(boxHeight+gapY > minimumBoxHeight){
330 case CornerSouthEast: {
331 if(boxWidth+gapX > minimumBoxWidth){
334 if(boxHeight+gapY > minimumBoxHeight){
340 cout << "abnormal case while resizing block" << endl;
343 updateGeometry(Resize);
345 // recompute the geometry of the block
347 // update all interfaces positions
348 foreach(InterfaceItem *item, interfaces){
349 item->updatePosition();
351 // update all connections from/to this block
352 foreach(ConnectionItem *item, getScene()->getConnectionItems()){
353 if ((item->getFromInterfaceItem()->getOwner() == this) || (item->getToInterfaceItem()->getOwner() == this)) {
358 cursorPosition = event->scenePos();
360 else if(params->editState == Parameters::EditInterfaceMove) {
361 prepareGeometryChange();
362 moveInterfaceTo(event->pos());
363 // recompute the geometry of the block
364 updateGeometry(InterfaceMove);
365 // update connection from/to the selected interface
366 foreach(ConnectionItem *item, getScene()->getConnectionItems()){
367 if ((item->getFromInterfaceItem() == currentInterface) || (item->getToInterfaceItem() == currentInterface)) {
375 void GroupItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
377 QPointF pos = event->pos();
381 QGraphicsItem::mousePressEvent(event);
383 if(event->button() == Qt::RightButton) return;
385 int mode = getScene()->getEditionMode();
387 dispatcher->setCurrentGroupWidget(getScene()->getGroupWidget());
389 if ((mode == GroupScene::AddConnection) && (params->cursorState == Parameters::CursorOnInterface)) {
390 InterfaceItem *inter = getInterfaceFromCursor(x,y);
393 if (params->editState == Parameters::EditNoOperation) {
394 getScene()->setSelectedInterface(1,inter);
395 params->setEditState(Parameters::EditStartConnection);
397 else if (params->editState == Parameters::EditStartConnection) {
398 if (inter == getScene()->getSelectedInterface(1)) {
399 params->setEditState(Parameters::EditAbortConnection);
402 getScene()->setSelectedInterface(2,inter);
403 params->setEditState(Parameters::EditCloseConnection);
408 else if (mode == GroupScene::ItemEdition) {
410 if (params->cursorState == Parameters::CursorOnInterface) {
411 InterfaceItem *inter = getInterfaceFromCursor(x,y);
413 currentInterface = inter;
414 params->setEditState(Parameters::EditInterfaceMove);
417 else if (params->cursorState == Parameters::CursorInGroupTitle) {
418 params->setEditState(Parameters::EditGroupMove);
419 cursorPosition = event->scenePos();
421 else if (params->cursorState == Parameters::CursorOnBorder) {
422 setFlag(ItemIsMovable, false);
423 cursorPosition = event->scenePos();
424 params->setEditState(Parameters::EditGroupResize);
429 void GroupItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
431 int mode = getScene()->getEditionMode();
433 if (mode == GroupScene::AddConnection) {
435 if (params->editState == Parameters::EditStartConnection) {
436 params->setEditState(Parameters::EditStartConnection);
437 InterfaceItem* iface = getScene()->getSelectedInterface(1);
438 iface->selected = true;
439 update(iface->boundingRect());
441 else if (params->editState == Parameters::EditAbortConnection) {
442 InterfaceItem* iface = getScene()->getSelectedInterface(1);
443 iface->selected = false;
444 update(iface->boundingRect());
445 getScene()->setSelectedInterface(1,NULL);
446 params->setEditState(Parameters::EditNoOperation);
448 else if (params->editState == Parameters::EditCloseConnection) {
449 InterfaceItem* iface1 = getScene()->getSelectedInterface(1);
450 InterfaceItem* iface2 = getScene()->getSelectedInterface(2);
451 bool ok = dispatcher->createConnectionItem(iface1,iface2);
453 iface1->selected = false;
454 update(iface1->boundingRect());
455 iface2->selected = false;
456 update(iface2->boundingRect());
457 getScene()->setSelectedInterface(1,NULL);
458 getScene()->setSelectedInterface(2,NULL);
459 params->setEditState(Parameters::EditNoOperation);
462 //QMessageBox::warning(NULL,"Error","Cannot connect selected interfaces", QMessageBox::Ok);
463 getScene()->setSelectedInterface(2,NULL);
464 params->setEditState(Parameters::EditStartConnection);
468 else if (mode == GroupScene::ItemEdition) {
469 currentInterface = NULL;
470 setFlag(ItemIsMovable, true);
471 params->editState = Parameters::EditNoOperation;
473 QGraphicsItem::mouseReleaseEvent(event);
476 void GroupItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
477 QPointF pos = event->pos();
480 currentBorder = NoBorder;
481 int mode = getScene()->getEditionMode();
483 if (mode == GroupScene::AddConnection) {
484 InterfaceItem* iface = getInterfaceFromCursor(x,y);
486 params->cursorState = Parameters::CursorOnInterface;
487 setCursor(Qt::PointingHandCursor);
490 params->cursorState = Parameters::CursorNowhere;
491 setCursor(Qt::ArrowCursor);
494 else if (mode == GroupScene::ItemEdition) {
498 InterfaceItem* iface = getInterfaceFromCursor(x,y);
500 params->cursorState = Parameters::CursorOnInterface;
501 setCursor(Qt::PointingHandCursor);
503 else if ((x>boxWidth-marginE)&&(x<boxWidth)) {
505 params->cursorState = Parameters::CursorOnBorder;
507 if ((y>boxHeight-2*marginS)&&(y<boxHeight)) {
508 currentBorder = CornerSouthEast;
509 setCursor(Qt::SizeFDiagCursor);
512 currentBorder = BorderEast;
513 setCursor(Qt::SizeHorCursor);
516 else if ((y>boxHeight-marginS)&&(y<boxHeight)) {
518 params->cursorState = Parameters::CursorOnBorder;
520 if ((x>boxWidth-2*marginE)&&(x<boxWidth)) {
521 currentBorder = CornerSouthEast;
522 setCursor(Qt::SizeFDiagCursor);
525 currentBorder = BorderSouth;
526 setCursor(Qt::SizeVerCursor);
530 if (rectTitle.contains(x,y)) {
531 params->cursorState = Parameters::CursorInGroupTitle;
532 setCursor(Qt::OpenHandCursor);
535 params->cursorState = Parameters::CursorNowhere;
536 setCursor(Qt::ArrowCursor);
540 //QGraphicsItem::hoverMoveEvent(event);
544 void GroupItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
546 QAction* titleAction = NULL;
547 QAction* showProperties = NULL;
548 QAction* removeAction = NULL;
549 QAction* renameAction = NULL;
550 QAction* showParameters = NULL;
552 InterfaceItem* ifaceItem = getInterfaceFromCursor(event->pos().x(), event->pos().y());
554 // menu for interface
555 if( ifaceItem != NULL) {
556 titleAction = menu.addAction("Interface operations");
557 titleAction->setEnabled(false);
559 showProperties = menu.addAction("Show properties");
560 renameAction = menu.addAction("Rename");
562 /* CAUTION : the interface can be removed only if its
563 connected to only one side, i.e. connectedFrom is null
564 or connectedTo is empty.
567 ConnectedInterface* ref = ifaceItem->refInter;
568 if ((!ref->isConnectedFrom()) || (!ref->isConnectedTo())) {
569 removeAction = menu.addAction("Remove");
573 titleAction = menu.addAction("Block operations");
574 titleAction->setEnabled(false);
577 if (refBlock->nbParameters() > 0) {
578 showParameters = menu.addAction("Show parameters");
580 renameAction = menu.addAction("Rename");
582 QAction* selectedAction = menu.exec(event->screenPos());
584 if(selectedAction == NULL) return;
586 if(selectedAction == renameAction){
587 if(ifaceItem != NULL)
588 dispatcher->renameInterface(ifaceItem);
590 dispatcher->renameGroupBlock(this);
592 else if(selectedAction == showProperties){
593 dispatcher->showProperties(ifaceItem);
595 else if (selectedAction == removeAction) {
596 dispatcher->removeGroupInterface(ifaceItem);
598 else if(selectedAction == showParameters) {
599 new ParametersWindow(refBlock, params, NULL);
603 InterfaceItem* GroupItem::isHoverInterface(QPointF point) {
604 foreach(InterfaceItem *inter, interfaces){
605 if(inter->boundingRect().contains(point))
611 void GroupItem::load(QDomElement groupElement) throw(Exception) {
613 GroupBlock* groupBlock = AB_TO_GRP(refBlock);
617 int id = groupElement.attribute("id","none").toInt(&ok);
618 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
620 QString nameStr = groupElement.attribute("name","none");
621 if(nameStr == "none") throw(Exception(PROJECTFILE_CORRUPTED));
623 QStringList positionStr = groupElement.attribute("position","none").split(",");
624 if(positionStr.length() != 2) throw(Exception(PROJECTFILE_CORRUPTED));
625 int posX = positionStr.at(0).toInt(&ok);
626 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
627 int posY = positionStr.at(1).toInt(&ok);
628 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
630 QStringList dimensionStr = groupElement.attribute("dimension","none").split(",");
631 if(dimensionStr.length() != 2) throw(Exception(PROJECTFILE_CORRUPTED));
632 int dimX = dimensionStr.at(0).toInt(&ok);
633 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
634 int dimY = dimensionStr.at(1).toInt(&ok);
635 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
639 setDimension(dimX,dimY);
640 groupBlock->setName(nameStr);
642 cout << "group info : \n-id : " << id << "\n-pos : " << posX << ", " << posY << "\n-dim : " << dimX << ", " << dimY << "\n-name : " << nameStr.toStdString() << endl;
644 QDomNodeList interfaces = groupElement.elementsByTagName("group_iface");
645 for(int j=0; j<interfaces.length(); j++){
646 QDomElement currentInterfaceNode = interfaces.at(j).toElement();
648 int id = currentInterfaceNode.attribute("id","none").toInt(&ok);
649 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
651 QString name = currentInterfaceNode.attribute("name","none");
652 if(name == "none") throw(Exception(PROJECTFILE_CORRUPTED));
654 QString directionStr = currentInterfaceNode.attribute("direction","none");
655 int direction = AbstractInterface::getIntDirection(directionStr);
656 if(direction == -1) throw(Exception(PROJECTFILE_CORRUPTED));
658 QString orientationStr = currentInterfaceNode.attribute("orientation","none");
659 int orientation = InterfaceItem::getIntOrientation(orientationStr);
660 if(orientation == -1) throw(Exception(PROJECTFILE_CORRUPTED));
662 double position = currentInterfaceNode.attribute("position","none").toDouble(&ok);
663 if(!ok) throw(Exception(PROJECTFILE_CORRUPTED));
665 GroupInterface *groupInterface = new GroupInterface(groupBlock,name,direction,AbstractInterface::Data);
667 InterfaceItem *interfaceItem = new InterfaceItem(position,orientation,groupInterface,this,params);
668 interfaceItem->setId(id);
670 groupBlock->addInterface(groupInterface);
671 addInterface(interfaceItem, false);
672 cout << "interface add to " << groupBlock->getName().toStdString() << endl;
677 void GroupItem::save(QXmlStreamWriter &writer) {
679 writer.writeStartElement("group_item");
681 QString attrId = QString::number(id);
682 QString attrName(getRefBlock()->getName());
683 QString attrUpperItem = QString::number(-1);
684 if(parentItem != NULL){
685 attrUpperItem = QString::number(parentItem->getId());
687 QString attrPos = QString::number((int)(pos().x())).append(",").append(QString::number((int)(pos().y())));
688 QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight()));
691 writer.writeAttribute("id",attrId);
692 writer.writeAttribute("upper_item",attrUpperItem);
693 writer.writeAttribute("name",attrName);
694 writer.writeAttribute("position", attrPos);
695 writer.writeAttribute("dimension", attrDim);
697 writer.writeStartElement("group_ifaces");
699 writer.writeAttribute("count",QString::number(interfaces.length()));
701 foreach(InterfaceItem *item, interfaces){
702 writer.writeStartElement("group_iface");
704 writer.writeAttribute("id",QString::number(item->getId()));
705 writer.writeAttribute("name",item->getName());
706 writer.writeAttribute("direction",QString(item->refInter->getDirectionString()));
707 writer.writeAttribute("orientation",item->getStrOrientation());
708 writer.writeAttribute("position",QString::number(item->getPositionRatio()));
710 writer.writeEndElement();
713 writer.writeEndElement();//</interfaces>
715 writer.writeEndElement();//</group_item>