File indexing completed on 2024-10-13 05:05:15
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"