File indexing completed on 2024-12-08 05:08:34
0001 /*************************************************************************** 0002 * Copyright (C) 2003-2004 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 "cnitemgroup.h" 0012 #include "component.h" 0013 #include "connector.h" 0014 #include "flowpart.h" 0015 #include "icndocument.h" 0016 #include "node.h" 0017 #include "nodegroup.h" 0018 0019 CNItemGroup::CNItemGroup(ICNDocument *icnDocument) 0020 : ItemGroup(icnDocument) 0021 { 0022 p_icnDocument = icnDocument; 0023 m_connectorCount = 0; 0024 m_nodeCount = 0; 0025 m_currentLevel = -1; 0026 } 0027 0028 CNItemGroup::~CNItemGroup() 0029 { 0030 } 0031 0032 bool CNItemGroup::addItem(Item *item) 0033 { 0034 // Note, we must prepend the item to the list so that 0035 // activeCNItem() can return the item at the start 0036 // of the list as the most recently added item if some 0037 // the previous activeCNItem is removed 0038 0039 if (!item || !item->canvas() || m_itemList.contains(item) || !item->isMovable()) 0040 return false; 0041 0042 if (m_currentLevel != -1 && item->level() > m_currentLevel) 0043 return false; 0044 0045 if (item && m_currentLevel > item->level()) 0046 removeAllItems(); 0047 0048 registerItem(item); 0049 m_currentLevel = item->level(); 0050 setActiveItem(item); 0051 item->setSelected(true); 0052 updateInfo(); 0053 emit itemAdded(item); 0054 return true; 0055 } 0056 0057 bool CNItemGroup::addNode(Node *node) 0058 { 0059 if (!node || m_nodeList.contains(node) || node->isChildNode()) 0060 return false; 0061 m_nodeList.prepend(node); 0062 node->setSelected(true); 0063 updateInfo(); 0064 emit nodeAdded(node); 0065 return true; 0066 } 0067 0068 bool CNItemGroup::addConnector(Connector *con) 0069 { 0070 if (!con || m_connectorList.contains(con)) 0071 return false; 0072 m_connectorList.prepend(con); 0073 con->setSelected(true); 0074 updateInfo(); 0075 emit connectorAdded(con); 0076 return true; 0077 } 0078 0079 bool CNItemGroup::addQCanvasItem(KtlQCanvasItem *qcanvasItem) 0080 { 0081 if (!qcanvasItem) 0082 return false; 0083 0084 Item *item = dynamic_cast<Item *>(qcanvasItem); 0085 if (item) 0086 return addItem(item); 0087 0088 Node *node = dynamic_cast<Node *>(qcanvasItem); 0089 if (node) 0090 return addNode(node); 0091 0092 Connector *connector = dynamic_cast<Connector *>(qcanvasItem); 0093 if (!connector) { 0094 ConnectorLine *connectorLine = dynamic_cast<ConnectorLine *>(qcanvasItem); 0095 if (connectorLine) 0096 connector = connectorLine->parent(); 0097 } 0098 if (connector) 0099 return addConnector(connector); 0100 0101 return false; 0102 } 0103 0104 void CNItemGroup::setItems(KtlQCanvasItemList list) 0105 { 0106 ItemList itemRemoveList = m_itemList; 0107 ConnectorList connectorRemoveList = m_connectorList; 0108 NodeList nodeRemoveList = m_nodeList; 0109 0110 const KtlQCanvasItemList::const_iterator end = list.end(); 0111 for (KtlQCanvasItemList::const_iterator it = list.begin(); it != end; ++it) { 0112 if (Item *item = dynamic_cast<Item *>(*it)) 0113 itemRemoveList.removeAll(item); 0114 0115 else if (Node *node = dynamic_cast<Node *>(*it)) 0116 nodeRemoveList.removeAll(node); 0117 0118 else if (Connector *con = dynamic_cast<Connector *>(*it)) 0119 connectorRemoveList.removeAll(con); 0120 0121 else if (ConnectorLine *conLine = dynamic_cast<ConnectorLine *>(*it)) 0122 connectorRemoveList.removeAll(conLine->parent()); 0123 } 0124 0125 { 0126 const ItemList::const_iterator end = itemRemoveList.end(); 0127 for (ItemList::const_iterator it = itemRemoveList.begin(); it != end; ++it) { 0128 removeItem(*it); 0129 (*it)->setSelected(false); 0130 } 0131 } 0132 0133 { 0134 const NodeList::const_iterator end = nodeRemoveList.end(); 0135 for (NodeList::const_iterator it = nodeRemoveList.begin(); it != end; ++it) { 0136 removeNode(*it); 0137 (*it)->setSelected(false); 0138 } 0139 } 0140 0141 { 0142 const ConnectorList::const_iterator end = connectorRemoveList.end(); 0143 for (ConnectorList::const_iterator it = connectorRemoveList.begin(); it != end; ++it) { 0144 removeConnector(*it); 0145 (*it)->setSelected(false); 0146 } 0147 } 0148 0149 { 0150 const KtlQCanvasItemList::const_iterator end = list.end(); 0151 for (KtlQCanvasItemList::const_iterator it = list.begin(); it != end; ++it) { 0152 // We don't need to check that we've already got the item as it will 0153 // be checked in the function call 0154 addQCanvasItem(*it); 0155 } 0156 } 0157 } 0158 0159 void CNItemGroup::removeItem(Item *item) 0160 { 0161 if (!item || !m_itemList.contains(item)) 0162 return; 0163 unregisterItem(item); 0164 if (m_activeItem == item) 0165 getActiveItem(); 0166 0167 item->setSelected(false); 0168 updateInfo(); 0169 emit itemRemoved(item); 0170 } 0171 0172 void CNItemGroup::removeNode(Node *node) 0173 { 0174 if (!node || !m_nodeList.contains(node)) 0175 return; 0176 m_nodeList.removeAll(node); 0177 node->setSelected(false); 0178 updateInfo(); 0179 emit nodeRemoved(node); 0180 } 0181 0182 void CNItemGroup::removeConnector(Connector *con) 0183 { 0184 if (!con || !m_connectorList.contains(con)) 0185 return; 0186 m_connectorList.removeAll(con); 0187 con->setSelected(false); 0188 updateInfo(); 0189 emit connectorRemoved(con); 0190 } 0191 0192 void CNItemGroup::removeQCanvasItem(KtlQCanvasItem *qcanvasItem) 0193 { 0194 if (!qcanvasItem) 0195 return; 0196 0197 Item *item = dynamic_cast<Item *>(qcanvasItem); 0198 if (item) 0199 return removeItem(item); 0200 0201 Node *node = dynamic_cast<Node *>(qcanvasItem); 0202 if (node) 0203 return removeNode(node); 0204 0205 Connector *connector = dynamic_cast<Connector *>(qcanvasItem); 0206 if (!connector) { 0207 ConnectorLine *connectorLine = dynamic_cast<ConnectorLine *>(qcanvasItem); 0208 if (connectorLine) 0209 connector = connectorLine->parent(); 0210 } 0211 if (connector) 0212 return removeConnector(connector); 0213 } 0214 0215 NodeList CNItemGroup::nodes(bool excludeParented) const 0216 { 0217 NodeList nodeList = m_nodeList; 0218 if (excludeParented) 0219 return nodeList; 0220 0221 NodeGroupList translatableNodeGroups; 0222 p_icnDocument->getTranslatable(items(false), nullptr, nullptr, &translatableNodeGroups); 0223 0224 NodeGroupList::iterator end = translatableNodeGroups.end(); 0225 for (NodeGroupList::iterator it = translatableNodeGroups.begin(); it != end; ++it) { 0226 const NodeList internal = (*it)->internalNodeList(); 0227 NodeList::const_iterator internalEnd = internal.end(); 0228 for (NodeList::const_iterator intIt = internal.begin(); intIt != internalEnd; ++intIt) { 0229 if (*intIt && !nodeList.contains(*intIt)) 0230 nodeList << *intIt; 0231 } 0232 } 0233 0234 return nodeList; 0235 } 0236 0237 ConnectorList CNItemGroup::connectors(bool excludeParented) const 0238 { 0239 ConnectorList connectorList = m_connectorList; 0240 if (excludeParented) 0241 return connectorList; 0242 0243 ConnectorList translatableConnectors; 0244 NodeGroupList translatableNodeGroups; 0245 p_icnDocument->getTranslatable(items(false), nullptr, &translatableConnectors, &translatableNodeGroups); 0246 0247 ConnectorList::iterator tcEnd = translatableConnectors.end(); 0248 for (ConnectorList::iterator it = translatableConnectors.begin(); it != tcEnd; ++it) { 0249 if (*it && !connectorList.contains(*it)) 0250 connectorList << *it; 0251 } 0252 0253 NodeGroupList::iterator end = translatableNodeGroups.end(); 0254 for (NodeGroupList::iterator it = translatableNodeGroups.begin(); it != end; ++it) { 0255 const NodeList internal = (*it)->internalNodeList(); 0256 NodeList::const_iterator internalEnd = internal.end(); 0257 for (NodeList::const_iterator intIt = internal.begin(); intIt != internalEnd; ++intIt) { 0258 const ConnectorList connected = (*intIt)->getAllConnectors(); 0259 ConnectorList::const_iterator connectedEnd = connected.end(); 0260 for (ConnectorList::const_iterator conIt = connected.begin(); conIt != connectedEnd; ++conIt) { 0261 if (*conIt && !connectorList.contains(*conIt)) 0262 connectorList << *conIt; 0263 } 0264 } 0265 } 0266 0267 return connectorList; 0268 } 0269 0270 bool CNItemGroup::contains(KtlQCanvasItem *qcanvasItem) const 0271 { 0272 if (!qcanvasItem) 0273 return false; 0274 0275 const ItemList::const_iterator ciEnd = m_itemList.end(); 0276 for (ItemList::const_iterator it = m_itemList.begin(); it != ciEnd; ++it) { 0277 if (*it == qcanvasItem) 0278 return true; 0279 } 0280 const ConnectorList::const_iterator conEnd = m_connectorList.end(); 0281 for (ConnectorList::const_iterator it = m_connectorList.begin(); it != conEnd; ++it) { 0282 if (*it == qcanvasItem) 0283 return true; 0284 } 0285 const NodeList::const_iterator nodeEnd = m_nodeList.end(); 0286 for (NodeList::const_iterator it = m_nodeList.begin(); it != nodeEnd; ++it) { 0287 if (*it == qcanvasItem) 0288 return true; 0289 } 0290 0291 return false; 0292 } 0293 0294 void CNItemGroup::setSelected(bool sel) 0295 { 0296 const ItemList::iterator ciEnd = m_itemList.end(); 0297 for (ItemList::iterator it = m_itemList.begin(); it != ciEnd; ++it) { 0298 if (*it && (*it)->isSelected() != sel) 0299 (*it)->setSelected(sel); 0300 } 0301 const ConnectorList::iterator conEnd = m_connectorList.end(); 0302 for (ConnectorList::iterator it = m_connectorList.begin(); it != conEnd; ++it) { 0303 if (*it && (*it)->isSelected() != sel) 0304 (*it)->setSelected(sel); 0305 } 0306 const NodeList::iterator nodeEnd = m_nodeList.end(); 0307 for (NodeList::iterator it = m_nodeList.begin(); it != nodeEnd; ++it) { 0308 if (*it && (*it)->isSelected() != sel) 0309 (*it)->setSelected(sel); 0310 } 0311 } 0312 0313 bool CNItemGroup::canRotate() const 0314 { 0315 const ItemList::const_iterator end = m_itemList.end(); 0316 for (ItemList::const_iterator it = m_itemList.begin(); it != end; ++it) { 0317 // Components can rotate 0318 if (dynamic_cast<Component *>(static_cast<Item *>(*it))) 0319 return true; 0320 } 0321 return false; 0322 } 0323 0324 bool CNItemGroup::canFlip() const 0325 { 0326 const ItemList::const_iterator end = m_itemList.end(); 0327 for (ItemList::const_iterator it = m_itemList.begin(); it != end; ++it) { 0328 // Components can flip 0329 if (dynamic_cast<Component *>(static_cast<Item *>(*it))) 0330 return true; 0331 } 0332 return false; 0333 } 0334 0335 void CNItemGroup::slotRotateCW() 0336 { 0337 const ItemList::iterator end = m_itemList.end(); 0338 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) { 0339 Component *component = dynamic_cast<Component *>(static_cast<Item *>(*it)); 0340 if (component && component->isMovable()) { 0341 int oldAngle = component->angleDegrees(); 0342 component->setAngleDegrees(oldAngle + 90); 0343 } 0344 } 0345 p_icnDocument->requestStateSave(); 0346 } 0347 0348 void CNItemGroup::slotRotateCCW() 0349 { 0350 const ItemList::iterator end = m_itemList.end(); 0351 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) { 0352 Component *component = dynamic_cast<Component *>(static_cast<Item *>(*it)); 0353 if (component && component->isMovable()) { 0354 int oldAngle = component->angleDegrees(); 0355 component->setAngleDegrees(oldAngle - 90); 0356 } 0357 } 0358 p_icnDocument->requestStateSave(); 0359 } 0360 0361 void CNItemGroup::flipHorizontally() 0362 { 0363 const ItemList::iterator end = m_itemList.end(); 0364 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) { 0365 Component *component = dynamic_cast<Component *>(static_cast<Item *>(*it)); 0366 if (component && component->isMovable()) { 0367 bool oldFlipped = component->flipped(); 0368 component->setFlipped(!oldFlipped); 0369 } 0370 } 0371 p_icnDocument->requestStateSave(); 0372 } 0373 0374 void CNItemGroup::flipVertically() 0375 { 0376 const ItemList::iterator end = m_itemList.end(); 0377 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) { 0378 Component *component = dynamic_cast<Component *>(static_cast<Item *>(*it)); 0379 if (component && component->isMovable()) { 0380 bool oldFlipped = component->flipped(); 0381 0382 int oldAngle = component->angleDegrees(); 0383 component->setAngleDegrees(oldAngle + 180); 0384 component->setFlipped(!oldFlipped); 0385 component->setAngleDegrees(oldAngle + 180); 0386 } 0387 } 0388 p_icnDocument->requestStateSave(); 0389 } 0390 0391 bool CNItemGroup::haveSameOrientation() const 0392 { 0393 // set true once determined what is in this itemgroup 0394 bool areFlowparts = false; 0395 bool areComponents = false; 0396 0397 // for components 0398 int angleDegrees = 0; 0399 bool flipped = false; 0400 0401 // for flowparts 0402 unsigned orientation = 0; 0403 0404 const ItemList::const_iterator end = m_itemList.end(); 0405 for (ItemList::const_iterator it = m_itemList.begin(); it != end; ++it) { 0406 Component *component = dynamic_cast<Component *>(static_cast<Item *>(*it)); 0407 FlowPart *flowpart = dynamic_cast<FlowPart *>(static_cast<Item *>(*it)); 0408 0409 if (component && flowpart) 0410 return false; 0411 0412 if (!component && !flowpart) 0413 return false; 0414 0415 if (component) { 0416 if (areFlowparts) 0417 return false; 0418 0419 if (!areComponents) { 0420 // It's the first component we've come across 0421 angleDegrees = component->angleDegrees(); 0422 flipped = component->flipped(); 0423 areComponents = true; 0424 } else { 0425 if (angleDegrees != component->angleDegrees()) 0426 return false; 0427 0428 if (flipped != component->flipped()) 0429 return false; 0430 } 0431 } else { 0432 if (areComponents) 0433 return false; 0434 0435 if (!areFlowparts) { 0436 // It's the first flowpart we've come across 0437 orientation = flowpart->orientation(); 0438 areFlowparts = true; 0439 } else { 0440 if (orientation != flowpart->orientation()) 0441 return false; 0442 } 0443 } 0444 } 0445 0446 return true; 0447 } 0448 0449 void CNItemGroup::setOrientationAngle(int _angle) 0450 { 0451 const ItemList::iterator end = m_itemList.end(); 0452 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) { 0453 Component *component = dynamic_cast<Component *>(static_cast<Item *>(*it)); 0454 if (component && component->isMovable()) { 0455 int oldAngle = component->angleDegrees(); 0456 if (oldAngle != _angle) { 0457 component->setAngleDegrees(_angle); 0458 } 0459 } 0460 } 0461 p_icnDocument->requestStateSave(); 0462 } 0463 0464 void CNItemGroup::setComponentOrientation(int angleDegrees, bool flipped) 0465 { 0466 const ItemList::iterator end = m_itemList.end(); 0467 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) { 0468 Component *component = dynamic_cast<Component *>(static_cast<Item *>(*it)); 0469 if (component && component->isMovable()) { 0470 int oldAngle = component->angleDegrees(); 0471 int oldFlipped = component->flipped(); 0472 if ((oldAngle != angleDegrees) || (oldFlipped != flipped)) { 0473 component->setFlipped(flipped); 0474 component->setAngleDegrees(angleDegrees); 0475 } 0476 } 0477 } 0478 p_icnDocument->requestStateSave(); 0479 } 0480 0481 void CNItemGroup::setFlowPartOrientation(unsigned orientation) 0482 { 0483 const ItemList::iterator end = m_itemList.end(); 0484 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) { 0485 FlowPart *flowPart = dynamic_cast<FlowPart *>(static_cast<Item *>(*it)); 0486 if (flowPart && flowPart->isMovable()) 0487 flowPart->setOrientation(orientation); 0488 } 0489 p_icnDocument->requestStateSave(); 0490 } 0491 0492 void CNItemGroup::mergeGroup(ItemGroup *itemGroup) 0493 { 0494 CNItemGroup *group = dynamic_cast<CNItemGroup *>(itemGroup); 0495 if (!group) 0496 return; 0497 0498 const ItemList items = group->items(); 0499 const ConnectorList connectors = group->connectors(); 0500 const NodeList nodes = group->nodes(); 0501 0502 const ItemList::const_iterator ciEnd = items.end(); 0503 for (ItemList::const_iterator it = items.begin(); it != ciEnd; ++it) { 0504 addItem(*it); 0505 } 0506 const ConnectorList::const_iterator conEnd = connectors.end(); 0507 for (ConnectorList::const_iterator it = connectors.begin(); it != conEnd; ++it) { 0508 addConnector(*it); 0509 } 0510 const NodeList::const_iterator nodeEnd = nodes.end(); 0511 for (NodeList::const_iterator it = nodes.begin(); it != nodeEnd; ++it) { 0512 addNode(*it); 0513 } 0514 } 0515 0516 void CNItemGroup::removeAllItems() 0517 { 0518 while (!m_itemList.isEmpty()) 0519 removeItem(*m_itemList.begin()); 0520 0521 while (!m_connectorList.isEmpty()) 0522 removeConnector(*m_connectorList.begin()); 0523 0524 while (!m_nodeList.isEmpty()) 0525 removeNode(*m_nodeList.begin()); 0526 } 0527 0528 void CNItemGroup::deleteAllItems() 0529 { 0530 const ItemList::iterator ciEnd = m_itemList.end(); 0531 for (ItemList::iterator it = m_itemList.begin(); it != ciEnd; ++it) { 0532 if (*it) 0533 (*it)->removeItem(); 0534 } 0535 const NodeList::iterator nodeEnd = m_nodeList.end(); 0536 for (NodeList::iterator it = m_nodeList.begin(); it != nodeEnd; ++it) { 0537 if (*it && !(*it)->isChildNode()) { 0538 (*it)->removeNode(); 0539 } 0540 } 0541 const ConnectorList::iterator conEnd = m_connectorList.end(); 0542 for (ConnectorList::iterator it = m_connectorList.begin(); it != conEnd; ++it) { 0543 if (*it) { 0544 (*it)->removeConnectorNoArg(); 0545 } 0546 } 0547 0548 // Clear the lists 0549 removeAllItems(); 0550 } 0551 0552 void CNItemGroup::updateInfo() 0553 { 0554 m_connectorCount = m_connectorList.count(); 0555 m_nodeCount = m_nodeList.count(); 0556 0557 if (m_itemList.isEmpty()) 0558 m_currentLevel = -1; 0559 } 0560 0561 void CNItemGroup::getActiveItem() 0562 { 0563 if (m_itemList.isEmpty()) 0564 setActiveItem(nullptr); 0565 else 0566 setActiveItem(*m_itemList.begin()); 0567 } 0568 0569 void CNItemGroup::setActiveItem(Item *item) 0570 { 0571 if (item == m_activeItem) 0572 return; 0573 m_activeItem = item; 0574 } 0575 0576 QStringList CNItemGroup::itemIDs() 0577 { 0578 QStringList list; 0579 ItemList::iterator end = m_itemList.end(); 0580 for (ItemList::iterator it = m_itemList.begin(); it != end; ++it) { 0581 if (*it) { 0582 list += (*it)->id(); 0583 } 0584 } 0585 return list; 0586 } 0587 0588 #include "moc_cnitemgroup.cpp"