2 #include "GroupScene.h"
3 #include "ConnectionItem.h"
4 #include "InterfaceItem.h"
6 #include "Parameters.h"
8 #include "Dispatcher.h"
9 #include "FunctionalBlock.h"
10 #include "FunctionalInterface.h"
11 #include "ReferenceInterface.h"
12 #include "ReferenceBlock.h"
13 #include "ParametersWindow.h"
14 #include "BlockParameter.h"
17 BoxItem::BoxItem(AbstractBlock *_refBlock,
18 Dispatcher *_dispatcher,
19 Parameters *_params, GroupItem *parent) throw(Exception) : AbstractBoxItem( _refBlock, _dispatcher, _params, parent) {
22 _refBlock : mandatory a FunctionalBlock or a GroupBlock
24 if (_refBlock->isReferenceBlock()) throw(Exception(BLOCK_INVALID_TYPE));
26 childGroupItem = NULL;
27 //boxWidth = params->defaultBlockWidth;
28 //boxHeight = params->defaultBlockHeight;
29 currentBorder = NoBorder;
33 setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
36 updateGeometry(InterfaceMove);
37 resetInterfacesPosition();
38 QPointF initPos = QPointF(0.0,0.0) - originPoint;
40 //cout << "total size of block: " << totalWidth << "," << totalHeight << endl;
41 //cout << "pos in group: " << x() << "," << y() << endl;
48 void BoxItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
49 QPen pen(Qt::black, 3);
51 pen.setColor(Qt::red);
54 painter->setBrush(Qt::yellow);
56 painter->drawRect(0,0,boxWidth, boxHeight);
57 painter->drawText(0,0,boxWidth, boxHeight,Qt::AlignCenter | Qt::TextWordWrap,QString(refBlock->getName()));
58 foreach(InterfaceItem *inter, interfaces) {
59 inter->paint(painter);
63 void BoxItem::moveTo(QPointF dest) {
65 currentPosition = dest;
68 bool BoxItem::isBoxItem() {
72 void BoxItem::updateMinimumSize() {
78 int nbSouth = nbInterfacesByOrientation(Parameters::South);
79 int nbNorth = nbInterfacesByOrientation(Parameters::North);
80 int nbMaxSN = nbNorth;
81 if (nbSouth > nbNorth) nbMaxSN = nbSouth;
82 int nbEast = nbInterfacesByOrientation(Parameters::East);
83 int nbWest = nbInterfacesByOrientation(Parameters::West);
85 if (nbWest > nbEast) {
92 foreach(InterfaceItem* iface, interfaces) {
93 ifaceWidth = iface->getNameWidth();
94 ifaceHeight = iface->getNameHeight();
95 if (iface->getOrientation() == Parameters::South) {
96 if (ifaceWidth > maxSouth) maxSouth = ifaceWidth;
98 else if (iface->getOrientation() == Parameters::North) {
99 if (ifaceWidth > maxNorth) maxNorth = ifaceWidth;
101 else if (iface->getOrientation() == Parameters::East) {
102 if (ifaceWidth > maxEast) maxEast = ifaceWidth;
104 else if (iface->getOrientation() == Parameters::West) {
105 if (ifaceWidth > maxWest) maxWest = ifaceWidth;
109 /* NB: the width layout is the following
110 ifaceMargin | maxWest | nameMargin | name | nameMargin | maxEast | ifaceMargin
112 minimumBoxWidth = maxWest+maxEast+nameWidth+2*(ifaceMargin+nameMargin);
113 // if the minimum is not sufficent taking into account N/S interfaces
114 if (minimumBoxWidth < (nbMaxSN*ifaceHeight+ifaceMargin*(nbMaxSN+1))) {
115 minimumBoxWidth = (nbMaxSN*ifaceHeight+ifaceMargin*(nbMaxSN+1));
117 minimumBoxHeight = maxNorth+maxSouth+3*ifaceMargin;
118 if (minimumBoxHeight < (nbMaxEW*ifaceHeight+ifaceMargin*(nbMaxEW+1))) {
119 minimumBoxHeight = (nbMaxEW*ifaceHeight+ifaceMargin*(nbMaxEW+1));
124 /* updateGeometry() :
127 bool BoxItem::updateGeometry(ChangeType type) {
129 currentPosition = pos();
130 //cout << "current pos of block: " << currentPosition.x() << "," << currentPosition.y() << endl;
131 QPointF oldOrigin = originPoint;
132 QSize oldSize(totalWidth,totalHeight);
134 bool boxSizeChanged = false;
136 // whatever the change, the minimum size may ahve changed
139 if (type == Resize) {
140 // resize implies to move interfaces and to update connections
141 boxSizeChanged = true;
143 else if (type == InterfaceMove) {
144 // if an interface moves, it may change the box size
145 if (boxWidth < minimumBoxWidth) {
146 boxWidth = minimumBoxWidth;
147 boxSizeChanged = true;
149 if (boxHeight < minimumBoxHeight) {
150 boxHeight = minimumBoxHeight;
151 boxSizeChanged = true;
154 if (boxSizeChanged) {
155 updateInterfacesAndConnections();
161 totalWidth = boxWidth;
162 totalHeight = boxHeight;
164 if(isInterfaces(Parameters::East)){
165 totalWidth += params->arrowWidth+params->arrowLineLength;
167 if(isInterfaces(Parameters::West)){
168 totalWidth += params->arrowWidth+params->arrowLineLength;
169 x -= params->arrowWidth+params->arrowLineLength;
171 if(isInterfaces(Parameters::South)){
172 totalHeight += params->arrowWidth+params->arrowLineLength;
174 if(isInterfaces(Parameters::North)){
175 totalHeight += params->arrowWidth+params->arrowLineLength;
176 y -= params->arrowWidth+params->arrowLineLength;
178 QSizeF newSize(totalWidth,totalHeight);
182 if ((boxSizeChanged) || (newSize != oldSize) || (originPoint != oldOrigin)) {
183 prepareGeometryChange();
189 void BoxItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
191 if(params->editState == Parameters::EditBlockMove) {
192 QPointF absPos = currentPosition + originPoint;
193 int marginConn = 2*(params->arrowWidth+params->arrowLineLength);
194 int gapX = event->scenePos().x() - cursorPosition.x();
195 int gapY = event->scenePos().y() - cursorPosition.y();
197 //cout << "block abs. pos: " << absPos.x() << "," << absPos.y() << " | ";
198 //cout << "block current. pos: " << currentPosition.x() << "," << currentPosition.y() << " | ";
200 if (absPos.x()+gapX < marginConn) {
201 gapX = marginConn-absPos.x();
203 if (absPos.y()+gapY < marginConn) {
204 gapY = marginConn-absPos.y();
206 //cout << "gap: " << gapX << "," << gapY << endl;
207 QPointF gap(gapX,gapY);
208 currentPosition = currentPosition+gap;
209 setPos(currentPosition);
210 // update all connections from/to this block
211 foreach(ConnectionItem *item, getScene()->getConnectionItems()){
212 if ((item->getFromInterfaceItem()->getOwner() == this) || (item->getToInterfaceItem()->getOwner() == this)) {
216 cursorPosition = event->scenePos();
218 // udpate the groupitem
219 (getScene()->getGroupItem())->updateShape();
221 else if(params->editState == Parameters::EditBlockResize) {
223 int gapX = event->scenePos().x() - cursorPosition.x();
224 int gapY = event->scenePos().y() - cursorPosition.y();
225 //cout << "gap: " << gapX << "," << gapY << endl;
226 switch(currentBorder){
228 if(boxWidth+gapX > minimumBoxWidth){
234 if(boxHeight+gapY > minimumBoxHeight){
239 case CornerSouthEast: {
240 if(boxWidth+gapX > minimumBoxWidth){
243 if(boxHeight+gapY > minimumBoxHeight){
249 cout << "abnormal case while resizing block" << endl;
252 // recompute the geometry of the block and possibly the group item
253 if (updateGeometry(Resize)) {
254 (getScene()->getGroupItem())->updateShape();
257 cursorPosition = event->scenePos();
259 else if(params->editState == Parameters::EditInterfaceMove) {
260 prepareGeometryChange();
261 moveInterfaceTo(event->pos());
262 // recompute the geometry of the block
263 if (updateGeometry(InterfaceMove)) {
264 cout << "must recompute group item geometry" << endl;
265 (getScene()->getGroupItem())->updateShape();
267 // update connection from/to the selected interface
268 foreach(ConnectionItem *item, getScene()->getConnectionItems()){
269 if ((item->getFromInterfaceItem() == currentInterface) || (item->getToInterfaceItem() == currentInterface)) {
276 void BoxItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
278 QPointF pos = event->pos();
282 //QGraphicsItem::mousePressEvent(event);
284 if(event->button() == Qt::RightButton) return;
286 int mode = getScene()->getEditionMode();
288 dispatcher->setCurrentGroupWidget(getScene()->getGroupWidget());
290 if ((mode == GroupScene::AddConnection) && (params->cursorState == Parameters::CursorOnInterface)) {
291 InterfaceItem *inter = getInterfaceFromCursor(x,y);
294 if (params->editState == Parameters::EditNoOperation) {
295 getScene()->setSelectedInterface(1,inter);
296 params->setEditState(Parameters::EditStartConnection);
298 else if (params->editState == Parameters::EditStartConnection) {
299 if (inter == getScene()->getSelectedInterface(1)) {
300 params->setEditState(Parameters::EditAbortConnection);
303 getScene()->setSelectedInterface(2,inter);
304 params->setEditState(Parameters::EditCloseConnection);
309 else if (mode == GroupScene::ItemEdition) {
310 setZValue(zValue()+100);
311 if (params->cursorState == Parameters::CursorOnInterface) {
312 InterfaceItem *inter = getInterfaceFromCursor(x,y);
314 if (inter == currentInterface) {
315 params->setEditState(Parameters::EditInterfaceDeselect);
318 setFlag(ItemIsMovable, false);
319 currentInterface = inter;
320 params->setEditState(Parameters::EditInterfaceMove);
324 else if (params->cursorState == Parameters::CursorInBlock) {
325 selected = !selected;
326 params->setEditState(Parameters::EditBlockMove);
327 cursorPosition = event->scenePos();
328 //cout << "cursor current pos. in scene " << cursorPosition.x() << "," << cursorPosition.y() << endl;
331 else if (params->cursorState == Parameters::CursorOnBorder) {
332 setFlag(ItemIsMovable, false);
333 cursorPosition = event->scenePos();
334 params->setEditState(Parameters::EditBlockResize);
339 void BoxItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
341 setZValue(zValue()-100);
343 int mode = getScene()->getEditionMode();
345 if (mode == GroupScene::AddConnection) {
347 if (params->editState == Parameters::EditStartConnection) {
348 InterfaceItem* iface = getScene()->getSelectedInterface(1);
349 iface->selected = true;
350 update(iface->boundingRect());
352 else if (params->editState == Parameters::EditAbortConnection) {
353 InterfaceItem* iface = getScene()->getSelectedInterface(1);
354 iface->selected = false;
355 update(iface->boundingRect());
356 getScene()->setSelectedInterface(1,NULL);
357 params->setEditState(Parameters::EditNoOperation);
359 else if (params->editState == Parameters::EditCloseConnection) {
360 InterfaceItem* iface1 = getScene()->getSelectedInterface(1);
361 InterfaceItem* iface2 = getScene()->getSelectedInterface(2);
362 bool ok = dispatcher->connect(iface1,iface2);
364 iface1->selected = false;
365 // no update needed since the whole scene will be repainted
366 getScene()->setSelectedInterface(1,NULL);
367 getScene()->setSelectedInterface(2,NULL);
368 params->setEditState(Parameters::EditNoOperation);
371 //QMessageBox::warning(NULL,"Error","Cannot connect selected interfaces", QMessageBox::Ok);
372 getScene()->setSelectedInterface(2,NULL);
373 params->setEditState(Parameters::EditStartConnection);
377 else if (mode == GroupScene::ItemEdition) {
378 currentInterface = NULL;
379 params->editState = Parameters::EditNoOperation;
380 setFlag(ItemIsMovable);
383 QGraphicsItem::mouseReleaseEvent(event);
386 void BoxItem::hoverMoveEvent(QGraphicsSceneHoverEvent * event) {
388 QPointF pos = event->pos();
391 currentBorder = NoBorder;
392 int mode = getScene()->getEditionMode();
394 if (mode == GroupScene::AddConnection) {
395 InterfaceItem* iface = getInterfaceFromCursor(x,y);
397 params->cursorState = Parameters::CursorOnInterface;
398 setCursor(Qt::PointingHandCursor);
401 params->cursorState = Parameters::CursorNowhere;
402 setCursor(Qt::ArrowCursor);
405 else if (mode == GroupScene::ItemEdition) {
409 InterfaceItem* iface = getInterfaceFromCursor(x,y);
411 params->cursorState = Parameters::CursorOnInterface;
412 setCursor(Qt::PointingHandCursor);
414 else if ((x>boxWidth-marginE)&&(x<boxWidth)) {
416 params->cursorState = Parameters::CursorOnBorder;
418 if ((y>boxHeight-2*marginS)&&(y<boxHeight)) {
419 currentBorder = CornerSouthEast;
420 setCursor(Qt::SizeFDiagCursor);
423 currentBorder = BorderEast;
424 setCursor(Qt::SizeHorCursor);
427 else if ((y>boxHeight-marginS)&&(y<boxHeight)) {
429 params->cursorState = Parameters::CursorOnBorder;
431 if ((x>boxWidth-2*marginE)&&(x<boxWidth)) {
432 currentBorder = CornerSouthEast;
433 setCursor(Qt::SizeFDiagCursor);
436 currentBorder = BorderSouth;
437 setCursor(Qt::SizeVerCursor);
441 if ((x>0) && (x<boxWidth-marginE) && (y>0) && (y<boxHeight-marginS)) {
442 params->cursorState = Parameters::CursorInBlock;
443 setCursor(Qt::OpenHandCursor);
446 params->cursorState = Parameters::CursorNowhere;
447 setCursor(Qt::ArrowCursor);
451 QGraphicsItem::hoverMoveEvent(event);
455 void BoxItem::contextMenuEvent(QGraphicsSceneContextMenuEvent * event) {
458 QAction* titleAction = NULL;
459 QAction* removeAction = NULL;
460 QAction* duplicateAction = NULL;
461 QAction* renameAction = NULL;
462 QAction* connectToGroup = NULL;
463 QAction* disconnectFromGroup = NULL;
464 QAction* showProperties = NULL;
465 QAction* cloneInterface = NULL;
466 QAction* openWindow = NULL;
467 QAction* showRstClkInter = NULL;
468 QAction* showParameters = NULL;
470 InterfaceItem* ifaceItem = getInterfaceFromCursor(event->pos().x(), event->pos().y());
471 // menu for interface
472 if( ifaceItem != NULL){
474 titleAction = menu.addAction("Interface operations");
475 titleAction->setEnabled(false);
479 showProperties = menu.addAction("Show properties");
480 renameAction = menu.addAction("Rename");
482 ConnectedInterface* iface = ifaceItem->refInter;
483 ConnectedInterface* ifaceGroup = NULL;
484 bool canRemove = true;
487 if ((iface->getDirection() == AbstractInterface::Input) && (iface->getConnectedFrom() == NULL)) {
488 connectToGroup = menu.addAction("Connect to group input");
490 else if ((iface->getDirection() == AbstractInterface::Output) && (iface->getConnectionToParentGroup() == NULL)) {
491 connectToGroup = menu.addAction("Connect to group output");
493 else if (iface->getConnectionFromParentGroup() != NULL) {
494 ifaceGroup = iface->getConnectionFromParentGroup();
495 //if ((!ifaceGroup->isConnectedFrom()) || (!ifaceGroup->isConnectedTo())) {
496 if (!ifaceGroup->isConnectedFrom()) {
497 disconnectFromGroup = menu.addAction("Disconnect from group");
503 else if (iface->getConnectionToParentGroup() != NULL) {
504 ifaceGroup = iface->getConnectionToParentGroup();
505 //if ((!ifaceGroup->isConnectedFrom()) || (!ifaceGroup->isConnectedTo())) {
506 if (!ifaceGroup->isConnectedTo()) {
507 disconnectFromGroup = menu.addAction("Disconnect from group");
514 if (iface->isFunctionalInterface()) {
515 FunctionalInterface* fi = AI_TO_FUN(ifaceItem->refInter);
516 ReferenceInterface* ri = (ReferenceInterface*)(fi->getReference());
517 if(ri->getMultiplicity() == -1 || ri->getMultiplicity() > 1){
518 cloneInterface = menu.addAction("Duplicate");
519 if ((canRemove) && (fi->getInterfaceMultiplicity() > 1)) {
520 removeAction = menu.addAction("Remove");
525 // menu for blocks (group or func)
527 titleAction = menu.addAction("Block operations");
528 titleAction->setEnabled(false);
531 if (refBlock->nbParameters() > 0) {
532 showParameters = menu.addAction("Show parameters");
534 renameAction = menu.addAction("Rename");
536 if(refBlock->isGroupBlock()){
537 openWindow = menu.addAction("Open/show group window");
540 duplicateAction = menu.addAction("Duplicate");
541 showRstClkInter = menu.addAction("Show reset/clock interfaces");
542 showRstClkInter->setCheckable(true);
543 showRstClkInter->setChecked(rstClkVisible);
545 removeAction = menu.addAction("Remove");
548 QAction* selectedAction = NULL;
549 selectedAction = menu.exec(event->screenPos());
551 if(selectedAction == NULL) return ;
553 if (selectedAction == removeAction) {
554 if(ifaceItem != NULL) {
555 dispatcher->removeBlockInterface(ifaceItem);
558 dispatcher->removeBlock(this);
561 else if (selectedAction == duplicateAction) {
562 dispatcher->duplicateBlock(this);
564 else if(selectedAction == renameAction){
565 if(ifaceItem != NULL)
566 dispatcher->renameInterface(ifaceItem);
568 dispatcher->renameBlockOrGroup(this);
570 else if(selectedAction == showProperties){
571 dispatcher->showProperties(ifaceItem);
573 else if (selectedAction == connectToGroup){
574 dispatcher->connectInterToGroup(ifaceItem);
576 else if (selectedAction == disconnectFromGroup) {
577 dispatcher->disconnectInterFromGroup(ifaceItem);
579 else if (selectedAction == cloneInterface){
580 dispatcher->duplicateInterface(ifaceItem);
582 else if (selectedAction == openWindow){
583 dispatcher->showRaiseWindow(this);
585 else if(selectedAction == showRstClkInter){
586 dispatcher->showRstClkInter(this);
588 else if(selectedAction == showParameters){
589 new ParametersWindow(refBlock, params, NULL);
593 void BoxItem::save(QXmlStreamWriter &writer) {
594 if (refBlock->isFunctionalBlock()) {
595 writer.writeStartElement("bi_functional");
597 writer.writeAttribute("id",QString::number(id));
598 writer.writeAttribute("ref_xml", ((FunctionalBlock*)refBlock)->getReferenceXmlFile());
599 writer.writeAttribute("ref_md5", ((FunctionalBlock*)refBlock)->getReferenceHashMd5());
600 writer.writeAttribute("name",refBlock->getName());
601 QString attrPos = QString::number(pos().x()).append(",").append(QString::number(pos().y()));
602 writer.writeAttribute("position",attrPos);
603 QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight()));
604 writer.writeAttribute("dimension",attrDim);
606 writer.writeStartElement("bif_parameters");
607 foreach(BlockParameter *param,refBlock->getParameters()){
608 writer.writeStartElement("bif_parameter");
610 writer.writeAttribute("name",param->getName());
611 writer.writeAttribute("value",param->getValue().toString());
613 writer.writeAttribute("context",param->getStrContext());
614 writer.writeAttribute("type",param->getTypeString());
616 writer.writeEndElement(); //</bif_parameter>
618 writer.writeEndElement(); //</bif_parameters>
620 writer.writeStartElement("bif_ifaces");
621 writer.writeAttribute("count",QString::number(interfaces.length()));
622 foreach(InterfaceItem* inter, interfaces){
623 writer.writeStartElement("bif_iface");
625 writer.writeAttribute("id",QString::number(inter->getId()));
626 writer.writeAttribute("name",inter->getName());
627 writer.writeAttribute("ref_name",inter->refInter->getName());
628 writer.writeAttribute("orientation",inter->getStrOrientation());
629 writer.writeAttribute("position",QString::number(inter->getPositionRatio()));
631 writer.writeEndElement(); //</bif_iface>
633 writer.writeEndElement(); //</bif_ifaces>
635 writer.writeEndElement(); //</bi_functional>
638 writer.writeStartElement("bi_group");
640 writer.writeAttribute("id",QString::number(id));
641 writer.writeAttribute("inside_group",QString::number(childGroupItem->getId()));
642 QString attrPos = QString::number(pos().x()).append(",").append(QString::number(pos().y()));
643 writer.writeAttribute("position",attrPos);
644 QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight()));
645 writer.writeAttribute("dimension",attrDim);
647 writer.writeStartElement("big_ifaces");
648 writer.writeAttribute("count",QString::number(interfaces.length()));
649 foreach(InterfaceItem* inter, interfaces){
650 writer.writeStartElement("big_iface");
652 writer.writeAttribute("id",QString::number(inter->getId()));
653 writer.writeAttribute("ref_name",inter->refInter->getName());
654 writer.writeAttribute("orientation",inter->getStrOrientation());
655 writer.writeAttribute("position",QString::number(inter->getPositionRatio()));
657 writer.writeEndElement(); //</big_iface>
660 writer.writeEndElement(); //</big_ifaces>
661 writer.writeEndElement(); //</bi_group>
665 QDataStream &operator <<(QDataStream &out, BoxItem &b) {
666 out.setVersion(QDataStream::Qt_4_8);
668 QByteArray blockData;
669 QDataStream toWrite(&blockData, QIODevice::WriteOnly);
671 QString refXml = ((FunctionalBlock*)b.refBlock)->getReferenceXmlFile();
672 QByteArray xmlFile = QByteArray(refXml.toStdString().c_str());
676 toWrite << (int)b.x();
677 toWrite << (int)b.y();
678 toWrite << b.boxWidth;
679 toWrite << b.boxHeight;
680 toWrite << b.getInterfaces().length();
682 for(int i=0; i<b.getInterfaces().length(); i++){
683 InterfaceItem *inter = b.getInterfaces().at(i);
684 toWrite << inter->getId();
685 toWrite << inter->getName();
686 toWrite << inter->getPositionRatio();
687 toWrite << inter->getOrientation();
695 QDataStream &operator >>(QDataStream &in, BoxItem &b)
698 in.setVersion(QDataStream::Qt_4_8);
713 cout << "nbInter:" << nbInter << endl;
714 for(int i=0; i<nbInter; i++){
717 double positionRatio;
720 InterfaceItem *inter = b.getInterfaces().at(i);
727 inter->setName(name);
728 inter->setPositionRatio(positionRatio);
729 inter->setOrientation(orientation);
730 inter->updatePosition();