TinkerCell Core 1.0
TinkerCell's Core library providing all basic functionalities
ConnectionGraphicsItem.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 Copyright (c) 2008 Deepak Chandran
00003 Contact: Deepak Chandran (dchandran1@gmail.com)
00004 See COPYRIGHT.TXT
00005 
00006 This is the source file for the connection graphics item, which is a Qt graphics path item
00007 that draws a connection between two or more nodes.
00008 
00009 The connection graphics items defines a new control point item inside itself.
00010 
00011 This header file also contains the arrow head item class. The arrow head item inherits from
00012 node graphics item and is used to draw the arrow heads at the end of the connection items.
00013 
00014 ****************************************************************************/
00015 #include <math.h>
00016 #include <QPainterPathStroker>
00017 #include "GraphicsScene.h"
00018 #include "MainWindow.h"
00019 #include "ConnectionGraphicsItem.h"
00020 #include "ItemHandle.h"
00021 #include "fileIO/NodeGraphicsReader.h"
00022 #include "UndoCommands.h"
00023 #include "TextGraphicsItem.h"
00024 #include "Tool.h"
00025 
00026 namespace Tinkercell
00027 {
00028         const QString ArrowHeadItem::CLASSNAME = QString("ArrowHeadItem");
00029         const QString ConnectionGraphicsItem::CLASSNAME = QString("ConnectionGraphicsItem");
00030         QString ConnectionGraphicsItem::DefaultMiddleItemFile(":/images/defaultarrow.xml");
00031         QString ConnectionGraphicsItem::DefaultArrowHeadFile(":/images/defaultarrow.xml");
00032 
00033         ItemHandle * ConnectionGraphicsItem::handle() const
00034         {
00035                 return itemHandle;
00036         }
00037 
00038         void ConnectionGraphicsItem::setHandle(ItemHandle * handle)
00039         {
00040                 if (handle != 0 && !handle->graphicsItems.contains(this))
00041                 {
00042                         handle->graphicsItems += this;
00043                 }
00044 
00045                 if (itemHandle)
00046                 {
00047                         if (itemHandle != handle)
00048                         {
00049                                 itemHandle->graphicsItems.removeAll(this);
00050                                 itemHandle = handle;
00051                         }
00052                 }
00053                 else
00054                 {
00055                         itemHandle = handle;
00056                 }
00057         }
00058 
00059         ItemHandle * ConnectionGraphicsItem::ControlPoint::handle() const
00060         {
00061                 /*if (connectionItem)
00062                         return connectionItem->handle();*/
00063                 return 0;
00064         }
00065 
00066         void ConnectionGraphicsItem::ControlPoint::setHandle(ItemHandle * h)
00067         {
00068                 if (connectionItem)
00069                         connectionItem->setHandle(h);
00070         }
00071 
00072 
00073         ControlPoint * ControlPoint::cast(QGraphicsItem* item)
00074         {
00075                 //if (MainWindow::invalidPointers.contains( (void*)item )) return 0;
00076                 if (!item || ToolGraphicsItem::cast(item->topLevelItem())) return 0;
00077 
00078                 ControlPoint * idptr = 0;
00079 
00080                 QGraphicsItem * p = item;
00081 
00082                 while (p)
00083                 {
00084                         idptr = qgraphicsitem_cast<ControlPoint*>(p);
00085                         if (idptr != 0) return idptr;
00086 
00087                         idptr = (ControlPoint*)qgraphicsitem_cast<NodeGraphicsItem::ControlPoint*>(p);
00088                         if (idptr != 0) return idptr;
00089 
00090                         idptr = (ControlPoint*)qgraphicsitem_cast<ConnectionGraphicsItem::ControlPoint*>(p);
00091                         if (idptr != 0) return idptr;
00092 
00093                         if (p != p->parentItem())
00094                                 p = p->parentItem();
00095                         else
00096                                 break;
00097                 }
00098 
00099                 return 0;
00100         }
00101         
00102         QList<ControlPoint*> ControlPoint::cast(const QList<QGraphicsItem*>& items)
00103         {
00104                 QList<ControlPoint*> items2;
00105                 ControlPoint * cp = 0;
00106                 for (int i=0; i < items.size(); ++i)
00107                         if ((cp = ControlPoint::cast(items[i])) && !items2.contains(cp))
00108                                 items2 << cp;
00109                 return items2;
00110         }
00111 
00113         ArrowHeadItem::ArrowHeadItem(ConnectionGraphicsItem* connection) : NodeGraphicsItem()
00114         {
00115                 className = ArrowHeadItem::CLASSNAME;
00116                 connectionItem = connection;
00117                 angle = 0.0;
00118         }
00119         
00121         ArrowHeadItem::ArrowHeadItem(const QString& filename, ConnectionGraphicsItem* connection) : NodeGraphicsItem(filename)
00122         {
00123                 className = ArrowHeadItem::CLASSNAME;
00124                 connectionItem = connection;
00125                 angle = 0.0;
00126         }
00127 
00129         ArrowHeadItem::ArrowHeadItem(const ArrowHeadItem& copy) : NodeGraphicsItem(copy)
00130         {
00131                 connectionItem = copy.connectionItem;
00132                 angle = copy.angle;
00133         }
00134         
00136         NodeGraphicsItem* ArrowHeadItem::clone() const
00137         {
00138                 return new ArrowHeadItem(*this);
00139         }
00140         
00141         ArrowHeadItem* ArrowHeadItem::cast(QGraphicsItem * q)
00142         {
00143                 //if (MainWindow::invalidPointers.contains( (void*)q )) return 0;
00144                 if (!q || ToolGraphicsItem::cast(q->topLevelItem())) return 0;
00145                 return qgraphicsitem_cast<ArrowHeadItem*>(q);
00146         }
00147 
00148 
00150         ConnectionGraphicsItem::ConnectionGraphicsItem(QGraphicsItem * parent) : QGraphicsItemGroup (parent), itemHandle(0)
00151         {
00152                 setCacheMode(QGraphicsItem::DeviceCoordinateCache);
00153                 setFlag(QGraphicsItem::ItemIsMovable, false);
00154                 setFlag(QGraphicsItem::ItemIsSelectable, false);
00155 
00156                 className = ConnectionGraphicsItem::CLASSNAME;
00157                 lineType = bezier;
00158                 arrowHeadDistance = 10.0;
00159                 centerRegionItem = 0;
00160                 centerRegion = QSizeF(20,20);
00161                 defaultPen = QPen(QColor(50,50,255,255),5.0);
00162                 defaultPen.setJoinStyle(Qt::RoundJoin);
00163                 
00164                 boundaryPathItem = new QGraphicsPathItem(this);
00165                 boundaryPathItem->setVisible(false);
00166                 boundaryPathItem->setPen(QPen(QColor(255,150,150,150),4.0,Qt::DotLine));
00167                 boundaryPathItem->setBrush(Qt::NoBrush);
00168                 
00169                 outerPathItem = new QGraphicsPathItem(this);
00170                 outerPathItem->setVisible(true);
00171                 outerPathItem->setPen(QPen(GraphicsScene::BackgroundColor,6.0,Qt::SolidLine));
00172                 outerPathItem->setBrush(Qt::NoBrush);
00173                 
00174                 mainPathItem = new QGraphicsPathItem(this);
00175                 mainPathItem->setVisible(true);
00176                 mainPathItem->setPen(defaultPen);
00177                 mainPathItem->setBrush(Qt::NoBrush);
00178 
00179                 /*ArrowHeadItem * node = new ArrowHeadItem;
00180                 node->connectionItem = this;
00181                 NodeGraphicsReader imageReader;
00182                 imageReader.readXml(node,DefaultMiddleItemFile);
00183                 if (node->isValid())
00184                 {
00185                         node->normalize();
00186                         node->scale(25.0/node->sceneBoundingRect().height(),25.0/node->sceneBoundingRect().height());
00187                 }*/
00188                 centerRegionItem = 0;
00189         }
00190 
00192         ConnectionGraphicsItem::ConnectionGraphicsItem(const ConnectionGraphicsItem& copy) : QGraphicsItemGroup ()
00193         {
00194                 setFlag(QGraphicsItem::ItemIsMovable, false);
00195                 setFlag(QGraphicsItem::ItemIsSelectable, false);
00196                 setVisible(copy.isVisible());
00197 
00198                 className = copy.className;
00199                 groupID = copy.groupID;
00200                 centerRegionItem = 0;
00201                 
00202                 defaultPen = copy.defaultPen;
00203 
00204                 boundaryPathItem = new QGraphicsPathItem(this);
00205                 boundaryPathItem->setVisible(false);
00206                 boundaryPathItem->setPen(QPen(QColor(255,150,150,150),4.0,Qt::DotLine));
00207                 boundaryPathItem->setBrush(Qt::NoBrush);
00208                 
00209                 outerPathItem = new QGraphicsPathItem(this);
00210                 outerPathItem->setVisible(true);
00211                 outerPathItem->setPen(QPen(GraphicsScene::BackgroundColor,6.0,Qt::SolidLine));
00212                 outerPathItem->setBrush(Qt::NoBrush);
00213                 
00214                 mainPathItem = new QGraphicsPathItem(this);
00215                 mainPathItem->setVisible(true);
00216                 mainPathItem->setPen(defaultPen);
00217                 mainPathItem->setBrush(Qt::NoBrush);
00218 
00219                 if (copy.centerRegionItem)
00220                 {
00221                         centerRegionItem = new ArrowHeadItem(*copy.centerRegionItem);
00222                         centerRegionItem->connectionItem = this;
00223                 }
00224 
00225                 centerRegion = copy.centerRegion;
00226                 
00227                 itemHandle = copy.itemHandle;
00228 
00229                 if (itemHandle)
00230                         setHandle(itemHandle);
00231 
00232                 curveSegments = copy.curveSegments;
00233                 lineType = copy.lineType;
00234                 arrowHeadDistance = copy.arrowHeadDistance;
00235                 setPos(copy.scenePos());
00236                 setTransform(copy.sceneTransform());
00237 
00238                 for (int i=0; i < copy.curveSegments.size(); ++i)
00239                 {
00240                         if (copy.curveSegments[i].arrowStart)
00241                         {
00242                                 curveSegments[i].arrowStart = new ArrowHeadItem(*copy.curveSegments[i].arrowStart);
00243                                 curveSegments[i].arrowStart->connectionItem = this;
00244                         }
00245                         if (copy.curveSegments[i].arrowEnd)
00246                         {
00247                                 curveSegments[i].arrowEnd = new ArrowHeadItem(*copy.curveSegments[i].arrowEnd);
00248                                 curveSegments[i].arrowEnd->connectionItem = this;
00249                         }
00250                 }
00251 
00252                 QList<ConnectionGraphicsItem::ControlPoint*> uniquePoints;
00253                 QList<QPoint> locations, positions;
00254 
00255                 for (int i=0; i < copy.curveSegments.size(); ++i)
00256                         for (int j=0; j < copy.curveSegments[i].size(); ++j)
00257                         {
00258                                 positions += QPoint(i,j);
00259 
00260                                 int k = uniquePoints.indexOf(copy.curveSegments[i][j]);
00261                                 if (k > -1)
00262                                 {
00263                                         locations += locations[k];
00264                                         uniquePoints += 0;
00265                                 }
00266                                 else
00267                                 {
00268                                         locations += QPoint(i,j);
00269                                         uniquePoints += (copy.curveSegments[i][j]);
00270                                 }
00271                         }
00272 
00273                         NodeGraphicsItem * parentNode = 0;
00274                         for (int k=0; k < uniquePoints.size() && k < locations.size() && k < positions.size(); ++k)
00275                         {
00276                                 int i = positions[k].x(),
00277                                         j = positions[k].y();
00278                                 if (copy.curveSegments[i][j])
00279                                 {
00280                                         if (uniquePoints[k])
00281                                         {
00282                                                 curveSegments[i][j] = new ConnectionGraphicsItem::ControlPoint(*copy.curveSegments[i][j]);
00283                                                 curveSegments[i][j]->connectionItem = this;
00284                                                 curveSegments[i][j]->setVisible(false);
00285 
00286                                                 if (copy.curveSegments[i][j]->parentItem())
00287                                                 {
00288                                                         parentNode = NodeGraphicsItem::cast(copy.curveSegments[i][j]->parentItem());
00289                                                         if (parentNode == copy.curveSegments[i].arrowEnd)
00290                                                                 curveSegments[i][j]->setParentItem(curveSegments[i].arrowEnd);
00291                                                         else
00292                                                                 if (parentNode == copy.curveSegments[i].arrowStart)
00293                                                                         curveSegments[i][j]->setParentItem(curveSegments[i].arrowStart);
00294                                                                 else
00295                                                                         curveSegments[i][j]->setParentItem(copy.curveSegments[i][j]->parentItem());
00296 
00297                                                 }
00298                                         }
00299                                         else
00300                                         {
00301                                                 curveSegments[i][j] = curveSegments[locations[k].x()][locations[k].y()];
00302                                         }
00303                                 }
00304                         }
00305         }
00306 
00308         ConnectionGraphicsItem* ConnectionGraphicsItem::clone() const
00309         {
00310                 ConnectionGraphicsItem * c = new ConnectionGraphicsItem(*this);
00311                 //c->className = ConnectionGraphicsItem::CLASSNAME;
00312                 return c;
00313         }
00314 
00316         ConnectionGraphicsItem& ConnectionGraphicsItem::operator = (const ConnectionGraphicsItem& copy)
00317         {
00318                 clear(true);
00319 
00320                 if (copy.centerRegionItem)
00321                 {
00322                         QList<QGraphicsItem*> children;
00323                         if (centerRegionItem)
00324                                 children = centerRegionItem->childItems();
00325                         centerRegionItem = new ArrowHeadItem(*copy.centerRegionItem);
00326                         centerRegionItem->connectionItem = this;
00327                         for (int i=0; i < children.size(); ++i)
00328                                 if (ControlPoint::cast(children[i]))
00329                                 {
00330                                         children[i]->setParentItem(centerRegionItem);
00331                                 }
00332                 }
00333                 else
00334                 {
00335                         centerRegionItem = 0;
00336                 }
00337                 centerRegion = copy.centerRegion;
00338 
00339                 itemHandle = copy.itemHandle;
00340 
00341                 if (itemHandle)
00342                         setHandle(itemHandle);
00343 
00344                 curveSegments = copy.curveSegments;
00345                 lineType = copy.lineType;
00346                 arrowHeadDistance = copy.arrowHeadDistance;
00347                 if (mainPathItem && outerPathItem)
00348                 {
00349                         mainPathItem->setPen(defaultPen = copy.defaultPen);
00350                         outerPathItem->setPen( QPen(QBrush(defaultPen.color()), defaultPen.widthF() + 1.0 ) );
00351                 }
00352 
00353                 setPos(copy.scenePos());
00354                 setTransform(copy.sceneTransform());
00355 
00356                 for (int i=0; i < copy.curveSegments.size(); ++i)
00357                 {
00358                         if (copy.curveSegments[i].arrowStart)
00359                         {
00360                                 curveSegments[i].arrowStart = new ArrowHeadItem(*copy.curveSegments[i].arrowStart);
00361                                 curveSegments[i].arrowStart->connectionItem = this;
00362                         }
00363                         if (copy.curveSegments[i].arrowEnd)
00364                         {
00365                                 curveSegments[i].arrowEnd = new ArrowHeadItem(*copy.curveSegments[i].arrowEnd);
00366                                 curveSegments[i].arrowEnd->connectionItem = this;
00367                         }
00368                 }
00369 
00370                 QList<ConnectionGraphicsItem::ControlPoint*> uniquePoints;
00371                 QList<QPoint> locations, positions;
00372 
00373                 for (int i=0; i < copy.curveSegments.size(); ++i)
00374                         for (int j=0; j < copy.curveSegments[i].size(); ++j)
00375                         {
00376                                 positions += QPoint(i,j);
00377 
00378                                 int k = uniquePoints.indexOf(copy.curveSegments[i][j]);
00379                                 if (k > -1)
00380                                 {
00381                                         locations += locations[k];
00382                                         uniquePoints += 0;
00383                                 }
00384                                 else
00385                                 {
00386                                         locations += QPoint(i,j);
00387                                         uniquePoints += (copy.curveSegments[i][j]);
00388                                 }
00389                         }
00390 
00391                         NodeGraphicsItem * parentNode = 0;
00392                         for (int k=0; k < uniquePoints.size() && k < locations.size() && k < positions.size(); ++k)
00393                         {
00394                                 int i = positions[k].x(),
00395                                         j = positions[k].y();
00396                                 if (copy.curveSegments[i][j])
00397                                 {
00398                                         if (uniquePoints[k])
00399                                         {
00400                                                 curveSegments[i][j] = new ConnectionGraphicsItem::ControlPoint(*copy.curveSegments[i][j]);
00401                                                 curveSegments[i][j]->connectionItem = this;
00402                                                 curveSegments[i][j]->setVisible(false);
00403 
00404                                                 if (copy.curveSegments[i][j]->parentItem())
00405                                                 {
00406                                                         parentNode = NodeGraphicsItem::cast(copy.curveSegments[i][j]->parentItem());
00407                                                         if (parentNode == copy.curveSegments[i].arrowEnd)
00408                                                                 curveSegments[i][j]->setParentItem(curveSegments[i].arrowEnd);
00409                                                         else
00410                                                                 if (parentNode == copy.curveSegments[i].arrowStart)
00411                                                                         curveSegments[i][j]->setParentItem(curveSegments[i].arrowStart);
00412                                                                 else
00413                                                                         curveSegments[i][j]->setParentItem(copy.curveSegments[i][j]->parentItem());
00414 
00415                                                 }
00416                                         }
00417                                         else
00418                                         {
00419                                                 curveSegments[i][j] = curveSegments[locations[k].x()][locations[k].y()];
00420                                         }
00421                                 }
00422                         }
00423                         return *this;
00424         }
00425         
00426          QPen ConnectionGraphicsItem::pen() const
00427          {
00428                 if (mainPathItem)
00429                         return mainPathItem->pen();
00430                 else
00431                         return QPen();
00432          }
00433         
00434         void ConnectionGraphicsItem::setPen(QPen pen, bool permanent)
00435         {
00436                 if (permanent)
00437                         defaultPen = pen;
00438                 if (mainPathItem)
00439                         mainPathItem->setPen(pen);
00440         }
00441         
00442         void ConnectionGraphicsItem::setPath(const QPainterPath& path)
00443         {
00444                 if (mainPathItem && outerPathItem)
00445                 {
00446                         QPen pen = mainPathItem->pen();
00447 
00448                         if (pen.style() == Qt::SolidLine)
00449                         {
00450                                 mainPathItem->setPath(this->pathShape);
00451                                 outerPathItem->setPath(this->pathShape);
00452                         }
00453                         else
00454                         {
00455                                 mainPathItem->setPath(path);
00456                                 outerPathItem->setPath(path);
00457                         }
00458 
00459                         outerPathItem->setPen( QPen( QBrush(GraphicsScene::BackgroundColor), pen.widthF() + 2.0 ));
00460                 }
00461         }
00462         
00464         ConnectionGraphicsItem& ConnectionGraphicsItem::copyPoints (const ConnectionGraphicsItem& copy)
00465         {
00466                 clear();
00467 
00468                 lineType = copy.lineType;
00469                 arrowHeadDistance = copy.arrowHeadDistance;
00470 
00471                 centerRegion = copy.centerRegion;
00472 
00473                 //itemHandle = copy.itemHandle;
00474                 setPen(defaultPen = copy.defaultPen);
00475 
00476                 for (int i=0; i < copy.curveSegments.size() && i < curveSegments.size(); ++i)
00477                         for (int j=0; j < copy.curveSegments[i].size() && j < curveSegments[i].size(); ++j)
00478                                 if (copy.curveSegments[i][j] && curveSegments[i][j] && curveSegments[i][j]->parentItem() == 0)
00479                                         curveSegments[i][j]->setPos(copy.curveSegments[i][j]->scenePos());
00480 
00481                 return *this;
00482         }
00483 
00485         ConnectionGraphicsItem::~ConnectionGraphicsItem()
00486         {
00487                 clear(true);
00488                 if (!itemHandle) return;
00489                 setHandle(0);
00490         }
00491 
00493         bool ConnectionGraphicsItem::isValid()
00494         {
00495                 for (int i=0; i < curveSegments.size(); ++i)
00496                         if (curveSegments[i].size() < 4)
00497                                 return false;
00498                 return (curveSegments.size() > 0);
00499         }
00500 
00501         /*
00502         void ConnectionGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget)
00503         {
00504                 //painter->setClipRect( option->exposedRect );
00505                 //refresh();
00506 
00507                 painter->setBrush(Qt::NoBrush);
00508                 painter->setPen(QPen(GraphicsScene::BackgroundColor,pen().width()+4));
00509                 painter->drawPath(path());//this->pathShape);
00510 
00511                 painter->setBrush(brush());
00512                 painter->setPen(pen());
00513                 painter->drawPath(path());//this->pathShape);
00514         }*/
00515 
00517         ConnectionGraphicsItem::ControlPoint::ControlPoint(ConnectionGraphicsItem * reaction_ptr, QGraphicsItem * parent) :
00518         Tinkercell::ControlPoint(parent)
00519         {
00520                 connectionItem = reaction_ptr;
00521                 setPen( defaultPen = QPen( QColor(100,100,255) ) );
00522                 setBrush( defaultBrush = QBrush( QColor(0,0,255,10)) );
00523                 setRect(QRectF(-10,-10,20,20));
00524                 setZValue(1);
00525         }
00526 
00528         ConnectionGraphicsItem::ControlPoint::ControlPoint(const QPointF& pos, ConnectionGraphicsItem * reaction_ptr, QGraphicsItem * parent) :
00529         Tinkercell::ControlPoint(parent)
00530         {
00531                 connectionItem = reaction_ptr;
00532                 setPen( defaultPen = QPen( QColor(100,100,255) ) );
00533                 setBrush( defaultBrush = QBrush( QColor(0,0,255,10)) );
00534                 setRect(QRectF(-10,-10,20,20));
00535                 setZValue(1);
00536                 setPos(pos);
00537         }
00539         ConnectionGraphicsItem::ControlPoint::ControlPoint(const ControlPoint& copy) : Tinkercell::ControlPoint(copy.parentItem())
00540         {
00541                 connectionItem = copy.connectionItem;
00542                 setPos(copy.scenePos());
00543                 setRect(copy.rect());
00544                 setBrush(defaultBrush = copy.defaultBrush);
00545                 setPen(defaultPen = copy.defaultPen);
00546                 //setTransform(copy.transform());
00547         }
00548 
00550         ControlPoint* ConnectionGraphicsItem::ControlPoint::clone() const
00551         {
00552                 return new ConnectionGraphicsItem::ControlPoint(*this);
00553         }
00554 
00556         ConnectionGraphicsItem::ControlPoint::~ControlPoint()
00557         {
00558                 if (connectionItem)
00559                 {
00560                         for (int i=0; i < connectionItem->curveSegments.size(); ++i)
00561                                 for (int j=0; j < connectionItem->curveSegments[i].size(); ++j)
00562                                         if (connectionItem->curveSegments[i][j] == this)
00563                                                 connectionItem->curveSegments[i][j] = 0;
00564                 }
00565         }
00566 
00568         ConnectionGraphicsItem::ControlPoint& ConnectionGraphicsItem::ControlPoint::operator =(const ControlPoint& copy)
00569         {
00570                 connectionItem = copy.connectionItem;
00571                 setPos(copy.scenePos());
00572                 setRect(copy.rect());
00573                 setBrush(defaultBrush = copy.defaultBrush);
00574                 setPen(defaultPen = copy.defaultPen);
00575                 return *this;
00576         }
00577 
00579         QPainterPath ConnectionGraphicsItem::shape() const
00580         {
00581                 return pathShape;
00582         }
00583 
00585         ConnectionGraphicsItem::ControlPoint * ConnectionGraphicsItem::centerPoint() const
00586         {
00587                 for (int i=0; i < curveSegments.size(); ++i)
00588                 {
00589                         if (curveSegments[i].last() && (NodeGraphicsItem::cast(curveSegments[i].last()->parentItem()) == 0)
00590                                 && curveSegments.size() > 1 && curveSegments[i].arrowEnd == 0)
00591                                 return curveSegments[i].last();
00592                 }
00593                 if (curveSegments.size() > 0 && curveSegments[0].size() >= 4)
00594                 {
00595                         int i = curveSegments[0].size()/2;
00596                         if (lineType == line || curveSegments[0].size() > 4)
00597                                 i = 3 * (int)(i/3);
00598                         return curveSegments[0][i];
00599                 }
00600                 return 0;
00601         }
00602 
00604         QPointF ConnectionGraphicsItem::centerLocation() const
00605         {
00606                 QPointF p(0,0);
00607                 if (scene())
00608                 {
00609                         if (pathShape.elementCount() > 0 && curveSegments.size() == 1 && curveSegments[0].size() < 5)
00610                         {
00611                                 p = pathShape.pointAtPercent(0.25);
00612                         }
00613                         else
00614                         {
00615                                 ConnectionGraphicsItem::ControlPoint * cp  = centerPoint();
00616                                 if (cp && cp->scene())
00617                                         p = centerPoint()->scenePos();
00618                         }
00619                         if (!p.isNull())
00620                                 return p;
00621                 }
00622                 
00623                 p = QPointF(0,0);
00624 
00625                 NodeGraphicsItem * node;
00626                 int n = 0;
00627                 for (int i=0; i < curveSegments.size(); ++i)
00628                         if (curveSegments[i].size() > 0 && curveSegments[i][0])
00629                         {
00630                                 node = NodeGraphicsItem::cast(curveSegments[i][0]->parentItem());
00631                                 if (node && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
00632                                 {
00633                                         p += node->scenePos();
00634                                         ++n;
00635                                 }
00636                                 if (curveSegments[i].size() > 1 && curveSegments[i][curveSegments[i].size()-1])
00637                                 {
00638                                         node = NodeGraphicsItem::cast(curveSegments[i][curveSegments[i].size()-1]->parentItem());
00639                                         if (node && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
00640                                         {
00641                                                 p += node->scenePos();
00642                                                 ++n;
00643                                         }
00644                                 }
00645                         }
00646                 p /= n;
00647                 return p;
00648         }
00649 
00653         void ConnectionGraphicsItem::adjustEndPoints(bool arrowTransform)
00654         {
00655                 if (!scene()) return;
00656 
00657                 //firstPoint = point on the node, lastPoint = point at the center (might be modifier)
00658                 //cp0 = point just before firstPoint, cp1 = point just before lastPoint
00659                 ControlPoint * firstPoint, *lastPoint, * cp0, * cp1;
00660                 int truePaths = 0; //number of non-modifier paths
00661 
00662                 //when there is only one path (1-to-1), the situation is totally different
00663                 for (int i=0; i < curveSegments.size(); ++i)
00664                 {
00665                         firstPoint = curveSegments[i].first();
00666                         lastPoint = curveSegments[i].last();
00667 
00668                         if (curveSegments[i].size() < 4 || !lastPoint || !firstPoint) continue;
00669 
00670                         if (firstPoint->parentItem() != 0 &&
00671                                 ((lastPoint->parentItem() != 0 &&
00672                                 lastPoint->parentItem() != curveSegments[i].arrowEnd)
00673                                 || (lastPoint->parentItem() == 0)))
00674                                 ++truePaths;
00675 
00676                         if (lineType == bezier)
00677                                 cp0 = curveSegments[i][ 1 ];
00678                         else
00679                                 cp0 = curveSegments[i][ 3 ];
00680 
00681                         if (lineType == bezier)
00682                                 cp1 = curveSegments[i][ curveSegments[i].size()-2 ];
00683                         else
00684                                 cp1 = curveSegments[i][ curveSegments[i].size()-4 ];
00685 
00686                         //adjust firstPoint so that it lies on the boundary rect of the item it points to
00687                         NodeGraphicsItem * node = 0;
00688                         if (firstPoint != 0 && cp0 != 0 && (node = NodeGraphicsItem::cast(firstPoint->parentItem())) != 0)
00689                         {
00690                                 QRectF parentRect = node->sceneBoundingRect();
00691                                 //QPainterPath parentShape = node->mapToScene(node->shape());
00692 
00693                                 if (firstPoint->isVisible())
00694                                         firstPoint->setVisible(false);
00695                                 if (curveSegments[i].arrowStart != 0)
00696                                 {
00697                                         QPointF p = pointOnEdge(*node, cp0->scenePos(), arrowHeadDistance , lineType == line);
00698 
00699                                         firstPoint->setPos( node->mapFromScene(p) );
00700 
00701                                         if (curveSegments[i].arrowStart->scene() != scene() && scene())
00702                                         {
00703                                                 if (curveSegments[i].arrowStart->scene())
00704                                                         curveSegments[i].arrowStart->scene()->removeItem(curveSegments[i].arrowStart);
00705                                                 (static_cast<GraphicsScene*>(scene()))->addItem(curveSegments[i].arrowStart);
00706                                         }
00707 
00708                                         curveSegments[i].arrowStart->setZValue(zValue() + 0.1);
00709 
00710                                         if (curveSegments[i].arrowStart->handle() != 0)  //arrow should not have handles
00711                                                 Tinkercell::setHandle(curveSegments[i].arrowStart,0);
00712 
00713                                         if (curveSegments[i].arrowStart->parentItem() == 0)
00714                                         {
00715                                                 QPointF p2 = p;//pointOnEdge( *node, cp0->scenePos(), arrowHeadDistance, lineType == line);
00716                                                 curveSegments[i].arrowStart->setPos(p2);
00717                                         }
00718 
00719                                         qreal angle;
00720                                         if (cp0->x() == p.x())
00721                                                 if (cp0->y() < p.y())
00722                                                         angle = 90.0;
00723                                                 else
00724                                                         angle = -90.0;
00725 
00726                                         else
00727                                                 angle = atan((cp0->y()-p.y())/(cp0->x()-p.x())) * 180.0/3.14159;
00728 
00729                                         if (cp0->x() > p.x())
00730                                                 if (cp0->y() < p.y())
00731                                                         angle += 180.0;
00732                                                 else
00733                                                         angle -= 180.0;
00734 
00735 
00736                                         if (curveSegments[i].arrowStart->angle != angle)
00737                                         {
00738                                                 double dx = angle - curveSegments[i].arrowStart->angle;
00739                                                 
00740                                                 if (arrowTransform)
00741                                                 {
00742                                                         double sinx = sin(dx * 3.14159/180.0),
00743                                                                   cosx = cos(dx * 3.14159/180.0);
00744                                                         QTransform rotate(cosx, sinx, -sinx, cosx, 0, 0);
00745                                                         QTransform t = curveSegments[i].arrowStart->transform();
00746                                                         curveSegments[i].arrowStart->setTransform(t * rotate);
00747                                                 }
00748                                                 curveSegments[i].arrowStart->angle = angle;
00749                                         }
00750                                 }
00751                                 else
00752                                 {
00753                                         firstPoint->setPos(
00754                                                 node->mapFromScene(
00755                                                 pointOnEdge(*node, cp0->scenePos(), arrowHeadDistance/2.0, lineType == line)));
00756                                 }
00757                         }
00758 
00759                         //adjust modifier arrows (if exists) by using center region
00760                         ControlPoint * centerPoint = this->centerPoint();
00761                         if (cp1 != 0 && centerPoint && lastPoint != centerPoint && curveSegments[i].arrowEnd != 0
00762                                 && (lastPoint->parentItem() == 0 || lastPoint->parentItem() == curveSegments[i].arrowEnd)
00763                                 && curveSegments.size() > 1)
00764                         {
00765                                 QPointF centerPoint = this->centerPoint()->scenePos();
00766                                 QRectF centerRect(centerPoint - QPointF(centerRegion.width(),centerRegion.height())/2.0, centerRegion);
00767                                 QPointF p = pointOnEdge(centerRect, cp1->scenePos(), arrowHeadDistance + 2.0,lineType == line);
00768                                 QPointF p2 = cp1->scenePos();
00769                                 if (lastPoint->parentItem() != curveSegments[i].arrowEnd)
00770                                         lastPoint->setParentItem(curveSegments[i].arrowEnd);
00771 
00772                                 curveSegments[i].arrowEnd->setPos(p);
00773                                 lastPoint->setPos(curveSegments[i].arrowEnd->mapFromScene(p) );
00774 
00775                                 if (curveSegments[i].arrowEnd->scene() != scene() && scene())
00776                                 {
00777                                         if (curveSegments[i].arrowEnd->scene())
00778                                                 curveSegments[i].arrowEnd->scene()->removeItem(curveSegments[i].arrowEnd);
00779                                         (static_cast<GraphicsScene*>(scene()))->addItem(curveSegments[i].arrowEnd);
00780                                 }
00781 
00782                                 curveSegments[i].arrowEnd->setZValue(zValue() + 0.1);
00783 
00784                                 qreal angle;
00785                                 if (cp1->x() == p.x())
00786                                         if (cp1->y() < p.y())
00787                                                 angle = 90.0;
00788                                         else
00789                                                 angle = -90.0;
00790                                 else
00791                                         angle = atan((cp1->y() - p.y())/(cp1->x() - p.x())) * 180.0/3.14159;
00792                                 if (cp1->x() > p.x())
00793                                         if (cp1->y() < p.y())
00794                                                 angle += 180.0;
00795                                         else
00796                                                 angle -= 180.0;
00797 
00798                                 if (curveSegments[i].arrowEnd->angle != angle)
00799                                 {
00800                                         double dx = angle - curveSegments[i].arrowEnd->angle;
00801                                         if (arrowTransform)
00802                                         {
00803                                                 double sinx = sin(dx * 3.14159/180.0),
00804                                                            cosx = cos(dx * 3.14159/180.0);
00805                                                 QTransform rotate(cosx, sinx, -sinx, cosx, 0, 0);
00806                                                 QTransform t = curveSegments[i].arrowEnd->transform();
00807                                                 curveSegments[i].arrowEnd->setTransform(t * rotate);
00808                                         }
00809                                         curveSegments[i].arrowEnd->angle = angle;
00810                                 }
00811                         }
00812                 }
00813 
00814                 if (truePaths == 1 && curveSegments[0].size() >= 4)
00815                 {
00816                         firstPoint = curveSegments[0].last();
00817                         lastPoint = curveSegments[0].first();
00818 
00819                         if (lineType == bezier)
00820                                 cp0 = curveSegments[0][ curveSegments[0].size()-2 ];
00821                         else
00822                                 cp0 = curveSegments[0][ curveSegments[0].size()-4 ];
00823 
00824                         NodeGraphicsItem * node = NodeGraphicsItem::cast(firstPoint->parentItem());
00825                         NodeGraphicsItem * node2 = NodeGraphicsItem::cast(lastPoint->parentItem());
00826                         if (firstPoint != 0 && cp0 != 0 && node && node2)
00827                         {
00828                                 QRectF parentRect1 = node->sceneBoundingRect(),
00829                                         parentRect2 = node2->sceneBoundingRect();
00830                                 //QPainterPath parentShape = node->mapToScene(node->shape());
00831 
00832                                 if (firstPoint->isVisible())
00833                                         firstPoint->setVisible(false);
00834 
00835                                 QPointF p0 = cp0->scenePos();
00836 
00837                                 if (curveSegments[0].arrowEnd != 0)
00838                                 {
00839                                         QPointF p = pointOnEdge(*node, cp0->scenePos(), arrowHeadDistance,lineType == line);
00840 
00841                                         if (lineType == line && curveSegments[0].size() == 4)
00842                                         {
00843                                                 if (p.rx() == p0.rx())
00844                                                 {
00845                                                         if (parentRect1.center().rx() > parentRect2.left() && parentRect1.center().rx() < parentRect2.right())
00846                                                                 p.rx() = parentRect1.center().rx();
00847                                                         else
00848                                                                 if (parentRect2.center().rx() > parentRect1.left() && parentRect2.center().rx() < parentRect1.right())
00849                                                                         p.rx() = parentRect2.center().rx();
00850                                                 }
00851                                                 else
00852                                                         if (p.ry() == p0.ry())
00853                                                         {
00854                                                                 if (parentRect1.center().ry() > parentRect2.top() && parentRect1.center().ry() < parentRect2.bottom())
00855                                                                         p.ry() = parentRect1.center().ry();
00856                                                                 else
00857                                                                         if (parentRect2.center().ry() > parentRect1.top() && parentRect2.center().ry() < parentRect1.bottom())
00858                                                                                 p.ry() = parentRect2.center().ry();
00859                                                         }
00860                                         }
00861 
00862                                         firstPoint->setPos( node->mapFromScene(p) );
00863 
00864                                         if (curveSegments[0].arrowEnd->scene() != scene() && scene())
00865                                         {
00866                                                 if (curveSegments[0].arrowEnd->scene())
00867                                                         curveSegments[0].arrowEnd->scene()->removeItem(curveSegments[0].arrowEnd);
00868                                                 (static_cast<GraphicsScene*>(scene()))->addItem(curveSegments[0].arrowEnd);
00869                                         }
00870 
00871                                         if (curveSegments[0].arrowEnd->parentItem() == 0)
00872                                         {
00873                                                 QPointF p2 = p;//pointOnEdge(*node, cp0->scenePos(), arrowHeadDistance,lineType == line);
00874                                                 curveSegments[0].arrowEnd->setPos(p2);
00875                                         }
00876 
00877                                         curveSegments[0].arrowEnd->setZValue(zValue() + 0.1);
00878 
00879                                         qreal angle;
00880                                         if (cp0->x() == p.x())
00881                                                 if (cp0->y() < p.y())
00882                                                         angle = 90.0;
00883                                                 else
00884                                                         angle = -90.0;
00885                                         else
00886                                                 angle = atan((cp0->y()-p.y())/(cp0->x()-p.x())) * 180.0/3.14159;
00887                                         if (cp0->x() > p.x())
00888                                                 if (cp0->y() < p.y())
00889                                                         angle += 180.0;
00890                                                 else
00891                                                         angle -= 180.0;
00892 
00893                                         if (curveSegments[0].arrowEnd->angle != angle)
00894                                         {
00895                                                 double dx = angle - curveSegments[0].arrowEnd->angle;
00896                                                 if (arrowTransform)
00897                                                 {
00898                                                         double sinx = sin(dx * 3.14159/180.0),
00899                                                                    cosx = cos(dx * 3.14159/180.0);
00900                                                         QTransform rotate(cosx, sinx, -sinx, cosx, 0, 0);
00901                                                         QTransform t = curveSegments[0].arrowEnd->transform();
00902                                                         curveSegments[0].arrowEnd->setTransform(t * rotate);
00903                                                 }
00904                                                 curveSegments[0].arrowEnd->angle = angle;
00905                                         }
00906                                 }
00907                                 else
00908                                 {
00909                                         QRectF parentRect1 = node->sceneBoundingRect(),
00910                                                 parentRect2 = node2->sceneBoundingRect();
00911 
00912                                         QPointF p = pointOnEdge(*node,cp0->scenePos(),arrowHeadDistance/2.0,lineType == line);
00913 
00914                                         if (lineType == line && curveSegments[0].size() == 4)
00915                                         {
00916                                                 if (p.rx() == p0.rx())
00917                                                 {
00918                                                         if (parentRect1.center().rx() > parentRect2.left() && parentRect1.center().rx() < parentRect2.right())
00919                                                                 p.rx() = parentRect1.center().rx();
00920                                                         else
00921                                                                 if (parentRect2.center().rx() > parentRect1.left() && parentRect2.center().rx() < parentRect1.right())
00922                                                                         p.rx() = parentRect2.center().rx();
00923                                                 }
00924                                                 else
00925                                                         if (p.ry() == p0.ry())
00926                                                         {
00927                                                                 if (parentRect1.center().ry() > parentRect2.top() && parentRect1.center().ry() < parentRect2.bottom())
00928                                                                         p.ry() = parentRect1.center().ry();
00929                                                                 else
00930                                                                         if (parentRect2.center().ry() > parentRect1.top() && parentRect2.center().ry() < parentRect1.bottom())
00931                                                                                 p.ry() = parentRect2.center().ry();
00932                                                         }
00933                                         }
00934 
00935                                         firstPoint->setPos( node->mapFromScene(p) );
00936                                 }
00937                         }
00938                 }
00939 
00940         }
00941 
00945         void ConnectionGraphicsItem::refresh(bool arrowTransform)
00946         {
00947                 setPos(0,0);
00948                 adjustEndPoints(arrowTransform);
00949                 qreal z = zValue();
00950                 
00951                 if (MainWindow::invalidPointers.contains(centerRegionItem))
00952                 {
00953                         centerRegionItem = 0;
00954                 }
00955                 
00956                 if (centerRegionItem)// && centerRegionItem->parentItem() == 0)
00957                 {
00958                         centerRegionItem->connectionItem = this;
00959                         if (centerRegionItem->scene() != this->scene() && this->scene())
00960                         {
00961                                 QList<QGraphicsItem*> children = centerRegionItem->childItems();
00962                                 for (int i=0; i < children.size(); ++i)
00963                                         if (qgraphicsitem_cast<ConnectionGraphicsItem::ControlPoint*>(children[i]))
00964                                         {
00965                                                 if (centerRegionItem->scene())
00966                                                         centerRegionItem->scene()->removeItem(centerRegionItem);
00967                                                 (static_cast<GraphicsScene*>(scene()))->addItem(centerRegionItem);
00968                                                 break;
00969                                         }
00970                         }
00971                 
00972                         centerRegionItem->setPos( centerLocation() );
00973                         centerRegionItem->setZValue(z + 0.01);
00974 
00975                         QList<ConnectionGraphicsItem*> otherConnections = centerRegionItem->connections();
00976                         for (int i=0; i < otherConnections.size(); ++i)
00977                                 if (otherConnections[i] && otherConnections[i] != this)
00978                                         otherConnections[i]->refresh();
00979                 }
00980 
00981                 QPainterPath path;
00982                 
00983                 //text items
00984                 QList<TextGraphicsItem*> textItems;
00985                 if (itemHandle)
00986                 {
00987                         TextGraphicsItem * textItem;
00988                         QList<QGraphicsItem*> & gitems = itemHandle->graphicsItems;
00989                         QPointF center = centerLocation();
00990                         for (int i=0; i < gitems.size(); ++i)
00991                                 if ( !gitems[i]->parentItem() && 
00992                                          (textItem = TextGraphicsItem::cast(gitems[i])) &&
00993                                           textItem->sceneBoundingRect().intersects(pathBoundingRect.adjusted(-10,-10,10,10)))
00994                         {
00995                                 textItem->relativePosition.first = this;
00996                                 textItem->relativePosition.second = textItem->scenePos() - center;
00997                                 textItems << textItem;
00998                         }
00999                 }
01000 
01001                 if (lineType == line)
01002                 {
01003                         QPointF pos;
01004                         for (int i=0; i < curveSegments.size(); ++i)
01005                         {
01006                                 if (MainWindow::invalidPointers.contains(curveSegments[i].arrowStart))
01007                                         curveSegments[i].arrowStart = 0;
01008                                 if (curveSegments[i].arrowStart)
01009                                 {
01010                                         if (curveSegments[i].arrowStart->scene() != this->scene() && this->scene())
01011                                         {
01012                                                 if (curveSegments[i].arrowStart->scene())
01013                                                         curveSegments[i].arrowStart->scene()->removeItem(curveSegments[i].arrowStart);
01014                                                 (static_cast<GraphicsScene*>(scene()))->addItem(curveSegments[i].arrowStart);
01015                                         }
01016                                         curveSegments[i].arrowStart->setZValue(z + 0.1);
01017                                 }
01018                                 
01019                                 if (MainWindow::invalidPointers.contains(curveSegments[i].arrowEnd))
01020                                         curveSegments[i].arrowEnd = 0;
01021                                 
01022                                 if (curveSegments[i].arrowEnd)
01023                                 {
01024                                         if (curveSegments[i].arrowEnd->scene() != this->scene() && this->scene())
01025                                         {
01026                                                 if (curveSegments[i].arrowEnd->scene())
01027                                                         curveSegments[i].arrowEnd->scene()->removeItem(curveSegments[i].arrowEnd);
01028                                                 (static_cast<GraphicsScene*>(scene()))->addItem(curveSegments[i].arrowEnd);
01029                                         }
01030                                         curveSegments[i].arrowEnd->setZValue(z + 0.1);
01031                                 }
01032 
01033                                 NodeGraphicsItem * node = nodeAt(i);
01034                                 if (curveSegments[i].size() > 0 && 
01035                                         curveSegments[i][0] &&
01036                                         node && node->scene() == scene())
01037                                 {
01038                                         curveSegments[i][0]->setZValue(z + 0.02);
01039                                         pos = curveSegments[i][0]->scenePos();
01040                                         path.moveTo(pos);
01041                                         for (int j=0; j+3 < curveSegments[i].size(); j+=3)
01042                                                 if (curveSegments[i][j] && curveSegments[i][j+1] && curveSegments[i][j+2] && curveSegments[i][j+3])
01043                                                 {
01044                                                         curveSegments[i][j+1]->setZValue(z + 0.02);
01045                                                         curveSegments[i][j+2]->setZValue(z + 0.02);
01046                                                         curveSegments[i][j+3]->setZValue(z + 0.02);
01047                                                         pos = curveSegments[i][j+3]->scenePos();
01048                                                         path.lineTo(pos);
01049                                                 }
01050                                 }
01051                         }
01052                 }
01053                 else
01054                 {
01055                         QPointF pos1,pos2,pos3;
01056                         for (int i=0; i < curveSegments.size(); ++i)
01057                         {
01058                                 if (curveSegments[i].arrowStart)
01059                                 {
01060                                         if (curveSegments[i].arrowStart->scene() != this->scene() && this->scene())
01061                                         {
01062                                                 if (curveSegments[i].arrowStart->scene())
01063                                                         curveSegments[i].arrowStart->scene()->removeItem(curveSegments[i].arrowStart);
01064                                                 (static_cast<GraphicsScene*>(scene()))->addItem(curveSegments[i].arrowStart);
01065                                         }
01066                                         curveSegments[i].arrowStart->setZValue(z + 0.1);
01067                                 }
01068                                 if (curveSegments[i].arrowEnd)
01069                                 {
01070                                         if (curveSegments[i].arrowEnd->scene() != this->scene() && this->scene())
01071                                         {
01072                                                 if (curveSegments[i].arrowEnd->scene())
01073                                                         curveSegments[i].arrowEnd->scene()->removeItem(curveSegments[i].arrowEnd);
01074                                                 (static_cast<GraphicsScene*>(scene()))->addItem(curveSegments[i].arrowEnd);
01075                                         }
01076                                         curveSegments[i].arrowEnd->setZValue(z + 0.1);
01077                                 }
01078                                 
01079                                 NodeGraphicsItem * node = nodeAt(i);
01080                                 if (curveSegments[i].size() > 0 && curveSegments[i][0] &&
01081                                         node && node->scene() == scene())
01082                                 {
01083                                         curveSegments[i][0]->setZValue(z + 0.02);
01084 
01085                                         pos1 =  curveSegments[i][0]->scenePos();
01086                                         curveSegments[i][0]->setZValue(z + 0.02);
01087                                         path.moveTo(pos1);
01088                                         for (int j=0; j+3 < curveSegments[i].size(); j+=3)
01089                                                 if (curveSegments[i][j+1] && curveSegments[i][j+2] && curveSegments[i][j+3])
01090                                                 {
01091                                                         curveSegments[i][j+1]->setZValue(z + 0.02);
01092                                                         curveSegments[i][j+2]->setZValue(z + 0.02);
01093                                                         curveSegments[i][j+3]->setZValue(z + 0.02);
01094 
01095                                                         pos1 =  curveSegments[i][j+1]->scenePos();
01096                                                         pos2 =  curveSegments[i][j+2]->scenePos();
01097                                                         pos3 =  curveSegments[i][j+3]->scenePos();
01098 
01099                                                         path.cubicTo(pos1,pos2,pos3);
01100                                                 }
01101                                 }
01102                         }
01103                 }
01104 
01105                 QPainterPathStroker stroker;
01106                 stroker.setJoinStyle(Qt::RoundJoin);
01107                 stroker.setCapStyle(Qt::RoundCap);
01108                 //stroker.setDashPattern(pen().style());
01109                 stroker.setWidth(0.0);
01110                 this->pathShape = stroker.createStroke(path);
01111 
01112                 if (pen().style() == Qt::SolidLine)
01113                         setPath(this->pathShape);
01114                 else
01115                         setPath(path);
01116 
01117                 pathBoundingRect = this->pathShape.controlPointRect().adjusted(-10,-10,10,10);
01118                 refreshBoundaryPath();
01119                 update();
01120                 
01121                 //text items
01122                 if (itemHandle && !textItems.isEmpty())
01123                 {
01124                         QPointF center = centerLocation();
01125                         for (int i=0; i < textItems.size(); ++i)
01126                         {
01127                                 textItems[i]->setPos( center + textItems[i]->relativePosition.second );
01128                         }
01129                 }
01130         }
01131 
01133         void ConnectionGraphicsItem::refreshBoundaryPath()
01134         {
01135                 //boundaryPathItem->setVisible(true);
01136                 QPainterPath boundary;
01137                 for (int i=0; i < curveSegments.size(); ++i)
01138                 {
01139                         for (int j=0; j < curveSegments[i].size(); ++j)
01140                         {
01141                                 if (curveSegments[i][j])
01142                                         if (j == 0)
01143                                                 boundary.moveTo(curveSegments[i][j]->scenePos());
01144                                         else
01145                                                 boundary.lineTo(curveSegments[i][j]->scenePos());
01146                         }
01147                 }
01148                 
01149                 if (boundaryPathItem && mainPathItem && outerPathItem)
01150                 {
01151                         boundaryPathItem->setPath(boundary);
01152                         boundaryPathItem->update();
01153                         outerPathItem->setZValue(0.1);
01154                         boundaryPathItem->setZValue(0.5);
01155                         mainPathItem->setZValue(1.0);
01156                 }
01157         }
01158 
01162         void ConnectionGraphicsItem::clear(bool all)
01163         {
01164                 QList<ConnectionGraphicsItem::ControlPoint*> visited;
01165                 for (int i=0; i < curveSegments.size(); ++i)
01166                         for (int j=0; j < curveSegments[i].size(); ++j)
01167                                 if (curveSegments[i][j] && !visited.contains(curveSegments[i][j]))
01168                                 {
01169                                         visited += curveSegments[i][j];
01170 
01171                                         curveSegments[i][j]->setParentItem(0);
01172 
01173                                         if (curveSegments[i][j]->scene())
01174                                         {
01175                                                 curveSegments[i][j]->scene()->removeItem(curveSegments[i][j]);
01176                                         }
01177 
01178                                         curveSegments[i][j]->connectionItem = 0;
01179                                         
01180                                         delete curveSegments[i][j];
01181                                         curveSegments[i][j] = 0;
01182 
01183                                         if (all)
01184                                         {
01185                                                 if (curveSegments[i].arrowStart && 
01186                                                         !MainWindow::invalidPointers.contains( (void*)curveSegments[i].arrowStart) )
01187                                                 {
01188                                                         if (curveSegments[i].arrowStart->scene())
01189                                                                 curveSegments[i].arrowStart->scene()->removeItem(curveSegments[i].arrowStart);
01190                                                         MainWindow::invalidPointers[ curveSegments[i].arrowStart ] = true;
01191                                                         delete curveSegments[i].arrowStart;
01192                                                 }
01193                                                         
01194                                                 if (curveSegments[i].arrowEnd &&
01195                                                         !MainWindow::invalidPointers.contains( (void*)curveSegments[i].arrowEnd) )
01196                                                 {
01197                                                         if (curveSegments[i].arrowEnd->scene())
01198                                                                 curveSegments[i].arrowEnd->scene()->removeItem(curveSegments[i].arrowEnd);
01199                                                         MainWindow::invalidPointers[ (void*)curveSegments[i].arrowEnd ] = true;
01200                                                         delete curveSegments[i].arrowEnd;
01201                                                 }
01202 
01203                                                 curveSegments[i].arrowStart = 0;
01204                                                 curveSegments[i].arrowEnd = 0;
01205                                         }
01206                                 }
01207                 curveSegments.clear();
01208 
01209                 if (centerRegionItem && all && !MainWindow::invalidPointers.contains(centerRegionItem))
01210                 {
01211                         centerRegionItem->setParentItem(0);
01212                         centerRegionItem->connectionItem = 0;
01213 
01214                         if (centerRegionItem->scene())
01215                                 centerRegionItem->scene()->removeItem(centerRegionItem);
01216                         
01217                         MainWindow::invalidPointers[ (void*)centerRegionItem ] = true;
01218                         delete centerRegionItem;                        
01219                         centerRegionItem = 0;
01220                 }
01221         }
01222 
01224         qreal ConnectionGraphicsItem::slopeAtPoint(const QPointF& point)
01225         {
01226                 if (!mainPathItem) return 0.0;
01227 
01228                 qreal percent = 1, dpercent = 1;
01229                 QPainterPath path = mainPathItem->path();
01230                 QPointF p1 = path.pointAtPercent(0), p2;
01231 
01232                 while (percent < 100)
01233                 {
01234                         p2 = path.pointAtPercent(percent);
01235                         if ( ((point.x() - p1.x())*(point.x() - p1.x()) + (point.y() - p1.y())*(point.y() - p1.y())) <
01236                                 ((point.x() - p2.x())*(point.x() - p2.x()) + (point.y() - p2.y())*(point.y() - p2.y())) )
01237 
01238                                 break;
01239 
01240                         percent += dpercent;
01241                 }
01242                 return path.slopeAtPercent(percent);
01243         }
01244 
01248         void ConnectionGraphicsItem::setControlPointsVisible(bool visible)
01249         {
01250                 controlPointsVisible = visible;
01251                 if (boundaryPathItem && lineType == bezier)
01252                         boundaryPathItem->setVisible(visible);
01253                 else
01254                         boundaryPathItem->setVisible(false);
01255 
01256                 for (int i=0; i < curveSegments.size(); ++i)
01257                         for (int j=0; j < curveSegments[i].size(); ++j)
01258                         {
01259                                 if (curveSegments[i][j])
01260                                 {
01261                                         curveSegments[i][j]->connectionItem = this;
01262                                         if (lineType == bezier || (j%3)==0)
01263                                         {
01264                                                 curveSegments[i][j]->setVisible(visible);
01265                                                 if (visible && scene() != curveSegments[i][j]->scene())
01266                                                 {
01267                                                         if (curveSegments[i][j]->scene())
01268                                                         {
01269                                                                 curveSegments[i][j]->setParentItem(0);
01270                                                                 curveSegments[i][j]->scene()->removeItem(curveSegments[i][j]);
01271                                                         }
01272                                                         if (scene())
01273                                                                 (static_cast<GraphicsScene*>(scene()))->addItem(curveSegments[i][j]);
01274                                                 }
01275                                         }
01276                                         else
01277                                         {
01278                                                 curveSegments[i][j]->setVisible(false);
01279                                         }
01280                                 }
01281                         }
01282                 refresh();
01283         }
01284 
01285         void ConnectionGraphicsItem::showControlPoints()
01286         {
01287                 setControlPointsVisible(true);
01288         }
01289 
01290         void ConnectionGraphicsItem::hideControlPoints()
01291         {
01292                 setControlPointsVisible(false);
01293         }
01294 
01296         QRectF ConnectionGraphicsItem::boundingRect() const
01297         {
01298                 //return pathShape.controlPointRect();
01299                 return pathBoundingRect;
01300         }
01302         QRectF ConnectionGraphicsItem::sceneBoundingRect() const
01303         {
01304                 //return pathShape.controlPointRect();
01305                 return pathBoundingRect;
01306         }
01308         QList<ConnectionGraphicsItem::ControlPoint*> ConnectionGraphicsItem::controlPoints(bool includeEnds) const
01309         {
01310                 QList<ControlPoint*> list;
01311                 for (int i=0; i < curveSegments.size(); ++i)
01312                         for (int j=0; j < curveSegments[i].size(); ++j)
01313                         {
01314                                 if (curveSegments[i][j] && !list.contains(curveSegments[i][j]) &&
01315                                         (curveSegments[i][j]->parentItem() == 0 || includeEnds)
01316                                         )
01317                                         list.append(curveSegments[i][j]);
01318                         }
01319                         return list;
01320         }
01322         QList<QGraphicsItem*> ConnectionGraphicsItem::controlPointsAsGraphicsItems(bool includeEnds) const
01323         {
01324                 QList<QGraphicsItem*> list;
01325                 for (int i=0; i < curveSegments.size(); ++i)
01326                         for (int j=0; j < curveSegments[i].size(); ++j)
01327                         {
01328                                 if (curveSegments[i][j] && !list.contains(curveSegments[i][j]) &&
01329                                         (curveSegments[i][j]->parentItem() == 0 || includeEnds)
01330                                         )
01331                                         list.append(curveSegments[i][j]);
01332                         }
01333                         return list;
01334         }
01335 
01337         ConnectionGraphicsItem * ConnectionGraphicsItem::topLevelConnectionItem(QGraphicsItem* item,bool includeControlPoints)
01338         {
01339                 ConnectionGraphicsItem * idptr = 0, * idptr2 = 0;
01340                 ConnectionGraphicsItem::ControlPoint * cp = 0;
01341 
01342                 QGraphicsItem * p = item;
01343 
01344                 while (p)
01345                 {
01346                         idptr = qgraphicsitem_cast<ConnectionGraphicsItem*>(p);
01347                         if (!idptr && includeControlPoints)
01348                         {
01349                                 cp = qgraphicsitem_cast<ConnectionGraphicsItem::ControlPoint*>(p);
01350                                 if (cp && cp->connectionItem)
01351                                         idptr = cp->connectionItem;
01352                         }
01353 
01354                         if (idptr != 0) idptr2 = idptr;
01355 
01356                         if (p != p->parentItem())
01357                                 p = p->parentItem();
01358                         else
01359                                 break;
01360                 }
01361 
01362                 return idptr2;
01363         }
01364         
01365         bool ConnectionGraphicsItem::isModifier() const
01366         {
01367                 NodeGraphicsItem* node;
01368                 ArrowHeadItem * arrow;
01369                 
01370                 for (int i=0; i < curveSegments.size(); ++i)
01371                         if (curveSegments[i].size() > 0 && curveSegments[i][0])
01372                         {
01373                                 node = NodeGraphicsItem::cast(curveSegments[i][0]->parentItem());
01374                                 if (node && (arrow = ArrowHeadItem::cast(node)))
01375                                 {
01376                                         if (arrow->connectionItem && arrow->connectionItem->centerRegionItem == arrow)
01377                                                 return true;
01378                                 }
01379                                 if (curveSegments[i].size() > 1 && curveSegments[i][curveSegments[i].size()-1])
01380                                 {
01381                                         node = NodeGraphicsItem::cast(curveSegments[i][curveSegments[i].size()-1]->parentItem());
01382                                         if (node && (arrow = ArrowHeadItem::cast(node)))
01383                                         {
01384                                                 if (arrow->connectionItem && arrow->connectionItem->centerRegionItem == arrow)
01385                                                         return true;
01386                                         }
01387                                 }
01388                         }
01389                 return false;
01390         }
01391 
01394         QList<NodeGraphicsItem*> ConnectionGraphicsItem::nodes() const
01395         {
01396                 QList<NodeGraphicsItem*> nodes;
01397                 NodeGraphicsItem* node;
01398 
01399                 for (int i=0; i < curveSegments.size(); ++i)
01400                         if (curveSegments[i].size() > 0 && curveSegments[i][0])
01401                         {
01402                                 node = NodeGraphicsItem::cast(curveSegments[i][0]->parentItem());
01403                                 if (node && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01404                                         nodes += node;
01405                                 if (curveSegments[i].size() > 1 && curveSegments[i][curveSegments[i].size()-1])
01406                                 {
01407                                         node = NodeGraphicsItem::cast(curveSegments[i][curveSegments[i].size()-1]->parentItem());
01408                                         if (node && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01409                                                 nodes += node;
01410                                 }
01411                         }
01412 
01413                 return nodes;
01414         }
01415 
01416 
01419         QList<NodeGraphicsItem*> ConnectionGraphicsItem::nodesWithArrows() const
01420         {
01421                 QList<NodeGraphicsItem*> nodes;
01422                 NodeGraphicsItem* node;
01423 
01424                 for (int i=0; i < curveSegments.size(); ++i)
01425                         if (curveSegments[i].size() > 0 && curveSegments[i][0])
01426                         {
01427                                 node = NodeGraphicsItem::cast(curveSegments[i][0]->parentItem());
01428                                 if (node && curveSegments[i].arrowStart && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01429                                         nodes += node;
01430                                 if (curveSegments[i].size() > 1 && curveSegments[i][curveSegments[i].size()-1])
01431                                 {
01432                                         node = NodeGraphicsItem::cast(curveSegments[i][curveSegments[i].size()-1]->parentItem());
01433                                         if (node && curveSegments[i].arrowEnd && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01434                                                 nodes += node;
01435                                 }
01436                         }
01437 
01438                         return nodes;
01439         }
01440 
01443         QList<NodeGraphicsItem*> ConnectionGraphicsItem::nodesWithoutArrows() const
01444         {
01445                 QList<NodeGraphicsItem*> nodes;
01446                 NodeGraphicsItem* node;
01447 
01448                 for (int i=0; i < curveSegments.size(); ++i)
01449                         if (curveSegments[i].size() > 0 && curveSegments[i][0])
01450                         {
01451                                 node = NodeGraphicsItem::cast(curveSegments[i][0]->parentItem());
01452                                 if (node && !curveSegments[i].arrowStart && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01453                                         nodes += node;
01454                                 if (curveSegments[i].size() > 1 && curveSegments[i][curveSegments[i].size()-1])
01455                                 {
01456                                         node = NodeGraphicsItem::cast(curveSegments[i][curveSegments[i].size()-1]->parentItem());
01457                                         if (node && !curveSegments[i].arrowEnd && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01458                                                 nodes += node;
01459                                 }
01460                         }
01461 
01462                         return nodes;
01463         }
01464 
01467         QList<NodeGraphicsItem*> ConnectionGraphicsItem::nodesDisconnected() const
01468         {
01469                 QList<NodeGraphicsItem*> nodes;
01470                 NodeGraphicsItem* node;
01471 
01472                 ControlPoint * center = centerPoint();
01473 
01474                 for (int i=0; i < curveSegments.size(); ++i)
01475                         if (curveSegments[i].size() > 1 && curveSegments[i][0] && !curveSegments[i].contains(center))
01476                         {
01477                                 node = NodeGraphicsItem::cast(curveSegments[i][0]->parentItem());
01478                                 if (node)
01479                                         nodes += node;
01480                         }
01481 
01482                         return nodes;
01483         }
01484 
01487         QList<QGraphicsItem*> ConnectionGraphicsItem::nodesAsGraphicsItems() const
01488         {
01489                 QList<QGraphicsItem*> nodes;
01490                 NodeGraphicsItem* node;
01491 
01492                 for (int i=0; i < curveSegments.size(); ++i)
01493                         if (curveSegments[i].size() > 0 && curveSegments[i][0])
01494                         {
01495                                 node = NodeGraphicsItem::cast(curveSegments[i][0]->parentItem());
01496                                 if (node && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01497                                         nodes += node;
01498                                 if (curveSegments[i].size() > 1)
01499                                 {
01500                                         node = NodeGraphicsItem::cast(curveSegments[i][curveSegments[i].size()-1]->parentItem());
01501                                         if (node && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01502                                                 nodes += node;
01503                                 }
01504                         }
01505 
01506                         return nodes;
01507         }
01508 
01511         QList<ArrowHeadItem*> ConnectionGraphicsItem::arrowHeads() const
01512         {
01513                 QList<ArrowHeadItem*> arrows;
01514                 NodeGraphicsItem* node;
01515 
01516                 for (int i=0; i < curveSegments.size(); ++i)
01517                         if (curveSegments[i].size() > 0 && curveSegments[i][0])
01518                         {
01519                                 node = NodeGraphicsItem::cast(curveSegments[i][0]->parentItem());
01520                                 if (node && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01521                                         arrows += curveSegments[i].arrowStart;
01522                                 if (curveSegments[i].size() > 1)
01523                                 {
01524                                         node = NodeGraphicsItem::cast(curveSegments[i][curveSegments[i].size()-1]->parentItem());
01525                                         if (node && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01526                                                 arrows += curveSegments[i].arrowEnd;
01527                                 }
01528                         }
01529 
01530                         return arrows;
01531         }
01532 
01535         QList<QGraphicsItem*> ConnectionGraphicsItem::arrowHeadsAsGraphicsItems() const
01536         {
01537                 QList<QGraphicsItem*> arrows;
01538                 NodeGraphicsItem* node;
01539 
01540                 for (int i=0; i < curveSegments.size(); ++i)
01541                         if (curveSegments[i].size() > 0 && curveSegments[i][0])
01542                         {
01543                                 node = NodeGraphicsItem::cast(curveSegments[i][0]->parentItem());
01544                                 if (node && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01545                                         arrows += curveSegments[i].arrowStart;
01546                                 if (curveSegments[i].size() > 1)
01547                                 {
01548                                         node = NodeGraphicsItem::cast(curveSegments[i][curveSegments[i].size()-1]->parentItem());
01549                                         if (node && node != curveSegments[i].arrowStart && node != curveSegments[i].arrowEnd)
01550                                                 arrows += curveSegments[i].arrowEnd;
01551                                 }
01552                         }
01553 
01554                         return arrows;
01555         }
01556 
01559         QList<ArrowHeadItem*> ConnectionGraphicsItem::modifierArrowHeads() const
01560         {
01561                 QList<ArrowHeadItem*> arrows;
01562                 NodeGraphicsItem* node;
01563 
01564                 for (int i=0; i < curveSegments.size(); ++i)
01565                         if (curveSegments[i].size() > 0 && curveSegments[i][0])
01566                         {
01567                                 node = NodeGraphicsItem::cast(curveSegments[i][0]->parentItem());
01568                                 if (node && node == curveSegments[i].arrowStart)
01569                                         arrows += curveSegments[i].arrowStart;
01570                                 if (curveSegments[i].size() > 1)
01571                                 {
01572                                         node = NodeGraphicsItem::cast(curveSegments[i][curveSegments[i].size()-1]->parentItem());
01573                                         if (node && node == curveSegments[i].arrowEnd)
01574                                                 arrows += curveSegments[i].arrowEnd;
01575                                 }
01576                         }
01577 
01578                         return arrows;
01579         }
01580 
01584         NodeGraphicsItem* ConnectionGraphicsItem::nodeAt(int index) const
01585         {
01586                 NodeGraphicsItem * node = 0;
01587                 if (curveSegments.size() == 1)
01588                 {
01589                         if (index < 0 || index > 1 ||
01590                                 curveSegments[0].size() < 4 || curveSegments[0][curveSegments[0].size()-1] == 0) return 0;
01591 
01592                         if (index == 0)
01593                                 node = NodeGraphicsItem::cast(curveSegments[0][0]->parentItem());
01594                         else
01595                                 node = NodeGraphicsItem::cast(curveSegments[0][curveSegments[0].size()-1]->parentItem());
01596 
01597                         if (node == curveSegments[0].arrowStart || node == curveSegments[0].arrowEnd)
01598                                 node = 0;
01599                         
01600                         return node;
01601                 }
01602 
01603                 if (index < 0 || index >= curveSegments.size() ||
01604                         curveSegments[index].size() < 4 ||
01605                         curveSegments[index][0] == 0)
01606                         return 0;
01607 
01608                 node = NodeGraphicsItem::cast(curveSegments[index][0]->parentItem());
01609                 if (node == curveSegments[index].arrowStart || node == curveSegments[index].arrowEnd)
01610                         node = 0;
01611 
01612                 if (node)
01613                         return node;
01614 
01615                 return 0;
01616         }
01617 
01621         int ConnectionGraphicsItem::indexOf(QGraphicsItem * target) const
01622         {
01623                 if (!target) return -1;
01624                 
01625                 if (curveSegments.size() == 1 && (curveSegments[0].size() > 1 && curveSegments[0][0]))
01626                 {
01627                         for (int i=0; i < curveSegments[0].size(); ++i)
01628                                 if (target == curveSegments[0][i])
01629                                         return 0;
01630 
01631                         if (target == curveSegments[0].arrowStart) return 0;
01632                         
01633                         if (target == curveSegments[0].arrowEnd) return 1;
01634 
01635                         if (target == curveSegments[0][0]->parentItem()) return 0;
01636                         
01637                         if (curveSegments[0][curveSegments[0].size()-1] && 
01638                                 (target == curveSegments[0][curveSegments[0].size()-1]->parentItem())) return 1;
01639                 }
01640 
01641                 for (int i=0; i < curveSegments.size(); ++i)
01642                         if (curveSegments[i].size() > 1 && curveSegments[i][0])
01643                         {
01644                                 if (target == curveSegments[i].arrowStart || 
01645                                         target == curveSegments[i].arrowEnd ||
01646                                         target == curveSegments[i][0]->parentItem()) return i;
01647                                 
01648                                 if (curveSegments[i][curveSegments[i].size()-1] &&
01649                                         target == curveSegments[i][curveSegments[i].size()-1]->parentItem()) return i;
01650                                         
01651                                 for (int j=0; j < curveSegments[i].size(); ++j)
01652                                         if (target == curveSegments[i][j])
01653                                                 return i;
01654                         }
01655 
01656                 return -1;
01657         }
01658         
01662         ArrowHeadItem* ConnectionGraphicsItem::arrowAt(int index) const
01663         {
01664                 ArrowHeadItem* arrow = 0;
01665                 NodeGraphicsItem * node;
01666                 if (curveSegments.size() == 1)
01667                 {
01668                         if (index < 0 || index > 1 ||
01669                                 curveSegments[0].size() < 4 || curveSegments[0][curveSegments[0].size()-1] == 0) return 0;
01670 
01671                         if (index == 0)
01672                         {
01673                                 node = NodeGraphicsItem::cast(curveSegments[0][0]->parentItem());
01674                                 arrow = curveSegments[0].arrowStart;
01675                         }
01676                         else
01677                         {
01678                                 node = NodeGraphicsItem::cast(curveSegments[0][curveSegments[0].size()-1]->parentItem());
01679                                 arrow = curveSegments[0].arrowEnd;
01680                         }
01681                         if (node == curveSegments[0].arrowStart || node == curveSegments[0].arrowEnd)
01682                         {
01683                                 node = 0;
01684                                 arrow = 0;
01685                         }
01686                 }
01687 
01688                 if (index < 0 || index >= curveSegments.size() ||
01689                         curveSegments[index].size() < 4 ||
01690                         curveSegments[index][0] == 0)
01691                         return 0;
01692 
01693                 node = NodeGraphicsItem::cast(curveSegments[index][0]->parentItem());
01694                 arrow = curveSegments[index].arrowStart;
01695                 if (node == curveSegments[index].arrowStart || node == curveSegments[index].arrowEnd)
01696                 {
01697                         node = 0;
01698                         arrow = 0;
01699                 }
01700 
01701                 if (arrow)
01702                         return arrow;
01703 
01704                 return 0;
01705         }
01706 
01710         ArrowHeadItem* ConnectionGraphicsItem::modifierArrowAt(int index) const
01711         {
01712                 if (index < 0 || index >= curveSegments.size())
01713                         return 0;
01714 
01715                 if (arrowAt(index) == curveSegments[index].arrowEnd) return 0;
01716 
01717                 return curveSegments[index].arrowEnd;
01718         }
01719 
01720         void ConnectionGraphicsItem::replaceNode(NodeGraphicsItem* oldNode, NodeGraphicsItem* newNode)
01721         {
01722                 if (oldNode == 0 || newNode == 0) return;
01723 
01724                 for (int i=0; i < curveSegments.size(); ++i)
01725                 {
01726                         if (curveSegments[i].size() > 0)
01727                         {
01728                                 if (curveSegments[i][0]->parentItem() == oldNode)
01729                                         curveSegments[i][0]->setParentItem(newNode);
01730                                 if (curveSegments[i][curveSegments[i].size() - 1]->parentItem() == oldNode)
01731                                         curveSegments[i][curveSegments[i].size() - 1]->setParentItem(newNode);
01732                         }
01733                 }
01734         }
01735 
01736         void ConnectionGraphicsItem::replaceNodeAt(int index, NodeGraphicsItem* nodeItem)
01737         {
01738                 if (nodeItem == 0) return;
01739 
01740                 if (curveSegments.size() == 1)
01741                 {
01742                         if (index < 0 || index > 1 ||
01743                                 curveSegments[0].size() < 4 || curveSegments[0][0] == 0) return;
01744 
01745                         if (index == 0)
01746                                 curveSegments[0][0]->setParentItem(nodeItem);
01747                         else
01748                                 curveSegments[0][curveSegments[0].size()-1]->setParentItem(nodeItem);
01749 
01750                         return;
01751                 }
01752 
01753                 if (index < 0 || index >= curveSegments.size() ||
01754                         curveSegments[index].size() < 4 ||
01755                         curveSegments[index][0] == 0) return;
01756 
01757                 curveSegments[index][0]->setParentItem(nodeItem);
01758         }
01759 
01760         void ArrowHeadItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option ,QWidget *widget)
01761         {
01762                 if (!boundaryControlPoints.isEmpty())
01763                 {
01764                         for (int i=0; i < boundaryControlPoints.size(); ++i)
01765                                 if (boundaryControlPoints[i])
01766                                 {
01767                                         boundaryControlPoints[i]->nodeItem = 0;
01768                                         boundaryControlPoints[i]->setParentItem(0);
01769                                         if (!boundaryControlPoints[i]->scene())
01770                                                 delete boundaryControlPoints[i];
01771                                 }
01772                                 boundaryControlPoints.clear();
01773                 }
01774                 if (connectionItem && connectionItem->scene() == this->scene())
01775                 {
01776                         NodeGraphicsItem::paint(painter,option,widget);
01777                 }
01778                 else
01779                 {
01780                         this->setParentItem(0);
01781                         if (this->scene())
01782                                 scene()->removeItem(this);
01783                 }
01784         }
01785 
01786         ConnectionGraphicsItem::CurveSegment::CurveSegment() : QVector<ConnectionGraphicsItem::ControlPoint*>()
01787         {
01788                 arrowStart = arrowEnd = 0;
01789         }
01790 
01791         ConnectionGraphicsItem::CurveSegment::CurveSegment(int n) : QVector<ConnectionGraphicsItem::ControlPoint*>(n)
01792         {
01793                 arrowStart = arrowEnd = 0;
01794         }
01795 
01796         ConnectionGraphicsItem::CurveSegment::CurveSegment(int n,ConnectionGraphicsItem::ControlPoint* p)
01797                 : QVector<ConnectionGraphicsItem::ControlPoint*>(n,p)
01798         {
01799                 arrowStart = arrowEnd = 0;
01800         }
01801 
01802         ConnectionGraphicsItem::CurveSegment::CurveSegment(const ConnectionGraphicsItem::CurveSegment& copy) :
01803         QVector<ConnectionGraphicsItem::ControlPoint*>(copy)
01804         {
01805                 arrowStart = copy.arrowStart;
01806                 arrowEnd = copy.arrowEnd;
01807         }
01808 
01815         QPointF pointOnEdge(const QRectF& rect0, const QPointF& p1, qreal dist, bool straight)
01816         {
01817                 QRectF rect1 = rect0;
01818 
01819                 if (dist > 0)
01820                 {
01821                         rect1.adjust(-dist,-dist,dist,dist);
01822                 }
01823 
01824                 if (straight)
01825                 {
01826                         if (p1.x() > rect0.left() && p1.x() < rect0.right())
01827                                 if (p1.y() > rect0.center().y())
01828                                         return QPointF(p1.x(),rect1.bottom());
01829                                 else
01830                                         return QPointF(p1.x(),rect1.top());
01831 
01832                         if (p1.y() > rect0.top() && p1.y() < rect0.bottom())
01833                                 if (p1.x() > rect0.center().x())
01834                                         return QPointF(rect1.right(),p1.y());
01835                                 else
01836                                         return QPointF(rect1.left(),p1.y());
01837                 }
01838 
01839                 QPointF p0 = rect1.center(), p;
01840                 qreal w1 = rect1.width() / 2.0,
01841                         h1 = rect1.height() / 2.0;
01842 
01843                 if (p1.x() < p0.x()) { w1 = -w1; }
01844                 if (p1.y() < p0.y()) { h1 = -h1; }
01845 
01846                 if (p1.x() != p0.x())
01847                 {
01848                         qreal slope = (p1.y() - p0.y())/(p1.x() - p0.x());
01849                         if (abs((int)(w1 * slope)) < abs((int)h1))
01850                         {
01851                                 p.rx() = p0.x() + w1;
01852                                 p.ry() = p0.y() + (w1*slope);
01853 
01854                         }
01855                         else
01856                         {
01857                                 p.rx() = p0.x() + (h1/slope);
01858                                 p.ry() = p0.y() + h1;
01859                         }
01860                 }
01861                 else
01862                 {
01863                         p.rx() = p0.x();
01864                         p.ry() = p0.y() + h1;
01865                 }
01866 
01867                 return p;
01868         }
01869 
01876         QPointF pointOnEdge(const NodeGraphicsItem& node, const QPointF& pt, qreal dist, bool straight)
01877         {
01878                 QRectF rect0 = node.sceneBoundingRect();
01879                 //QPointF p0 = pointOnEdge(rect0,pt,dist,straight);
01880                 QPointF p0 = pt;
01881                 QPointF p1, p;
01882                 qreal d = 0;
01883 
01884                 for (int i=0; i < node.shapes.size(); ++i)
01885                         if (node.shapes[i])
01886                         {
01887                                 QRectF rect1 = node.shapes[i]->sceneBoundingRect().adjusted(-dist,-dist,dist,dist);
01888 
01889                                 if (!straight || d == 0 ||
01890                                         (straight &&
01891                                         (       (pt.x() > rect1.left() && pt.x() < rect1.right()) ||
01892                                         (pt.y() > rect1.top() && pt.y() < rect1.bottom())) ))
01893                                 {
01894                                         p1 = pointOnEdge(rect1,pt,dist,straight);
01895                                         if (d==0 || (((p1.rx() - p0.rx())*(p1.rx() - p0.rx()) + (p1.ry() - p0.ry())*(p1.ry() - p0.ry())) < d))
01896                                         {
01897                                                 d = ((p1.rx() - p0.rx())*(p1.rx() - p0.rx()) + (p1.ry() - p0.ry())*(p1.ry() - p0.ry()));
01898                                                 p = p1;
01899                                         }
01900                                 }
01901                         }
01902 
01903                         return p;
01904         }
01905 
01906         ConnectionGraphicsItem* ConnectionGraphicsItem::cast(QGraphicsItem * q)
01907         {
01908                 //if (MainWindow::invalidPointers.contains( (void*)q )) return 0;
01909                 if (!q || ToolGraphicsItem::cast(q->topLevelItem())) return 0;
01910                 return qgraphicsitem_cast<ConnectionGraphicsItem*>(q);
01911         }
01912         
01913         QList<ConnectionGraphicsItem*> ConnectionGraphicsItem::cast(const QList<QGraphicsItem*>& list)
01914         {
01915                 QList<ConnectionGraphicsItem*> connections;
01916                 ConnectionGraphicsItem* q;
01917                 for (int i=0; i < list.size(); ++i)
01918                         if (!MainWindow::invalidPointers.contains( (void*)(list[i]) ) && 
01919                                 (q = qgraphicsitem_cast<ConnectionGraphicsItem*>(list[i])))
01920                                 connections << q;
01921                 return connections;
01922         }
01923 
01924         ConnectionGraphicsItem::ConnectionGraphicsItem(const QList<NodeGraphicsItem*>& from, const QList<NodeGraphicsItem*>& to, QGraphicsItem * parent) :
01925                 QGraphicsItemGroup (parent), itemHandle(0)
01926         {
01927                 setCacheMode(QGraphicsItem::DeviceCoordinateCache);
01928                 setFlag(QGraphicsItem::ItemIsMovable, false);
01929                 setFlag(QGraphicsItem::ItemIsSelectable, false);
01930 
01931                 className = ConnectionGraphicsItem::CLASSNAME;
01932                 lineType = line;
01933                 
01934                 arrowHeadDistance = 10.0;
01935                 centerRegionItem = 0;
01936                 centerRegion = QSizeF(20,20);
01937                 defaultPen = QPen(QColor(50,50,255,255),5.0,Qt::SolidLine);
01938                 defaultPen.setJoinStyle(Qt::RoundJoin);
01939                 
01940                 boundaryPathItem = new QGraphicsPathItem(this);         
01941                 boundaryPathItem->setVisible(false);
01942                 boundaryPathItem->setPen(QPen(QColor(255,150,150,150),4.0,Qt::DotLine));
01943                 boundaryPathItem->setBrush(Qt::NoBrush);
01944                 
01945                 outerPathItem = new QGraphicsPathItem(this);
01946                 outerPathItem->setVisible(true);
01947                 outerPathItem->setPen(QPen(GraphicsScene::BackgroundColor,6.0,Qt::SolidLine));
01948                 outerPathItem->setBrush(Qt::NoBrush);
01949                 
01950                 mainPathItem = new QGraphicsPathItem(this);
01951                 mainPathItem->setVisible(true);
01952                 mainPathItem->setPen(defaultPen);
01953                 mainPathItem->setBrush(Qt::NoBrush);
01954                 
01955                 addToGroup(boundaryPathItem);
01956                 addToGroup(outerPathItem);
01957                 addToGroup(mainPathItem);
01958 
01959                 NodeGraphicsReader imageReader;
01960                 /*ArrowHeadItem * node = new ArrowHeadItem;
01961                 node->connectionItem = this;
01962                 imageReader.readXml(node,DefaultMiddleItemFile);
01963                 if (node->isValid())
01964                 {
01965                         node->normalize();
01966                         node->scale(25.0/node->sceneBoundingRect().height(),25.0/node->sceneBoundingRect().height());
01967                 }*/
01968                 centerRegionItem = 0;
01969 
01970                 if (from.size() < 1 || to.size() < 1) return;
01971 
01972                 QPointF center;
01973 
01974                 for (int i=0; i < from.size(); ++i)
01975                         if (from[i])
01976                                 center += from[i]->scenePos();
01977 
01978                 for (int i=0; i < to.size(); ++i)
01979                         if (to[i])
01980                                 center += to[i]->scenePos();
01981 
01982                 center /= (from.size() + to.size());
01983                 ControlPoint * centerPoint = new ControlPoint(center,this,0);
01984 
01985                 for (int i=0; i < from.size(); ++i)
01986                         if (from[i])
01987                         {
01988                                 CurveSegment cv;
01989                                 cv      << new ControlPoint(from[i]->scenePos(),this,from[i])
01990                                         << new ControlPoint((from[i]->scenePos() + center)/2.0,this,0)
01991                                         << new ControlPoint((from[i]->scenePos() + center)/2.0,this,0)
01992                                         << centerPoint;
01993                                 curveSegments.append(cv);
01994                         }
01995 
01996                 for (int i=0; i < to.size(); ++i)
01997                         if (to[i])
01998                         {
01999                                 CurveSegment cv;
02000                                 cv << new ControlPoint(to[i]->scenePos(),this,to[i])
02001                                         << new ControlPoint((to[i]->scenePos() + center)/2.0,this,0)
02002                                         << new ControlPoint((to[i]->scenePos() + center)/2.0,this,0)
02003                                         << centerPoint;
02004                                 cv.arrowStart = new ArrowHeadItem(this);
02005                                 imageReader.readXml(cv.arrowStart,DefaultArrowHeadFile);
02006                                 if (cv.arrowStart->isValid())
02007                                 {
02008                                         cv.arrowStart->normalize();
02009                                         cv.arrowStart->scale(25.0/cv.arrowStart->sceneBoundingRect().height(),25.0/cv.arrowStart->sceneBoundingRect().height());
02010                                 }
02011                                 curveSegments.append(cv);
02012                         }
02013         }
02014 }
02015 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines