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"
12 #include "ParametersWindow.h"
15 GroupItem::GroupItem(BoxItem *_parentItem,
16 AbstractBlock *_refBlock,
17 Dispatcher *_dispatcher,
18 Parameters *_params) throw(Exception) :AbstractBoxItem( _refBlock, _dispatcher, _params) {
20 parentItem = _parentItem;
21 if (parentItem != NULL) {
22 parentItem->setChildGroupItem(this);
26 minimumBoxWidth = nameWidth+2*nameMargin;
27 minimumBoxHeight = 100;
28 boxHeight = minimumBoxHeight;
29 boxWidth = minimumBoxWidth;
31 rectTitle = QRectF(0,-(nameHeight+2*nameMargin),nameWidth+2*nameMargin,nameHeight+2*nameMargin);
33 totalHeight = boxHeight + rectTitle.height();
34 totalWidth = boxWidth;
41 setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
44 updateGeometry(InterfaceMove);
45 QPointF initPos = QPointF(0.0,0.0) - originPoint;
47 cout << "total size of group: " << totalWidth << "," << totalHeight << endl;
48 cout << "pos in scene: " << x() << "," << y() << endl;
51 GroupItem::~GroupItem() {
52 // since the reference block is nowhere referenced except in this class, it must be deleted here
56 bool GroupItem::isGroupItem() {
60 BoxItem* GroupItem::getParentItem() {
64 void GroupItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
65 if(boxWidth > 0 && boxHeight > 0){
67 painter->setPen(Qt::red);
69 painter->setPen(Qt::black);
71 painter->drawRect(0,0,boxWidth,boxHeight);
72 painter->drawRect(rectTitle);
73 painter->drawText(rectTitle,Qt::AlignCenter | Qt::TextWordWrap,refBlock->getName());
75 foreach(InterfaceItem *item, interfaces){
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.
90 void GroupItem::updateMinimumSize() {
92 // compute place taken by blocks.
93 int marginConn = 2*(params->arrowWidth+params->arrowLineLength);
94 if (rectTitle.width() > 2*marginConn) {
95 minimumBoxWidth = rectTitle.width();
98 minimumBoxWidth = 2*marginConn;
100 minimumBoxHeight = 2*marginConn;
102 if (getScene() == NULL) return;
104 QList<BoxItem *> blocks = getScene()->getBlockItems();
105 if(blocks.length() > 0) {
106 // first, search for blocks that are at (0,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)) {
117 if (item->getTotalWidth() > xMaxZero) {
118 xMaxZero = item->getTotalWidth();
120 if (item->getTotalHeight() > yMaxZero) {
121 yMaxZero = item->getTotalHeight();
125 isOtherBlocks = true;
126 if(p.x()+item->getTotalWidth() > xMax) {
127 xMax = p.x()+item->getTotalWidth();
129 if(p.y()+item->getTotalHeight() > yMax) {
130 yMax = p.y()+item->getTotalHeight();
135 if (!isOtherBlocks) {
136 minimumBoxWidth = xMaxZero+2*marginConn;
137 minimumBoxHeight = yMaxZero+2*marginConn;
140 if (xMaxZero+marginConn > xMax) {
141 minimumBoxWidth = xMaxZero+2*marginConn;
144 minimumBoxWidth = xMax+marginConn;
146 if (yMaxZero+marginConn > yMax) {
147 minimumBoxHeight = yMaxZero+2*marginConn;
150 minimumBoxHeight = yMax+marginConn;
155 minimumBoxWidth = xMax+marginConn;
156 minimumBoxHeight = yMax+marginConn;
159 //cout << "min group size: " << minimumBoxWidth << "," << minimumBoxHeight << endl;
162 void GroupItem::updateShape() {
163 updateGeometry(InterfaceMove);
166 bool GroupItem::updateGeometry(ChangeType type) {
168 QPointF oldOrigin = originPoint;
169 QSize oldSize(totalWidth,totalHeight);
171 bool boxSizeChanged = false;
173 // whatever the change, the minimum size may have changed
176 if (type == Resize) {
177 boxSizeChanged = true;
179 // if an internal block has moved, the actual box size may be inadequate
180 if (boxWidth < minimumBoxWidth) {
181 boxWidth = minimumBoxWidth;
182 boxSizeChanged = true;
184 if (boxHeight < minimumBoxHeight) {
185 boxHeight = minimumBoxHeight;
186 boxSizeChanged = true;
189 if (boxSizeChanged) {
190 updateInterfacesAndConnections();
194 // compute the max. width of interfaces' name for 4 orientations.
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;
206 else if (iface->getOrientation() == Parameters::North) {
207 if (ifaceWidth > maxNorth) maxNorth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
209 else if (iface->getOrientation() == Parameters::East) {
210 if (ifaceWidth > maxEast) maxEast = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
212 else if (iface->getOrientation() == Parameters::West) {
213 if (ifaceWidth > maxWest) maxWest = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength;
218 totalWidth = boxWidth+maxEast;
219 totalHeight = boxHeight+maxSouth;
223 totalWidth += maxWest;
225 if (maxNorth > (nameHeight+2*nameMargin)) {
227 totalHeight += maxNorth;
230 y -= nameHeight+2*nameMargin;
231 totalHeight += nameHeight+2*nameMargin;
233 QSizeF newSize(totalWidth,totalHeight);
237 if ((boxSizeChanged) || (newSize != oldSize) || (originPoint != oldOrigin)) {
238 cout << "must change group item shape" << endl;
239 prepareGeometryChange();
245 void GroupItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
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();
252 //cout << "block abs. pos: " << absPos.x() << "," << absPos.y() << " | ";
253 //cout << "block current. pos: " << currentPosition.x() << "," << currentPosition.y() << " | ";
255 if (absPos.x()+gapX < 0) {
258 if (absPos.y()+gapY < 0) {
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();
269 else if(params->editState == Parameters::EditGroupResize) {
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){
276 if(boxWidth+gapX > minimumBoxWidth){
282 if(boxHeight+gapY > minimumBoxHeight){
287 case CornerSouthEast: {
288 if(boxWidth+gapX > minimumBoxWidth){
291 if(boxHeight+gapY > minimumBoxHeight){
297 cout << "abnormal case while resizing block" << endl;
300 updateGeometry(Resize);
302 // recompute the geometry of the block
304 // update all interfaces positions
305 foreach(InterfaceItem *item, interfaces){
306 item->updatePosition();
308 // update all connections from/to this block
309 foreach(ConnectionItem *item, getScene()->getConnectionItems()){
310 if ((item->getFromInterfaceItem()->getOwner() == this) || (item->getToInterfaceItem()->getOwner() == this)) {
315 cursorPosition = event->scenePos();
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)) {
332 void GroupItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
334 QPointF pos = event->pos();
338 QGraphicsItem::mousePressEvent(event);
340 if(event->button() == Qt::RightButton) return;
342 int mode = getScene()->getEditionMode();
344 dispatcher->setCurrentGroupWidget(getScene()->getGroupWidget());
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.
351 if ((mode == GroupScene::AddConnection) && (params->cursorState == Parameters::CursorOnInterface)) {
352 InterfaceItem *inter = getInterfaceFromCursor(x,y);
355 if (params->editState == Parameters::EditNoOperation) {
356 getScene()->setSelectedInterface(1,inter);
357 params->setEditState(Parameters::EditStartConnection);
359 else if (params->editState == Parameters::EditStartConnection) {
360 if (inter == getScene()->getSelectedInterface(1)) {
361 params->setEditState(Parameters::EditAbortConnection);
364 getScene()->setSelectedInterface(2,inter);
365 params->setEditState(Parameters::EditCloseConnection);
371 if (mode == GroupScene::ItemEdition) {
373 if (params->cursorState == Parameters::CursorOnInterface) {
374 InterfaceItem *inter = getInterfaceFromCursor(x,y);
376 currentInterface = inter;
377 params->setEditState(Parameters::EditInterfaceMove);
380 else if (params->cursorState == Parameters::CursorInGroupTitle) {
381 params->setEditState(Parameters::EditGroupMove);
382 cursorPosition = event->scenePos();
384 else if (params->cursorState == Parameters::CursorOnBorder) {
385 setFlag(ItemIsMovable, false);
386 cursorPosition = event->scenePos();
387 params->setEditState(Parameters::EditGroupResize);
392 void GroupItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
394 int mode = getScene()->getEditionMode();
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.
401 if (mode == GroupScene::AddConnection) {
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());
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);
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);
421 iface1->selected = false;
422 update(iface1->boundingRect());
423 getScene()->setSelectedInterface(1,NULL);
424 getScene()->setSelectedInterface(2,NULL);
425 params->setEditState(Parameters::EditNoOperation);
430 if (mode == GroupScene::ItemEdition) {
431 currentInterface = NULL;
432 setFlag(ItemIsMovable, true);
433 params->editState = Parameters::EditNoOperation;
435 QGraphicsItem::mouseReleaseEvent(event);
438 void GroupItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
439 QPointF pos = event->pos();
442 currentBorder = NoBorder;
443 int mode = getScene()->getEditionMode();
445 if (mode == GroupScene::AddConnection) {
446 InterfaceItem* iface = getInterfaceFromCursor(x,y);
448 params->cursorState = Parameters::CursorOnInterface;
449 setCursor(Qt::PointingHandCursor);
452 params->cursorState = Parameters::CursorNowhere;
453 setCursor(Qt::ArrowCursor);
456 else if (mode == GroupScene::ItemEdition) {
460 InterfaceItem* iface = getInterfaceFromCursor(x,y);
462 params->cursorState = Parameters::CursorOnInterface;
463 setCursor(Qt::PointingHandCursor);
465 else if ((x>boxWidth-marginE)&&(x<boxWidth)) {
467 params->cursorState = Parameters::CursorOnBorder;
469 if ((y>boxHeight-2*marginS)&&(y<boxHeight)) {
470 currentBorder = CornerSouthEast;
471 setCursor(Qt::SizeFDiagCursor);
474 currentBorder = BorderEast;
475 setCursor(Qt::SizeHorCursor);
478 else if ((y>boxHeight-marginS)&&(y<boxHeight)) {
480 params->cursorState = Parameters::CursorOnBorder;
482 if ((x>boxWidth-2*marginE)&&(x<boxWidth)) {
483 currentBorder = CornerSouthEast;
484 setCursor(Qt::SizeFDiagCursor);
487 currentBorder = BorderSouth;
488 setCursor(Qt::SizeVerCursor);
492 if (rectTitle.contains(x,y)) {
493 params->cursorState = Parameters::CursorInGroupTitle;
494 setCursor(Qt::OpenHandCursor);
497 params->cursorState = Parameters::CursorNowhere;
498 setCursor(Qt::ArrowCursor);
502 QGraphicsItem::hoverMoveEvent(event);
505 void GroupItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
507 QAction* titleAction = NULL;
508 QAction* showProperties = NULL;
509 QAction* removeAction = NULL;
510 QAction* renameAction = NULL;
511 QAction* showParameters = NULL;
513 InterfaceItem* ifaceItem = getInterfaceFromCursor(event->pos().x(), event->pos().y());
515 // menu for interface
516 if( ifaceItem != NULL) {
517 titleAction = menu.addAction("Interface operations");
518 titleAction->setEnabled(false);
520 showProperties = menu.addAction("Show properties");
521 renameAction = menu.addAction("Rename");
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.
528 ConnectedInterface* ref = ifaceItem->refInter;
529 if ((!ref->isConnectedFrom()) || (!ref->isConnectedTo())) {
530 removeAction = menu.addAction("Remove");
534 titleAction = menu.addAction("Block operations");
535 titleAction->setEnabled(false);
538 if (refBlock->nbParameters() > 0) {
539 showParameters = menu.addAction("Show parameters");
541 renameAction = menu.addAction("Rename");
543 QAction* selectedAction = menu.exec(event->screenPos());
545 if(selectedAction == NULL) return;
547 if(selectedAction == renameAction){
548 if(ifaceItem != NULL)
549 dispatcher->renameInterface(ifaceItem);
551 dispatcher->renameBlockOrGroup(this);
553 else if(selectedAction == showProperties){
554 dispatcher->showProperties(ifaceItem);
556 else if (selectedAction == removeAction) {
557 dispatcher->removeGroupInterface(ifaceItem);
559 else if(selectedAction == showParameters) {
560 new ParametersWindow(refBlock, params, NULL);
564 InterfaceItem* GroupItem::isHoverInterface(QPointF point) {
565 foreach(InterfaceItem *inter, interfaces){
566 if(inter->boundingRect().contains(point))
572 void GroupItem::save(QXmlStreamWriter &writer) {
574 writer.writeStartElement("group_item");
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());
582 QString attrPos = QString::number(pos().x()).append(",").append(QString::number(pos().y()));
583 QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight()));
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);
592 writer.writeStartElement("group_ifaces");
594 writer.writeAttribute("count",QString::number(interfaces.length()));
596 foreach(InterfaceItem *item, interfaces){
597 writer.writeStartElement("group_iface");
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()));
606 writer.writeEndElement();
609 writer.writeEndElement();//</interfaces>
611 writer.writeEndElement();//</group_item>