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
00201 painter->drawText(rect, Qt::AlignTop | Qt::AlignHCenter, QString("") + name);
00202 painter->drawText(rect.adjusted(0.0, lineSpacing, 0.0, 0.0), Qt::AlignTop | Qt::AlignHCenter, myText);
00203
00204
00205 painter->setPen(Qt::white);
00206 painter->setBrush(Qt::black);
00207 for (int i = 0; i < numProp; i++)
00208 {
00209 if (itemProp.isInput(i))
00210 painter->drawEllipse((int)(rect.left() + lineSpacing*0.1), (int)(rect.top() + lineSpacing*(i + 1.1)), (int)(lineSpacing*0.8), (int)(lineSpacing*0.8));
00211 if (itemProp.isOutput(i))
00212 painter->drawEllipse((int)(rect.right() - lineSpacing*0.9), (int)(rect.top() + lineSpacing*(i + 1.1)), (int)(lineSpacing*0.8), (int)(lineSpacing*0.8));
00213 }
00214
00215
00216 if (markedPoint >= 0)
00217 {
00218 if (markedValidity) painter->setBrush(Qt::green);
00219 else painter->setBrush(Qt::red);
00220
00221 if (markedPoint < numProp)
00222 painter->drawEllipse((int)(rect.left() + lineSpacing*0.1), (int)(rect.top() + lineSpacing*(markedPoint + 1.1)), (int)(lineSpacing*0.8), (int)(lineSpacing*0.8));
00223 else
00224 painter->drawEllipse((int)(rect.right() - lineSpacing*0.9), (int)(rect.top() + lineSpacing*(markedPoint - numProp + 1.1)), (int)(lineSpacing*0.8), (int)(lineSpacing*0.8));
00225 }
00226 }
00227
00228
00229 QPointF Node::scenePointPos(int point) const
00230 {
00231 QRectF rect = outlineRect();
00232
00233 if (point < 0) return this->scenePos();
00234 if (point < numProp) return mapToScene( QPointF(rect.left() + lineSpacing*0.1, rect.top() + lineSpacing*(point + 1.5)) );
00235 if (point < 2 * numProp) return mapToScene( QPointF(rect.right() - lineSpacing*0.2, rect.top() + lineSpacing*(point-numProp + 1.5)) );
00236 return this->scenePos();
00237 }
00238
00239 QPointF Node::scenePointPos(QString name, bool in) const
00240 {
00241 return scenePointPos(propPoint(name, in));
00242 }
00243
00244
00245 int Node::numProps() const
00246 {
00247 return numProp;
00248 }
00249
00250
00251 void Node::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
00252 {
00253 QRectF rect = outlineRect();
00254 QPointF click = mapFromScene(event->scenePos());
00255
00256 if (click.y() > rect.top() + lineSpacing) {
00257 window->showProperties(this);
00258 }
00259 else {
00260 QString text = QInputDialog::getText(event->widget(),
00261 tr("Edit Name"), tr("Enter new name:"),
00262 QLineEdit::Normal, name);
00263 if (!text.isEmpty()) {
00264 window->setName(this, text);
00265 }
00266 }
00267 }
00268
00269 void Node::setName(QString _name) {
00270 prepareGeometryChange();
00271 name = _name;
00272 CorrectTextChange();
00273 update();
00274 }
00275
00276
00277
00278 void Node::mousePressEvent(QGraphicsSceneMouseEvent * event)
00279 {
00280 if (!window->isSelected(this)) {
00281 window->clearSelection();
00282 setSelected(true);
00283 }
00284
00285 clickedPoint = pointAt(event->pos());
00286 if (clickedPoint < 0)
00287 {
00288
00289 QGraphicsItem::mousePressEvent(event);
00290 }
00291 else
00292 {
00293
00294 line = new QGraphicsLineItem( QLineF(event->scenePos(), event->scenePos()) );
00295 line->setZValue(1000);
00296 scene()->addItem(line);
00297 }
00298 }
00299
00300 void Node::prepareHierarchy()
00301 {
00302
00303 QGraphicsItem *ancestor = parentItem();
00304 while (ancestor) {
00305 if (dynamic_cast<Node *>(ancestor))
00306 ((Node *)ancestor)->publicPrepareGeometryChange();
00307 ancestor = ancestor->parentItem();
00308 }
00309 }
00310
00311 void Node::publicPrepareGeometryChange() {
00312 prepareGeometryChange();
00313 }
00314
00315 void Node::updateHierarchy()
00316 {
00317
00318 QGraphicsItem *ancestor = parentItem();
00319 while (ancestor) {
00320 ancestor->update();
00321 if (dynamic_cast<Node *>(ancestor))
00322 ((Node *)ancestor)->updateLinksPos();
00323 ancestor = ancestor->parentItem();
00324 }
00325 }
00326
00327 void Node::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
00328 {
00329
00330 if (clickedPoint < 0)
00331 {
00332
00333 updateHierarchy();
00334
00335 QGraphicsItem::mouseMoveEvent(event);
00336
00337
00338 updateHierarchy();
00339 }
00340 else
00341 {
00342
00343
00344 QLineF shortLine = QLineF(line->line().p1(), event->scenePos());
00345 shortLine.setLength(shortLine.length() - 0.5);
00346 line->setLine(shortLine);
00347
00348
00349 if (externalMarkedPoint >= 0)
00350 {
00351 externalMarkedItem->unmarkPoint();
00352 externalMarkedPoint = -1;
00353 }
00354
00355
00356 Node *target = dynamic_cast<Node *>(scene()->itemAt(event->scenePos()));
00357 if (target)
00358 {
00359
00360 int pointPos = target->pointAt(target->mapFromScene(event->scenePos()));
00361 if (pointPos >= 0)
00362 {
00363 externalMarkedPoint = pointPos;
00364 externalMarkedItem = target;
00365 externalMarkedItem->markPoint(externalMarkedPoint, isValidLink(this, clickedPoint, target, pointPos));
00366 }
00367 }
00368 }
00369 }
00370
00371 void Node::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
00372 {
00373
00374 if (clickedPoint < 0)
00375 {
00376 QGraphicsItem::mouseReleaseEvent(event);
00377 }
00378 else
00379 {
00380
00381 delete(line);
00382
00383
00384 if (externalMarkedPoint >= 0)
00385 {
00386 externalMarkedItem->unmarkPoint();
00387 externalMarkedPoint = -1;
00388 }
00389
00390
00391 Node *target = dynamic_cast<Node *>(scene()->itemAt(event->scenePos()));
00392 if (target)
00393 {
00394
00395 int pointPos = target->pointAt(target->mapFromScene(event->scenePos()));
00396
00397
00398 if ( (pointPos >= 0) && isValidLink(this, clickedPoint, target, pointPos) )
00399 {
00400 if (clickedPoint >= numProp)
00401 validLinkRelease(this, clickedPoint, target, pointPos);
00402 else
00403 validLinkRelease(target, pointPos, this, clickedPoint);
00404 }
00405 }
00406
00407 clickedPoint = -1;
00408 }
00409 }
00410
00411 void Node::validLinkRelease(Node *fromNode, int fromPoint, Node *toNode, int toPoint)
00412 {
00413 window->createLink(fromNode, fromPoint, toNode, toPoint);
00414 }
00415
00416 void Node::markPoint(int point, bool validity)
00417 {
00418 markedPoint = point;
00419 markedValidity = validity;
00420 update();
00421 }
00422
00423 void Node::unmarkPoint()
00424 {
00425 markedPoint = -1;
00426 update();
00427 }
00428
00429
00431 bool Node::isValidLink(Node *fromNode, int fromPoint, Node *toNode, int toPoint) const
00432 {
00433 int fromNumProp = fromNode->numProp;
00434 int toNumProp = toNode->numProp;
00435
00436 if (fromNode == toNode) return false;
00437 if (fromNode->parentItem() != toNode->parentItem()) return false;
00438 if ( (fromPoint < 0) || (toPoint < 0) ) return false;
00439 if ( (fromPoint < fromNumProp) && (toPoint < toNumProp) ) return false;
00440 if ( (fromPoint >= fromNumProp) && (toPoint >= toNumProp) ) return false;
00441 if ( (fromPoint >= 2 * fromNumProp) || (toPoint >= 2 * toNumProp) ) return false;
00442 return true;
00443 }
00444
00445 int Node::insertPos() const
00446 {
00447 return numProp;
00448 }
00449
00450 int Node::insertProperty(QString name, int type, bool input, bool output)
00451 {
00452 int pos = insertPos();
00453 insertProperty(pos, name, type, input, output);
00454 return pos;
00455 }
00456
00457 void Node::insertProperty(int pos, QString name, int type, bool input, bool output)
00458 {
00459 prepareGeometryChange();
00460 itemProp.insertProperty(pos, name, type, input, output);
00461 numProp = itemProp.getProperties().size();
00462
00463 CorrectTextChange();
00464 update();
00465 }
00466
00467 void Node::removeProperty(QString name)
00468 {
00469 prepareGeometryChange();
00470 itemProp.deleteProperty(name);
00471 numProp = itemProp.getProperties().size();
00472
00473 CorrectTextChange();
00474 update();
00475 }
00476
00477 void Node::deleteProperty(int pos)
00478 {
00479 prepareGeometryChange();
00480 itemProp.deleteProperty(pos);
00481 numProp = itemProp.getProperties().size();
00482
00483 CorrectTextChange();
00484 update();
00485 }
00486
00487 void Node::CorrectTextChange()
00488 {
00489
00490 QFontMetricsF metrics = qApp->font();
00491 lineSpacing = metrics.lineSpacing();
00492 outlinerect = metrics.boundingRect(QString("") + QString("(%1) ").arg(getId()) + name);
00493
00494 const QList<QString> props = itemProp.getProperties();
00495 for (int i = 0; i < props.size(); i++)
00496 outlinerect |= metrics.boundingRect(props[i]);
00497
00498 outlinerect.adjust(0.0, 0.0, lineSpacing*4, props.size()*metrics.lineSpacing() );
00499
00500
00501
00502 QString propsText("");
00503 for (int i = 0; i < props.size(); i++) {
00504 if (i > 0) propsText += QString("\n");
00505 propsText += props[i];
00506 }
00507
00508 setText(propsText);
00509 updateLinksPos();
00510 }
00511
00512 void Node::delLastProp()
00513 {
00514 prepareGeometryChange();
00515 deleteProperty(numProp - 2);
00516 update();
00517 }
00518
00519 QVariant Node::itemChange(GraphicsItemChange change,
00520 const QVariant &value)
00521 {
00522 if (change == ItemPositionHasChanged)
00523 updateLinksPos();
00524
00525 return QGraphicsItem::itemChange(change, value);
00526 }
00527
00528 void Node::updateLinksPos()
00529 {
00530 foreach (Link *link, getLinks())
00531 link->trackNodes();
00532 }
00533
00534 QRectF Node::outlineRect() const
00535 {
00536 return outlinerect;
00537 }
00538
00539 int Node::roundness(double size) const
00540 {
00541 const int Diameter = 12;
00542 return 100 * Diameter / int(size);
00543 }
00544
00545
00546
00547
00548 int Node::pointAt(QPointF pos) const
00549 {
00550 QRectF rect = outlineRect();
00551 if ((pos.x() >= rect.left() + lineSpacing*0.1) && (pos.x() <= rect.left() + lineSpacing*0.9))
00552 {
00553 if (pos.y() - rect.top() >= lineSpacing*1.1)
00554 {
00555 int relativePos = (int)(pos.y() - rect.top() - lineSpacing*1.1);
00556 if (relativePos % (int)lineSpacing <= lineSpacing*0.8)
00557 if (itemProp.isInput((int)(relativePos / lineSpacing))) return (int)(relativePos / lineSpacing);
00558 }
00559 }
00560 else if ((pos.x() >= rect.right() - lineSpacing*0.9) && (pos.x() <= rect.right() - lineSpacing*0.1))
00561 {
00562 if (pos.y() - rect.top() >= lineSpacing*1.1)
00563 {
00564 int relativePos = (int)(pos.y() - rect.top() - lineSpacing*1.1);
00565 if (relativePos % (int)lineSpacing <= lineSpacing*0.8)
00566 if (itemProp.isOutput((int)(relativePos / lineSpacing))) return (int)(relativePos / lineSpacing + numProp);
00567 }
00568 }
00569 return -1;
00570 }
00571
00572 QString Node::propName(int point) const
00573 {
00574 if ( (point < 0) || (point >= 2 * numProp) ) return QString();
00575
00576 if (point >= numProp) point = point - numProp;
00577 return itemProp.getProperties()[point];
00578 }
00579
00580 int Node::propPoint(QString name, bool in) const
00581 {
00582 int pos = itemProp.getProperties().indexOf(name);
00583 if (pos < 0) return pos;
00584 if (!in) return pos += numProp;
00585 return pos;
00586 }
00587
00588 int Node::propType(int point) const
00589 {
00590 if ( (point < 0) && (point >= 2 * numProp) ) return 0;
00591
00592 if (point >= numProp) point = point - numProp;
00593 return itemProp.propertyType(point);
00594 }
00595
00596 void Node::setHide(bool hide)
00597 {
00598 foreach(Link *link, getLinks())
00599 link->setVisible(!hide);
00600
00601 setVisible(!hide);
00602 }
00603