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 QPointF initPos = QPointF(0.0,0.0) - originPoint;
42 cout << "total size of group: " << totalWidth << "," << totalHeight << endl;
43 cout << "pos in scene: " << x() << "," << y() << endl;
46 GroupItem::~GroupItem() {
47 // since the reference block is nowhere referenced except in this class, it must be deleted here
51 bool GroupItem::isGroupItem() {
55 BoxItem* GroupItem::getParentItem() {
59 void GroupItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
60 if(boxWidth > 0 && boxHeight > 0){
62 painter->setPen(Qt::red);
64 painter->setPen(Qt::black);
66 painter->drawRect(0,0,boxWidth,boxHeight);
67 painter->drawRect(rectTitle);
68 painter->drawText(rectTitle,Qt::AlignCenter | Qt::TextWordWrap,refBlock->getName());
70 foreach(InterfaceItem *item, interfaces){
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.
85 void GroupItem::updateMinimumSize() {
87 // compute place taken by blocks.
88 int marginConn = 2*(params->arrowWidth+params->arrowLineLength);
89 if (rectTitle.width() > 2*marginConn) {
90 minimumBoxWidth = rectTitle.width();
93 minimumBoxWidth = 2*marginConn;
95 minimumBoxHeight = 2*marginConn;
97 if (getScene() == NULL) return;
99 QList<BoxItem *> blocks = getScene()->getBlockItems();
100 if(blocks.length() > 0) {
101 // first, search for blocks that are at (0,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)) {
112 if (item->getTotalWidth() > xMaxZero) {
113 xMaxZero = item->getTotalWidth();
115 if (item->getTotalHeight() > yMaxZero) {
116 yMaxZero = item->getTotalHeight();
120 isOtherBlocks = true;
121 if(p.x()+item->getTotalWidth() > xMax) {
122 xMax = p.x()+item->getTotalWidth();
124 if(p.y()+item->getTotalHeight() > yMax) {
125 yMax = p.y()+item->getTotalHeight();
130 if (!isOtherBlocks) {
131 minimumBoxWidth = xMaxZero+2*marginConn;
132 minimumBoxHeight = yMaxZero+2*marginConn;
135 if (xMaxZero+marginConn > xMax) {
136 minimumBoxWidth = xMaxZero+2*marginConn;
139 minimumBoxWidth = xMax+marginConn;
141 if (yMaxZero+marginConn > yMax) {
142 minimumBoxHeight = yMaxZero+2*marginConn;
145 minimumBoxHeight = yMax+marginConn;
150 minimumBoxWidth = xMax+marginConn;
151 minimumBoxHeight = yMax+marginConn;
154 //cout << "min group size: " << minimumBoxWidth << "," << minimumBoxHeight << endl;
157 void GroupItem::updateShape() {
161 bool GroupItem::updateGeometry(ChangeType type) {
163 QPointF oldOrigin = originPoint;
164 QSize oldSize(totalWidth,totalHeight);
167 bool boxSizeChanged = false;
168 if (boxWidth < minimumBoxWidth) {
169 boxWidth = minimumBoxWidth;
170 boxSizeChanged = true;
172 if (boxHeight < minimumBoxHeight) {
173 boxHeight = minimumBoxHeight;
174 boxSizeChanged = true;
176 if (boxSizeChanged) {
177 updateInterfacesAndConnections();
180 // compute the max. width of interfaces' name for 4 orientations.
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;
192 else if (iface->getOrientation() == Parameters::North) {
193 if (ifaceWidth > maxNorth) maxNorth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
195 else if (iface->getOrientation() == Parameters::East) {
196 if (ifaceWidth > maxEast) maxEast = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
198 else if (iface->getOrientation() == Parameters::West) {
199 if (ifaceWidth > maxWest) maxWest = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
204 totalWidth = boxWidth+maxEast;
205 totalHeight = boxHeight+maxSouth;
209 totalWidth += maxWest;
211 if (maxNorth > (nameHeight+2*nameMargin)) {
213 totalHeight += maxNorth;
216 y -= nameHeight+2*nameMargin;
217 totalHeight += nameHeight+2*nameMargin;
219 QSizeF newSize(totalWidth,totalHeight);
223 if ((boxSizeChanged) || (newSize != oldSize) || (originPoint != oldOrigin)) {
224 //cout << "must change group item shape" << endl;
225 prepareGeometryChange();
231 void GroupItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
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();
238 //cout << "block abs. pos: " << absPos.x() << "," << absPos.y() << " | ";
239 //cout << "block current. pos: " << currentPosition.x() << "," << currentPosition.y() << " | ";
241 if (absPos.x()+gapX < 0) {
244 if (absPos.y()+gapY < 0) {
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();
255 else if(params->editState == Parameters::EditGroupResize) {
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){
262 if(boxWidth+gapX > minimumBoxWidth){
268 if(boxHeight+gapY > minimumBoxHeight){
273 case CornerSouthEast: {
274 if(boxWidth+gapX > minimumBoxWidth){
277 if(boxHeight+gapY > minimumBoxHeight){
283 cout << "abnormal case while resizing block" << endl;
288 // recompute the geometry of the block
290 // update all interfaces positions
291 foreach(InterfaceItem *item, interfaces){
292 item->updatePosition();
294 // update all connections from/to this block
295 foreach(ConnectionItem *item, getScene()->getConnectionItems()){
296 if ((item->getFromInterfaceItem()->getOwner() == this) || (item->getToInterfaceItem()->getOwner() == this)) {
301 cursorPosition = event->scenePos();
303 else if(params->editState == Parameters::EditInterfaceMove) {
304 prepareGeometryChange();
305 deplaceInterface(event->pos());
306 // recompute the geometry of the block
308 // update connection from/to the selected interface
309 foreach(ConnectionItem *item, getScene()->getConnectionItems()){
310 if ((item->getFromInterfaceItem() == currentInterface) || (item->getToInterfaceItem() == currentInterface)) {
318 void GroupItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
320 QPointF pos = event->pos();
324 QGraphicsItem::mousePressEvent(event);
326 if(event->button() == Qt::RightButton) return;
328 int mode = getScene()->getEditionMode();
330 dispatcher->setCurrentGroupWidget(getScene()->getGroupWindow());
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.
337 if ((mode == GroupScene::AddConnection) && (params->cursorState == Parameters::CursorOnInterface)) {
338 InterfaceItem *inter = getInterfaceFromCursor(x,y);
341 if (params->editState == Parameters::EditNoOperation) {
342 getScene()->setSelectedInterface(1,inter);
343 params->setEditState(Parameters::EditStartConnection);
345 else if (params->editState == Parameters::EditStartConnection) {
346 if (inter == getScene()->getSelectedInterface(1)) {
347 params->setEditState(Parameters::EditAbortConnection);
350 getScene()->setSelectedInterface(2,inter);
351 params->setEditState(Parameters::EditCloseConnection);
357 if (mode == GroupScene::ItemEdition) {
359 if (params->cursorState == Parameters::CursorOnInterface) {
360 InterfaceItem *inter = getInterfaceFromCursor(x,y);
362 currentInterface = inter;
363 params->setEditState(Parameters::EditInterfaceMove);
366 else if (params->cursorState == Parameters::CursorInGroupTitle) {
367 params->setEditState(Parameters::EditGroupMove);
368 cursorPosition = event->scenePos();
370 else if (params->cursorState == Parameters::CursorOnBorder) {
371 setFlag(ItemIsMovable, false);
372 cursorPosition = event->scenePos();
373 params->setEditState(Parameters::EditGroupResize);
378 void GroupItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
380 int mode = getScene()->getEditionMode();
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.
387 if (mode == GroupScene::AddConnection) {
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());
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);
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);
407 iface1->selected = false;
408 update(iface1->boundingRect());
409 getScene()->setSelectedInterface(1,NULL);
410 getScene()->setSelectedInterface(2,NULL);
411 params->setEditState(Parameters::EditNoOperation);
416 if (mode == GroupScene::ItemEdition) {
417 currentInterface = NULL;
418 setFlag(ItemIsMovable, true);
419 params->editState = Parameters::EditNoOperation;
421 QGraphicsItem::mouseReleaseEvent(event);
424 void GroupItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
425 QPointF pos = event->pos();
428 currentBorder = NoBorder;
429 int mode = getScene()->getEditionMode();
431 if (mode == GroupScene::AddConnection) {
432 InterfaceItem* iface = getInterfaceFromCursor(x,y);
434 params->cursorState = Parameters::CursorOnInterface;
435 setCursor(Qt::PointingHandCursor);
438 params->cursorState = Parameters::CursorNowhere;
439 setCursor(Qt::ArrowCursor);
442 else if (mode == GroupScene::ItemEdition) {
446 InterfaceItem* iface = getInterfaceFromCursor(x,y);
448 params->cursorState = Parameters::CursorOnInterface;
449 setCursor(Qt::PointingHandCursor);
451 else if ((x>boxWidth-marginE)&&(x<boxWidth)) {
453 params->cursorState = Parameters::CursorOnBorder;
455 if ((y>boxHeight-2*marginS)&&(y<boxHeight)) {
456 currentBorder = CornerSouthEast;
457 setCursor(Qt::SizeFDiagCursor);
460 currentBorder = BorderEast;
461 setCursor(Qt::SizeHorCursor);
464 else if ((y>boxHeight-marginS)&&(y<boxHeight)) {
466 params->cursorState = Parameters::CursorOnBorder;
468 if ((x>boxWidth-2*marginE)&&(x<boxWidth)) {
469 currentBorder = CornerSouthEast;
470 setCursor(Qt::SizeFDiagCursor);
473 currentBorder = BorderSouth;
474 setCursor(Qt::SizeVerCursor);
478 if (rectTitle.contains(x,y)) {
479 params->cursorState = Parameters::CursorInGroupTitle;
480 setCursor(Qt::OpenHandCursor);
483 params->cursorState = Parameters::CursorNowhere;
484 setCursor(Qt::ArrowCursor);
488 QGraphicsItem::hoverMoveEvent(event);
491 void GroupItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
493 QAction* showProperties = NULL;
494 QAction* removeAction = NULL;
495 QAction* renameAction = NULL;
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");
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.
507 ConnectedInterface* ref = ifaceItem->refInter;
508 if ((!ref->isConnectedFrom()) || (!ref->isConnectedTo())) {
509 removeAction = menu.addAction("Remove");
513 renameAction = menu.addAction("Rename");
515 QAction* selectedAction = menu.exec(event->screenPos());
517 if(selectedAction == NULL) return;
519 if(selectedAction == renameAction){
520 if(ifaceItem != NULL)
521 dispatcher->rename(ifaceItem);
523 dispatcher->rename(this);
525 else if(selectedAction == showProperties){
526 dispatcher->showProperties(ifaceItem);
528 else if (selectedAction == removeAction) {
529 dispatcher->removeGroupInterface(ifaceItem);
533 InterfaceItem* GroupItem::isHoverInterface(QPointF point) {
534 foreach(InterfaceItem *inter, interfaces){
535 if(inter->boundingRect().contains(point))
541 void GroupItem::save(QXmlStreamWriter &writer) {
543 writer.writeStartElement("group_item");
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());
551 QString attrPos = QString::number(pos().x()).append(",").append(QString::number(pos().y()));
552 QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight()));
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);
561 writer.writeStartElement("group_ifaces");
563 writer.writeAttribute("count",QString::number(interfaces.length()));
565 foreach(InterfaceItem *item, interfaces){
566 writer.writeStartElement("group_iface");
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()));
575 writer.writeEndElement();
578 writer.writeEndElement();//</interfaces>
580 writer.writeEndElement();//</group_item>