File indexing completed on 2025-04-20 08:13:27
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 "ecnode.h" 0012 #include "circuitdocument.h" 0013 #include "component.h" 0014 #include "connector.h" 0015 #include "electronicconnector.h" 0016 #include "pin.h" 0017 0018 #include <QPainter> 0019 0020 #include <ktlconfig.h> 0021 #include <ktechlab_debug.h> 0022 0023 ECNode::ECNode(ICNDocument *icnDocument, Node::node_type _type, int dir, const QPoint &pos, QString *_id) 0024 : Node(icnDocument, _type, dir, pos, _id) 0025 { 0026 m_prevV = 0; 0027 m_prevI = 0; 0028 m_pinPoint = nullptr; 0029 m_bShowVoltageBars = KTLConfig::showVoltageBars(); 0030 m_bShowVoltageColor = KTLConfig::showVoltageColor(); 0031 0032 if (icnDocument) 0033 icnDocument->registerItem(this); 0034 0035 m_pins.resize(1); 0036 m_pins[0] = new Pin(this); 0037 } 0038 0039 ECNode::~ECNode() 0040 { 0041 if (m_pinPoint) { 0042 m_pinPoint->setCanvas(nullptr); 0043 delete m_pinPoint; 0044 } 0045 0046 qDeleteAll(m_pins); 0047 m_pins.resize(0); 0048 } 0049 0050 void ECNode::setNumPins(unsigned num) 0051 { 0052 unsigned oldNum = m_pins.size(); 0053 0054 if (num == oldNum) 0055 return; 0056 0057 if (num > oldNum) { 0058 m_pins.resize(num); 0059 for (unsigned i = oldNum; i < num; i++) 0060 m_pins[i] = new Pin(this); 0061 } else { 0062 for (unsigned i = num; i < oldNum; i++) 0063 delete m_pins[i]; 0064 m_pins.resize(num); 0065 } 0066 0067 emit numPinsChanged(num); 0068 } 0069 0070 Pin *ECNode::pin(unsigned num) const 0071 { 0072 return (int(num) < m_pins.size()) ? m_pins[num] : nullptr; 0073 } 0074 0075 void ECNode::setNodeChanged() 0076 { 0077 if (!canvas() || numPins() != 1) 0078 return; 0079 0080 Pin *pin = m_pins[0]; 0081 0082 double v = pin->voltage(); 0083 double i = pin->current(); 0084 0085 if (v != m_prevV || i != m_prevI) { 0086 QRect r = boundingRect(); 0087 // r.setCoords( r.left()+(r.width()/2)-1, r.top()+(r.height()/2)-1, r.right()-(r.width()/2)+1, r.bottom()-(r.height()/2)+1 ); 0088 canvas()->setChanged(r); 0089 m_prevV = v; 0090 m_prevI = i; 0091 } 0092 } 0093 0094 void ECNode::setParentItem(CNItem *parentItem) 0095 { 0096 Node::setParentItem(parentItem); 0097 0098 if (Component *component = dynamic_cast<Component *>(parentItem)) { 0099 connect(component, SIGNAL(elementDestroyed(Element *)), this, SLOT(removeElement(Element *))); 0100 // TODO fix compiler error: invalid application of ‘sizeof’ to incomplete type ‘Element’ 0101 // connect(component, &Component::elementDestroyed, this, &ECNode::removeElement); 0102 connect(component, SIGNAL(switchDestroyed(Switch *)), this, SLOT(removeSwitch(Switch *))); 0103 // TODO fix compiler error: invalid application of ‘sizeof’ to incomplete type ‘Switch’ 0104 // connect(component, &Component::switchDestroyed, this, &ECNode::removeSwitch); 0105 } 0106 } 0107 0108 void ECNode::removeElement(Element *e) 0109 { 0110 for (int i = 0; i < m_pins.size(); i++) 0111 m_pins[i]->removeElement(e); 0112 } 0113 0114 void ECNode::removeSwitch(Switch *sw) 0115 { 0116 for (int i = 0; i < m_pins.size(); i++) 0117 m_pins[i]->removeSwitch(sw); 0118 } 0119 0120 // -- functionality from node.cpp -- 0121 0122 bool ECNode::isConnected(Node *node, NodeList *checkedNodes) 0123 { 0124 if (this == node) 0125 return true; 0126 0127 bool firstNode = !checkedNodes; 0128 if (firstNode) 0129 checkedNodes = new NodeList(); 0130 0131 else if (checkedNodes->contains(this)) 0132 return false; 0133 0134 checkedNodes->append(this); 0135 0136 const ConnectorList::const_iterator inputEnd = m_connectorList.end(); 0137 for (ConnectorList::const_iterator it = m_connectorList.begin(); it != inputEnd; ++it) { 0138 Connector *connector = *it; 0139 if (connector) { 0140 Node *startNode = connector->startNode(); 0141 if (startNode && startNode->isConnected(node, checkedNodes)) { 0142 if (firstNode) { 0143 delete checkedNodes; 0144 } 0145 return true; 0146 } 0147 } 0148 } 0149 0150 if (firstNode) { 0151 delete checkedNodes; 0152 } 0153 0154 return false; 0155 } 0156 0157 void ECNode::checkForRemoval(Connector *connector) 0158 { 0159 removeConnector(connector); 0160 setNodeSelected(false); 0161 0162 removeNullConnectors(); 0163 0164 if (!p_parentItem) { 0165 int conCount = m_connectorList.count(); 0166 if (conCount < 1) 0167 removeNode(); 0168 } 0169 } 0170 0171 void ECNode::setVisible(bool yes) 0172 { 0173 if (isVisible() == yes) 0174 return; 0175 0176 KtlQCanvasPolygon::setVisible(yes); 0177 0178 const ConnectorList::iterator inputEnd = m_connectorList.end(); 0179 for (ConnectorList::iterator it = m_connectorList.begin(); it != inputEnd; ++it) { 0180 Connector *connector = *it; 0181 if (connector) { 0182 if (isVisible()) 0183 connector->setVisible(true); 0184 else { 0185 Node *node = connector->startNode(); 0186 connector->setVisible(node && node->isVisible()); 0187 } 0188 } 0189 } 0190 } 0191 0192 QPoint ECNode::findConnectorDivergePoint(bool *found) 0193 { 0194 // FIXME someone should check that this function is OK ... I just don't understand what it does 0195 bool temp; 0196 if (!found) 0197 found = &temp; 0198 *found = false; 0199 0200 if (numCon(false, false) != 2) 0201 return QPoint(0, 0); 0202 0203 QPointList p1; 0204 QPointList p2; 0205 0206 int inSize = m_connectorList.count(); 0207 0208 const ConnectorList connectors = m_connectorList; 0209 const ConnectorList::const_iterator end = connectors.end(); 0210 0211 bool gotP1 = false; 0212 bool gotP2 = false; 0213 0214 int at = -1; 0215 for (ConnectorList::const_iterator it = connectors.begin(); it != end && !gotP2; ++it) { 0216 at++; 0217 if (!(*it) || !(*it)->canvas()) 0218 continue; 0219 0220 if (gotP1) { 0221 p2 = (*it)->connectorPoints(at < inSize); 0222 gotP2 = true; 0223 } else { 0224 p1 = (*it)->connectorPoints(at < inSize); 0225 gotP1 = true; 0226 } 0227 } 0228 0229 if (!gotP1 || !gotP2) 0230 return QPoint(0, 0); 0231 0232 // If they are differing lengths, return the end of the shortest 0233 if (p1.size() < p2.size()) { 0234 *found = true; 0235 return p1.last(); 0236 } else if (p2.size() < p1.size()) { 0237 *found = true; 0238 return p2.last(); 0239 } 0240 0241 Q_ASSERT(p1.size() == p2.size()); 0242 0243 for (int i = 1; i < qMin(p1.size(), p2.size()); ++i) { 0244 if (p1[i] != p2[i]) { 0245 *found = true; 0246 return p1[i - 1]; 0247 } 0248 } 0249 return QPoint(0, 0); 0250 } 0251 0252 void ECNode::addConnector(Connector *const connector) 0253 { 0254 if (!handleNewConnector(connector)) 0255 return; 0256 0257 m_connectorList.append(connector); 0258 } 0259 0260 bool ECNode::handleNewConnector(Connector *connector) 0261 { 0262 if (!connector) 0263 return false; 0264 0265 if (m_connectorList.contains(connector)) { 0266 qCWarning(KTL_LOG) << " Already have connector = " << connector; 0267 return false; 0268 } 0269 0270 connect(this, &ECNode::removed, connector, &Connector::removeConnectorNodeArg); 0271 connect(connector, &Connector::removed, this, &ECNode::checkForRemoval); 0272 connect(connector, &Connector::selected, this, &ECNode::setNodeSelected); 0273 0274 if (!isChildNode()) 0275 p_icnDocument->slotRequestAssignNG(); 0276 0277 return true; 0278 } 0279 0280 Connector *ECNode::createConnector(Node *node) 0281 { 0282 // FIXME dynamic_cast used 0283 Connector *connector = new ElectronicConnector(dynamic_cast<ECNode *>(node), dynamic_cast<ECNode *>(this), p_icnDocument); 0284 addConnector(connector); 0285 0286 return connector; 0287 } 0288 0289 void ECNode::removeNullConnectors() 0290 { 0291 m_connectorList.removeAll(static_cast<Connector *>(nullptr)); 0292 } 0293 0294 int ECNode::numCon(bool includeParentItem, bool includeHiddenConnectors) const 0295 { 0296 unsigned count = 0; 0297 0298 const ConnectorList connectors = m_connectorList; 0299 0300 ConnectorList::const_iterator end = connectors.end(); 0301 for (ConnectorList::const_iterator it = connectors.begin(); it != end; ++it) { 0302 if (*it && (includeHiddenConnectors || (*it)->canvas())) 0303 count++; 0304 } 0305 0306 if (isChildNode() && includeParentItem) 0307 count++; 0308 0309 return count; 0310 } 0311 0312 void ECNode::removeConnector(Connector *connector) 0313 { 0314 if (!connector) 0315 return; 0316 0317 ConnectorList::iterator it; 0318 0319 // it = m_connectorList.find(connector); // 2018.12.02 0320 int i = m_connectorList.indexOf(connector); 0321 it = (i == -1 ? m_connectorList.end() : (m_connectorList.begin() + i)); 0322 if (it != m_connectorList.end()) { 0323 (*it)->removeConnectorNoArg(); 0324 (*it) = nullptr; 0325 } 0326 } 0327 0328 Connector *ECNode::getAConnector() const 0329 { 0330 if (!m_connectorList.isEmpty()) 0331 return *m_connectorList.begin(); 0332 else 0333 return nullptr; 0334 } 0335 0336 #include "moc_ecnode.cpp"