File indexing completed on 2024-04-14 05:37:01

0001 /***************************************************************************
0002  *   Copyright (C) 2003-2005 by David Saxton                               *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "fpnode.h"
0012 #include "connector.h"
0013 #include "flowconnector.h"
0014 #include "flowpart.h"
0015 #include "icndocument.h"
0016 
0017 #include <QPainter>
0018 
0019 #include <ktechlab_debug.h>
0020 
0021 FPNode::FPNode(ICNDocument *icnDocument, Node::node_type type, int dir, const QPoint &pos, QString *id)
0022     : Node(icnDocument, type, dir, pos, id)
0023 {
0024     if (icnDocument)
0025         icnDocument->registerItem(this);
0026     m_outputConnector = nullptr;
0027 }
0028 
0029 FPNode::~FPNode()
0030 {
0031 }
0032 
0033 FlowPart *FPNode::outputFlowPart() const
0034 {
0035     // for InputFlowNode this member is overridden
0036 
0037     if (!m_outputConnector)
0038         return nullptr;
0039     if (m_outputConnector->endNode() == nullptr)
0040         return nullptr;
0041 
0042     return (dynamic_cast<FPNode *>(m_outputConnector->endNode()))->outputFlowPart();
0043 }
0044 
0045 FlowPartList FPNode::inputFlowParts() const
0046 {
0047     // for InputFlowNode it's overridden
0048 
0049     FlowPartList list;
0050     FlowPart *flowPart = dynamic_cast<FlowPart *>(parentItem());
0051 
0052     if (flowPart) {
0053         list.append(flowPart);
0054         return list;
0055     }
0056 
0057     const FlowConnectorList::const_iterator end = m_inFlowConnList.end();
0058     for (FlowConnectorList::const_iterator it = m_inFlowConnList.begin(); it != end; ++it) {
0059         if (*it) {
0060             Node *startNode = (*it)->startNode();
0061             FlowPart *flowPart = startNode ? dynamic_cast<FlowPart *>(startNode->parentItem()) : nullptr;
0062             if (flowPart)
0063                 list.append(flowPart);
0064         }
0065     }
0066 
0067     return list;
0068 }
0069 
0070 inline QPolygon arrowPoints(int dir)
0071 {
0072     QPolygon pa(3);
0073     switch (dir) {
0074     case 0:
0075         pa[0] = QPoint(3, 0);
0076         pa[1] = QPoint(0, 2);
0077         pa[2] = QPoint(0, -2);
0078         break;
0079     case 180:
0080         pa[0] = QPoint(-3, 0);
0081         pa[1] = QPoint(0, 2);
0082         pa[2] = QPoint(0, -2);
0083         break;
0084     case 90:
0085         pa[0] = QPoint(2, 0);
0086         pa[1] = QPoint(-2, 0);
0087         pa[2] = QPoint(0, 3);
0088         break;
0089     case 270:
0090         pa[0] = QPoint(2, 0);
0091         pa[1] = QPoint(-2, 0);
0092         pa[2] = QPoint(0, -3);
0093         break;
0094     };
0095     return pa;
0096 }
0097 
0098 void FPNode::addOutputConnector(Connector *const connector)
0099 {
0100     // for Junction and output flownodes
0101     if (!handleNewConnector(connector))
0102         return;
0103 
0104     if (m_outputConnector)
0105         qCCritical(KTL_LOG) << "BUG: adding an output connector when we already have one";
0106 
0107     // FIXME dynamic_cast connector
0108     m_outputConnector = dynamic_cast<FlowConnector *>(connector);
0109 }
0110 
0111 void FPNode::addInputConnector(Connector *const connector)
0112 {
0113     // for Junction and Input flownodes
0114     if (!handleNewConnector(connector))
0115         return;
0116 
0117     // FIXME dynamic_cast connector
0118     m_inFlowConnList.append(dynamic_cast<FlowConnector *>(connector));
0119 }
0120 
0121 bool FPNode::handleNewConnector(Connector *connector)
0122 {
0123     if (!connector)
0124         return false;
0125 
0126     // FIXME dynamic_cast connector
0127     if (m_inFlowConnList.contains(dynamic_cast<FlowConnector *>(connector)) || (static_cast<Connector *>(m_outputConnector) == connector)) {
0128         qCWarning(KTL_LOG) << " Already have connector = " << connector;
0129         return false;
0130     }
0131 
0132     connect(this, &FPNode::removed, connector, &Connector::removeConnector);
0133     connect(connector, &Connector::removed, this, &FPNode::checkForRemoval);
0134     connect(connector, &Connector::selected, this, &FPNode::setNodeSelected);
0135 
0136     if (!isChildNode())
0137         p_icnDocument->slotRequestAssignNG();
0138 
0139     return true;
0140 }
0141 
0142 Connector *FPNode::createInputConnector(Node *startNode)
0143 {
0144     if ((!acceptInput()) || !startNode)
0145         return nullptr;
0146 
0147     // FIXME dynamic_cast used
0148     Connector *connector = new FlowConnector(dynamic_cast<FPNode *>(startNode), dynamic_cast<FPNode *>(this), p_icnDocument);
0149     addInputConnector(connector);
0150 
0151     return connector;
0152 }
0153 
0154 int FPNode::numCon(bool includeParentItem, bool includeHiddenConnectors) const
0155 {
0156     unsigned count = 0;
0157 
0158     FlowConnectorList connectors = m_inFlowConnList;
0159     if (m_outputConnector)
0160         connectors.append(m_outputConnector);
0161 
0162     FlowConnectorList::const_iterator end = connectors.end();
0163     for (FlowConnectorList::const_iterator it = connectors.begin(); it != end; ++it) {
0164         if (*it && (includeHiddenConnectors || (*it)->canvas()))
0165             count++;
0166     }
0167 
0168     if (isChildNode() && includeParentItem)
0169         count++;
0170 
0171     return count;
0172 }
0173 
0174 void FPNode::removeConnector(Connector *connector)
0175 {
0176     if (!connector)
0177         return;
0178 
0179     FlowConnectorList::iterator it;
0180 
0181     // FIXME dynamic_cast connector
0182     it = m_inFlowConnList.find(dynamic_cast<FlowConnector *>(connector));
0183     if (it != m_inFlowConnList.end()) {
0184         (*it)->removeConnectorNoArg();
0185         (*it) = nullptr;
0186     }
0187 
0188     if (static_cast<Connector *>(m_outputConnector) == connector) {
0189         connector->removeConnectorNoArg();
0190         m_outputConnector = nullptr;
0191     }
0192 }
0193 
0194 void FPNode::checkForRemoval(Connector *connector)
0195 {
0196     removeConnector(connector);
0197     setNodeSelected(false);
0198 
0199     removeNullConnectors();
0200 
0201     if (!p_parentItem) {
0202         int conCount = m_inFlowConnList.count();
0203         if (m_outputConnector)
0204             conCount++;
0205         if (conCount < 2)
0206             removeNode();
0207     }
0208     // for JunctionFlowNode this method is overridden!
0209 }
0210 
0211 void FPNode::removeNullConnectors()
0212 {
0213     m_inFlowConnList.remove(static_cast<FlowConnector *>(nullptr));
0214 }
0215 
0216 QPoint FPNode::findConnectorDivergePoint(bool *found)
0217 {
0218     bool temp;
0219     if (!found)
0220         found = &temp;
0221     *found = false;
0222 
0223     if (numCon(false, false) != 2)
0224         return QPoint(0, 0);
0225 
0226     QPointList p1;
0227     QPointList p2;
0228 
0229     int inSize = m_inFlowConnList.count();
0230 
0231     FlowConnectorList connectors = m_inFlowConnList;
0232     if (m_outputConnector)
0233         connectors.append(m_outputConnector);
0234 
0235     const FlowConnectorList::const_iterator end = connectors.end();
0236     bool gotP1 = false;
0237     bool gotP2 = false;
0238     int at = -1;
0239     for (FlowConnectorList::const_iterator it = connectors.begin(); it != end && !gotP2; ++it) {
0240         at++;
0241         if (!(*it) || !(*it)->canvas())
0242             continue;
0243 
0244         if (gotP1) {
0245             p2 = (*it)->connectorPoints(at < inSize);
0246             gotP2 = true;
0247         } else {
0248             p1 = (*it)->connectorPoints(at < inSize);
0249             gotP1 = true;
0250         }
0251     }
0252 
0253     if (!gotP1 || !gotP2)
0254         return QPoint(0, 0);
0255 
0256     unsigned maxLength = p1.size() > p2.size() ? p1.size() : p2.size();
0257 
0258     for (unsigned i = 1; i < maxLength; ++i) {
0259         if (p1[i] != p2[i]) {
0260             *found = true;
0261             return p1[i - 1];
0262         }
0263     }
0264     return QPoint(0, 0);
0265 }
0266 
0267 void FPNode::setVisible(bool yes)
0268 {
0269     if (isVisible() == yes)
0270         return;
0271 
0272     KtlQCanvasPolygon::setVisible(yes);
0273 
0274     const FlowConnectorList::iterator inputEnd = m_inFlowConnList.end();
0275     for (FlowConnectorList::iterator it = m_inFlowConnList.begin(); it != inputEnd; ++it) {
0276         Connector *connector = *it;
0277         if (connector) {
0278             if (isVisible())
0279                 connector->setVisible(true);
0280             else {
0281                 Node *node = connector->startNode();
0282                 connector->setVisible(node && node->isVisible());
0283             }
0284         }
0285     }
0286 
0287     Connector *connector = m_outputConnector;
0288     if (connector) {
0289         if (isVisible())
0290             connector->setVisible(true);
0291         else {
0292             Node *node = connector->endNode();
0293             connector->setVisible(node && node->isVisible());
0294         }
0295     }
0296 }
0297 
0298 bool FPNode::isConnected(Node *node, NodeList *checkedNodes)
0299 {
0300     if (this == node)
0301         return true;
0302 
0303     bool firstNode = !checkedNodes;
0304     if (firstNode)
0305         checkedNodes = new NodeList();
0306 
0307     else if (checkedNodes->contains(this))
0308         return false;
0309 
0310     checkedNodes->append(this);
0311 
0312     const FlowConnectorList::const_iterator inputEnd = m_inFlowConnList.end();
0313     for (FlowConnectorList::const_iterator it = m_inFlowConnList.begin(); it != inputEnd; ++it) {
0314         Connector *connector = *it;
0315         if (connector) {
0316             Node *startNode = connector->startNode();
0317             if (startNode && startNode->isConnected(node, checkedNodes)) {
0318                 if (firstNode) {
0319                     delete checkedNodes;
0320                 }
0321                 return true;
0322             }
0323         }
0324     }
0325 
0326     Connector *connector = m_outputConnector;
0327     if (connector) {
0328         Node *endNode = connector->endNode();
0329         if (endNode && endNode->isConnected(node, checkedNodes)) {
0330             if (firstNode) {
0331                 delete checkedNodes;
0332             }
0333             return true;
0334         }
0335     }
0336 
0337     if (firstNode) {
0338         delete checkedNodes;
0339     }
0340 
0341     return false;
0342 }
0343 
0344 ConnectorList FPNode::inputConnectorList() const
0345 {
0346     return static_cast<ConnectorList>(static_cast<FlowConnectorList>(m_inFlowConnList));
0347 }
0348 
0349 ConnectorList FPNode::outputConnectorList() const
0350 {
0351     ConnectorList out;
0352     if (m_outputConnector)
0353         out.append(static_cast<Connector *>(m_outputConnector)); // un upcast between downcasts :o
0354     return out;
0355 }
0356 
0357 ConnectorList FPNode::getAllConnectors() const
0358 {
0359     ConnectorList all = static_cast<ConnectorList>(static_cast<FlowConnectorList>(m_inFlowConnList));
0360     if (m_outputConnector)
0361         all.append(static_cast<Connector *>(m_outputConnector));
0362     return all;
0363 }
0364 
0365 Connector *FPNode::getAConnector() const
0366 {
0367     if (!m_inFlowConnList.isEmpty())
0368         return *m_inFlowConnList.begin();
0369 
0370     if (m_outputConnector)
0371         return m_outputConnector;
0372 
0373     return nullptr;
0374 }
0375 
0376 #include "moc_fpnode.cpp"