00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <QtGui>
00022
00023 #include "node.h"
00024 #include <QGraphicsScene>
00025
00026
00027 Node::Node(QString _name, SlateWindow *wind, QGraphicsItem * parent, QGraphicsScene * scene): QGraphicsItem(parent, scene), name(), type(),
00028 itemProp("Group"), numProp(itemProp.getProperties().size()), window(wind), clickedPoint(-1), externalMarkedPoint(-1), markedPoint(-1)
00029 {
00030 myTextColor = Qt::darkGreen;
00031 myOutlineColor = Qt::darkBlue;
00032 myBackgroundColor = Qt::white;
00033 setFlags(ItemIsMovable | ItemIsSelectable);
00034
00035 type = "Group";
00036 name = _name;
00037 id = 0;
00038
00039 CorrectTextChange();
00040 update();
00041 }
00042
00043 Node::Node(ItemProperties item, QString _name, uint _id, SlateWindow *wind, QGraphicsItem * parent, QGraphicsScene * scene): QGraphicsItem(parent, scene), name(),
00044 type(), itemProp(item), numProp(itemProp.getProperties().size()), window(wind), clickedPoint(-1), externalMarkedPoint(-1), markedPoint(-1)
00045 {
00046 myTextColor = Qt::darkGreen;
00047 myOutlineColor = Qt::darkBlue;
00048 myBackgroundColor = Qt::white;
00049 setFlags(ItemIsMovable | ItemIsSelectable);
00050
00051 type = itemProp.getType();
00052 name = _name;
00053 id = _id;
00054
00055 CorrectTextChange();
00056 update();
00057 }
00058
00059 Node::~Node()
00060 {
00061 foreach (Link *link, getLinks())
00062 delete link;
00063 }
00064
00065 void Node::addInLink(Link *link)
00066 {
00067 myInLinks.append(link);
00068 }
00069
00070 void Node::addOutLink(Link *link)
00071 {
00072 myOutLinks.append(link);
00073 }
00074
00075 void Node::removeLink(Link *link)
00076 {
00077 myInLinks.removeAll(link);
00078 myOutLinks.removeAll(link);
00079 }
00080
00081 QList<Link *> Node::getLinks() const
00082 {
00083 return (myInLinks + myOutLinks);
00084 }
00085
00086 QList<Link *> Node::getInLinks() const
00087 {
00088 return myInLinks;
00089 }
00090
00091 QList<Link *> Node::getOutLinks() const
00092 {
00093 return myOutLinks;
00094 }
00095
00096 int Node::precursors(QList<Node *> tail)
00097 {
00098 if (myInLinks.isEmpty()) {
00099 return 0;
00100 }
00101 else if (tail.contains(this)) {
00102 return 0;
00103 }
00104 else {
00105 int maxPre = 0;
00106 tail.append(this);
00107 foreach(Link *link, myInLinks) {
00108 if ((link) && (link->fromNode())) {
00109 int pre = link->fromNode()->precursors(tail);
00110 if (maxPre < pre) maxPre = pre;
00111 }
00112 }
00113 return maxPre + 1;
00114 }
00115 }
00116
00117
00118
00119 void Node::setText(const QString &text)
00120 {
00121 prepareGeometryChange();
00122 myText = text;
00123 update();
00124 }
00125
00126 QString Node::text() const
00127 {
00128 return myText;
00129 }
00130
00131 void Node::setTextColor(const QColor &color)
00132 {
00133 myTextColor = color;
00134 update();
00135 }
00136
00137 QColor Node::textColor() const
00138 {
00139 return myTextColor;
00140 }
00141
00142 void Node::setOutlineColor(const QColor &color)
00143 {
00144 myOutlineColor = color;
00145 update();
00146 }
00147
00148 QColor Node::outlineColor() const
00149 {
00150 return myOutlineColor;
00151 }
00152
00153 void Node::setBackgroundColor(const QColor &color)
00154 {
00155 myBackgroundColor = color;
00156 update();
00157 }
00158
00159 QColor Node::backgroundColor() const
00160 {
00161 return myBackgroundColor;
00162 }
00163
00164 QRectF Node::boundingRect() const
00165 {
00166 const int Margin = 1;
00167 return outlineRect().adjusted(-Margin, -Margin, +Margin, +Margin);
00168 }
00169
00170 QPainterPath Node::shape() const
00171 {
00172 QRectF rect = outlineRect();
00173
00174 QPainterPath path;
00175 path.addRoundRect(rect, roundness(rect.width()),
00176 roundness(rect.height()));
00177 return path;
00178 }
00179
00180 uint Node::getId()
00181 {
00182 return id;
00183 }
00184
00185 void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * )
00186 {
00187 QPen pen(myOutlineColor);
00188 if (option->state & QStyle::State_Selected) {
00189 pen.setStyle(Qt::DotLine);
00190 pen.setWidth(2);
00191 }
00192 painter->setPen(pen);
00193 painter->setBrush(myBackgroundColor);
00194
00195 QRectF rect = outlineRect();
00196 painter->drawRect(rect);
00197 painter->drawLine((int)rect.left(), (int)(rect.top() + lineSpacing), (int)rect.right(), (int)(rect.top() + lineSpacing));
00198
00199 painter->setPen(myTextColor);
00200 painter->drawText(rect, Qt::AlignTop | Qt::AlignHCenter, QString("") + QString("(%1) ").arg(getId()) + name);
00201 painter->drawText(rect.adjusted(0.0, lineSpacing, 0.0, 0.0), Qt::AlignTop | Qt::AlignHCenter, myText);
00202
00203
00204 painter->setPen(Qt::white);
00205 painter->setBrush(Qt::black);
00206 for (int i = 0; i < numProp; i++)
00207 {
00208 if (itemProp.isInput(i))
00209 painter->drawEllipse((int)(rect.left() + lineSpacing*0.25), (int)(rect.top() + lineSpacing*(i + 1.25)), (int)(lineSpacing*0.5), (int)(lineSpacing*0.5));
00210 if (itemProp.isOutput(i))
00211 painter->drawEllipse((int)(rect.right() - lineSpacing*0.75), (int)(rect.top() + lineSpacing*(i + 1.25)), (int)(lineSpacing*0.5), (int)(lineSpacing*0.5));
00212 }
00213
00214
00215 if (markedPoint >= 0)
00216 {
00217 if (markedValidity) painter->setBrush(Qt::green);
00218 else painter->setBrush(Qt::red);
00219
00220 if (markedPoint < numProp)
00221 painter->drawEllipse((int)(rect.left() + lineSpacing*0.25), (int)(rect.top() + lineSpacing*(markedPoint + 1.25)), (int)(lineSpacing*0.5), (int)(lineSpacing*0.5));
00222 else
00223 painter->drawEllipse((int)(rect.right() - lineSpacing*0.75), (int)(rect.top() + lineSpacing*(markedPoint - numProp + 1.25)), (int)(lineSpacing*0.5), (int)(lineSpacing*0.5));
00224 }
00225 }
00226
00227
00228 QPointF Node::scenePointPos(int point) const
00229 {
00230 QRectF rect = outlineRect();
00231
00232 if (point < 0) return this->scenePos();
00233 if (point < numProp) return mapToScene( QPointF(rect.left() + lineSpacing*0.5, rect.top() + lineSpacing*(point + 1.5)) );
00234 if (point < 2 * numProp) return mapToScene( QPointF(rect.right() - lineSpacing*0.5, rect.top() + lineSpacing*(point-numProp + 1.5)) );
00235 return this->scenePos();
00236 }
00237
00238 QPointF Node::scenePointPos(QString name, bool in) const
00239 {
00240 return scenePointPos(propPoint(name, in));
00241 }
00242
00243
00244 int Node::numProps() const
00245 {
00246 return numProp;
00247 }
00248
00249
00250 void Node::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
00251 {
00252 QRectF rect = outlineRect();
00253 QPointF click = mapFromScene(event->scenePos());
00254
00255 if (click.y() > rect.top() + lineSpacing) {
00256 window->showProperties(this);
00257 }
00258 else {
00259 QString text = QInputDialog::getText(event->widget(),
00260 tr("Edit Name"), tr("Enter new name:"),
00261 QLineEdit::Normal, name);
00262 if (!text.isEmpty()) {
00263 window->setName(this, text);
00264 }
00265 }
00266 }
00267
00268 void Node::setName(QString _name) {
00269 prepareGeometryChange();
00270 name = _name;
00271 CorrectTextChange();
00272 update();
00273 }
00274
00275
00276
00277 void Node::mousePressEvent(QGraphicsSceneMouseEvent * event)
00278 {
00279 if (!window->isSelected(this)) {
00280 window->clearSelection();
00281 setSelected(true);
00282 }
00283
00284 clickedPoint = pointAt(event->pos());
00285 if (clickedPoint < 0)
00286 {
00287
00288 QGraphicsItem::mousePressEvent(event);
00289 }
00290 else
00291 {
00292
00293 line = new QGraphicsLineItem( QLineF(event->scenePos(), event->scenePos()) );
00294 line->setZValue(1000);
00295 scene()->addItem(line);
00296 }
00297 }
00298
00299 void Node::prepareHierarchy()
00300 {
00301
00302 QGraphicsItem *ancestor = parentItem();
00303 while (ancestor) {
00304 if (dynamic_cast<Node *>(ancestor))
00305 ((Node *)ancestor)->publicPrepareGeometryChange();
00306 ancestor = ancestor->parentItem();
00307 }
00308 }
00309
00310 void Node::publicPrepareGeometryChange() {
00311 prepareGeometryChange();
00312 }
00313
00314 void Node::updateHierarchy()
00315 {
00316
00317 QGraphicsItem *ancestor = parentItem();
00318 while (ancestor) {
00319 ancestor->update();
00320 if (dynamic_cast<Node *>(ancestor))
00321 ((Node *)ancestor)->updateLinksPos();
00322 ancestor = ancestor->parentItem();
00323 }
00324 }
00325
00326 void Node::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
00327 {
00328
00329 if (clickedPoint < 0)
00330 {
00331
00332 updateHierarchy();
00333
00334 QGraphicsItem::mouseMoveEvent(event);
00335
00336
00337 updateHierarchy();
00338 }
00339 else
00340 {
00341
00342
00343 QLineF shortLine = QLineF(line->line().p1(), event->scenePos());
00344 shortLine.setLength(shortLine.length() - 0.5);
00345 line->setLine(shortLine);
00346
00347
00348 if (externalMarkedPoint >= 0)
00349 {
00350 externalMarkedItem->unmarkPoint();
00351 externalMarkedPoint = -1;
00352 }
00353
00354
00355 Node *target = dynamic_cast<Node *>(scene()->itemAt(event->scenePos()));
00356 if (target)
00357 {
00358
00359 int pointPos = target->pointAt(target->mapFromScene(event->scenePos()));
00360 if (pointPos >= 0)
00361 {
00362 externalMarkedPoint = pointPos;
00363 externalMarkedItem = target;
00364 externalMarkedItem->markPoint(externalMarkedPoint, isValidLink(this, clickedPoint, target, pointPos));
00365 }
00366 }
00367 }
00368 }
00369
00370 void Node::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
00371 {
00372
00373 if (clickedPoint < 0)
00374 {
00375 QGraphicsItem::mouseReleaseEvent(event);
00376 }
00377 else
00378 {
00379
00380 delete(line);
00381
00382
00383 if (externalMarkedPoint >= 0)
00384 {
00385 externalMarkedItem->unmarkPoint();
00386 externalMarkedPoint = -1;
00387 }
00388
00389
00390 Node *target = dynamic_cast<Node *>(scene()->itemAt(event->scenePos()));
00391 if (target)
00392 {
00393
00394 int pointPos = target->pointAt(target->mapFromScene(event->scenePos()));
00395
00396
00397 if ( (pointPos >= 0) && isValidLink(this, clickedPoint, target, pointPos) )
00398 {
00399 if (clickedPoint >= numProp)
00400 validLinkRelease(this, clickedPoint, target, pointPos);
00401 else
00402 validLinkRelease(target, pointPos, this, clickedPoint);
00403 }
00404 }
00405
00406 clickedPoint = -1;
00407 }
00408 }
00409
00410 void Node::validLinkRelease(Node *fromNode, int fromPoint, Node *toNode, int toPoint)
00411 {
00412 window->createLink(fromNode, fromPoint, toNode, toPoint);
00413 }
00414
00415 void Node::markPoint(int point, bool validity)
00416 {
00417 markedPoint = point;
00418 markedValidity = validity;
00419 update();
00420 }
00421
00422 void Node::unmarkPoint()
00423 {
00424 markedPoint = -1;
00425 update();
00426 }
00427
00428
00430 bool Node::isValidLink(Node *fromNode, int fromPoint, Node *toNode, int toPoint) const
00431 {
00432 int fromNumProp = fromNode->numProp;
00433 int toNumProp = toNode->numProp;
00434
00435 if (fromNode == toNode) return false;
00436 if (fromNode->parentItem() != toNode->parentItem()) return false;
00437 if ( (fromPoint < 0) || (toPoint < 0) ) return false;
00438 if ( (fromPoint < fromNumProp) && (toPoint < toNumProp) ) return false;
00439 if ( (fromPoint >= fromNumProp) && (toPoint >= toNumProp) ) return false;
00440 if ( (fromPoint >= 2 * fromNumProp) || (toPoint >= 2 * toNumProp) ) return false;
00441 return true;
00442 }
00443
00444 int Node::insertPos() const
00445 {
00446 return numProp;
00447 }
00448
00449 int Node::insertProperty(QString name, int type, bool input, bool output)
00450 {
00451 int pos = insertPos();
00452 insertProperty(pos, name, type, input, output);
00453 return pos;
00454 }
00455
00456 void Node::insertProperty(int pos, QString name, int type, bool input, bool output)
00457 {
00458 prepareGeometryChange();
00459 itemProp.insertProperty(pos, name, type, input, output);
00460 numProp = itemProp.getProperties().size();
00461
00462 CorrectTextChange();
00463 update();
00464 }
00465
00466 void Node::removeProperty(QString name)
00467 {
00468 prepareGeometryChange();
00469 itemProp.deleteProperty(name);
00470 numProp = itemProp.getProperties().size();
00471
00472 CorrectTextChange();
00473 update();
00474 }
00475
00476 void Node::deleteProperty(int pos)
00477 {
00478 prepareGeometryChange();
00479 itemProp.deleteProperty(pos);
00480 numProp = itemProp.getProperties().size();
00481
00482 CorrectTextChange();
00483 update();
00484 }
00485
00486 void Node::CorrectTextChange()
00487 {
00488
00489 QFontMetricsF metrics = qApp->font();
00490 lineSpacing = metrics.lineSpacing();
00491 outlinerect = metrics.boundingRect(QString("") + QString("(%1) ").arg(getId()) + name);
00492
00493 const QList<QString> props = itemProp.getProperties();
00494 for (int i = 0; i < props.size(); i++)
00495 outlinerect |= metrics.boundingRect(props[i]);
00496
00497 outlinerect.adjust(0.0, 0.0, lineSpacing*4, props.size()*metrics.lineSpacing() );
00498
00499
00500
00501 QString propsText("");
00502 for (int i = 0; i < props.size(); i++) {
00503 if (i > 0) propsText += QString("\n");
00504 propsText += props[i];
00505 }
00506
00507 setText(propsText);
00508 updateLinksPos();
00509 }
00510
00511 void Node::delLastProp()
00512 {
00513 prepareGeometryChange();
00514 deleteProperty(numProp - 2);
00515 update();
00516 }
00517
00518 QVariant Node::itemChange(GraphicsItemChange change,
00519 const QVariant &value)
00520 {
00521 if (change == ItemPositionHasChanged)
00522 updateLinksPos();
00523
00524 return QGraphicsItem::itemChange(change, value);
00525 }
00526
00527 void Node::updateLinksPos()
00528 {
00529 foreach (Link *link, getLinks())
00530 link->trackNodes();
00531 }
00532
00533 QRectF Node::outlineRect() const
00534 {
00535 return outlinerect;
00536 }
00537
00538 int Node::roundness(double size) const
00539 {
00540 const int Diameter = 12;
00541 return 100 * Diameter / int(size);
00542 }
00543
00544
00545
00546
00547 int Node::pointAt(QPointF pos) const
00548 {
00549 QRectF rect = outlineRect();
00550 if ((pos.x() >= rect.left() + lineSpacing*0.25) && (pos.x() <= rect.left() + lineSpacing*0.75))
00551 {
00552 if (pos.y() - rect.top() >= lineSpacing*1.25)
00553 {
00554 int relativePos = (int)(pos.y() - rect.top() - lineSpacing*1.25);
00555 if (relativePos % (int)lineSpacing <= lineSpacing*0.5)
00556 if (itemProp.isInput((int)(relativePos / lineSpacing))) return (int)(relativePos / lineSpacing);
00557 }
00558 }
00559 else if ((pos.x() >= rect.right() - lineSpacing*0.75) && (pos.x() <= rect.right() - lineSpacing*0.25))
00560 {
00561 if (pos.y() - rect.top() >= lineSpacing*1.25)
00562 {
00563 int relativePos = (int)(pos.y() - rect.top() - lineSpacing*1.25);
00564 if (relativePos % (int)lineSpacing <= lineSpacing*0.5)
00565 if (itemProp.isOutput((int)(relativePos / lineSpacing))) return (int)(relativePos / lineSpacing + numProp);
00566 }
00567 }
00568 return -1;
00569 }
00570
00571 QString Node::propName(int point) const
00572 {
00573 if ( (point < 0) || (point >= 2 * numProp) ) return QString();
00574
00575 if (point >= numProp) point = point - numProp;
00576 return itemProp.getProperties()[point];
00577 }
00578
00579 int Node::propPoint(QString name, bool in) const
00580 {
00581 int pos = itemProp.getProperties().indexOf(name);
00582 if (pos < 0) return pos;
00583 if (!in) return pos += numProp;
00584 return pos;
00585 }
00586
00587 int Node::propType(int point) const
00588 {
00589 if ( (point < 0) && (point >= 2 * numProp) ) return 0;
00590
00591 if (point >= numProp) point = point - numProp;
00592 return itemProp.propertyType(point);
00593 }
00594
00595 void Node::setHide(bool hide)
00596 {
00597 foreach(Link *link, getLinks())
00598 link->setVisible(!hide);
00599
00600 setVisible(!hide);
00601 }
00602