/*************************************************************************** * Copyright (C) 2005 by David Saxton * * david@bluehaze.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "connector.h" #include "ecnode.h" #include "ecsubcircuit.h" #include "flowcodedocument.h" #include "flowcontainer.h" #include "fpnode.h" #include "itemdocumentdata.h" #include "itemlibrary.h" #include "picitem.h" #include "pinmapping.h" #include #include #include #include #include #include #include #include // Converts the TQBitArray into a string (e.g. "F289A9E") that can be stored in an xml file static TQString toAsciiHex( TQBitArray _data ) { TQBitArray data = _data; // data = tqCompress(data); // Pad out the data to a nice size if ( (data.size() % 4) != 0 ) { data.detach(); data.resize( data.size() + 4 - (data.size()%4) ); } TQString text; for ( unsigned i = 0; i < data.size()/4; ++i ) { unsigned val = 0; for ( unsigned j = 0; j < 4; ++j ) val += (data[4*i+j] ? 1:0) << j; text += TQString::number( val, 16 ); } return text; } // Converts a string (e.g. "F289A9E") into a TQBitArray, the opposite of the above function static TQBitArray toTQBitArray( TQString text ) { unsigned size = text.length(); TQBitArray data(size*4); for ( unsigned i = 0; i < size; ++i ) { unsigned val = TQString(text[i]).toInt( 0l, 16 ); for ( unsigned j = 0; j < 4; ++j ) data[4*i+j] = val & (1 << j); } // data = tqUncompress(data); return data; } //BEGIN class ItemDocumentData ItemDocumentData::ItemDocumentData( uint documentType ) { reset(); m_documentType = documentType; } ItemDocumentData::~ItemDocumentData() { } void ItemDocumentData::reset() { m_itemDataMap.clear(); m_connectorDataMap.clear(); m_nodeDataMap.clear(); m_microData.reset(); m_documentType = Document::dt_none; } bool ItemDocumentData::loadData( const KURL &url ) { TQString target; if ( !TDEIO::NetAccess::download( url, target, 0l ) ) { // If the file could not be downloaded, for example does not // exist on disk, NetAccess will tell us what error to use KMessageBox::error( 0l, TDEIO::NetAccess::lastErrorString() ); return false; } TQFile file(target); if ( !file.open( IO_ReadOnly ) ) { KMessageBox::sorry( 0l, i18n("Could not open %1 for reading").arg(target) ); return false; } TQString xml; TQTextStream textStream( &file ); while ( !textStream.eof() ) xml += textStream.readLine() + '\n'; file.close(); return fromXML(xml); } bool ItemDocumentData::fromXML( const TQString &xml ) { reset(); TQDomDocument doc( "KTechlab" ); TQString errorMessage; if ( !doc.setContent( xml, &errorMessage ) ) { KMessageBox::sorry( 0l, i18n("Couldn't parse xml:\n%1").arg(errorMessage) ); return false; } TQDomElement root = doc.documentElement(); TQDomNode node = root.firstChild(); while ( !node.isNull() ) { TQDomElement element = node.toElement(); if ( !element.isNull() ) { const TQString tagName = element.tagName(); if ( tagName == "item" ) elementToItemData(element); else if ( tagName == "node" ) elementToNodeData(element); else if ( tagName == "connector" ) elementToConnectorData(element); else if ( tagName == "pic-settings" || tagName == "micro" ) elementToMicroData(element); else if ( tagName == "code" ) ; // do nothing - we no longer use this tag else kdWarning() << k_funcinfo << "Unrecognised element tag name: "<= 0, then set by a FlowPart, so we don't need to worry about the angle / flip if ( itemData.orientation >= 0 ) { node.setAttribute( "orientation", itemData.orientation ); } else { node.setAttribute( "angle", itemData.angleDegrees ); node.setAttribute( "flip", itemData.flipped ); } if ( !itemData.parentId.isEmpty() ) node.setAttribute( "parent", itemData.parentId ); const TQStringMap::const_iterator stringEnd = itemData.dataString.end(); for ( TQStringMap::const_iterator it = itemData.dataString.begin(); it != stringEnd; ++it ) { TQDomElement e = doc.createElement("data"); node.appendChild(e); e.setAttribute( "id", it.key() ); e.setAttribute( "type", "string" ); e.setAttribute( "value", it.data() ); } const DoubleMap::const_iterator numberEnd = itemData.dataNumber.end(); for ( DoubleMap::const_iterator it = itemData.dataNumber.begin(); it != numberEnd; ++it ) { TQDomElement e = doc.createElement("data"); node.appendChild(e); e.setAttribute( "id", it.key() ); e.setAttribute( "type", "number" ); e.setAttribute( "value", TQString::number(it.data()) ); } const TQColorMap::const_iterator colorEnd = itemData.dataColor.end(); for ( TQColorMap::const_iterator it = itemData.dataColor.begin(); it != colorEnd; ++it ) { TQDomElement e = doc.createElement("data"); node.appendChild(e); e.setAttribute( "id", it.key() ); e.setAttribute( "type", "color" ); e.setAttribute( "value", it.data().name() ); } const TQBitArrayMap::const_iterator rawEnd = itemData.dataRaw.end(); for ( TQBitArrayMap::const_iterator it = itemData.dataRaw.begin(); it != rawEnd; ++it ) { TQDomElement e = doc.createElement("data"); node.appendChild(e); e.setAttribute( "id", it.key() ); e.setAttribute( "type", "raw" ); e.setAttribute( "value", toAsciiHex(it.data()) ); } const BoolMap::const_iterator boolEnd = itemData.dataBool.end(); for ( BoolMap::const_iterator it = itemData.dataBool.begin(); it != boolEnd; ++it ) { TQDomElement e = doc.createElement("data"); node.appendChild(e); e.setAttribute( "id", it.key() ); e.setAttribute( "type", "bool" ); e.setAttribute( "value", TQString::number(it.data()) ); } const BoolMap::const_iterator buttonEnd = itemData.buttonMap.end(); for ( BoolMap::const_iterator it = itemData.buttonMap.begin(); it != buttonEnd; ++it ) { TQDomElement e = doc.createElement("button"); node.appendChild(e); e.setAttribute( "id", it.key() ); e.setAttribute( "state", TQString::number(it.data()) ); } const IntMap::const_iterator sliderEnd = itemData.sliderMap.end(); for ( IntMap::const_iterator it = itemData.sliderMap.begin(); it != sliderEnd; ++it ) { TQDomElement e = doc.createElement("slider"); node.appendChild(e); e.setAttribute( "id", it.key() ); e.setAttribute( "value", TQString::number(it.data()) ); } return node; } void ItemDocumentData::elementToItemData( TQDomElement element ) { TQString id = element.attribute( "id", TQString() ); if ( id.isNull() ) { kdError() << k_funcinfo << "Could not find id in element" << endl; return; } ItemData itemData; itemData.type = element.attribute( "type", TQString() ); itemData.x = element.attribute( "x", "120" ).toInt(); itemData.y = element.attribute( "y", "120" ).toInt(); itemData.z = element.attribute( "z", "-1" ).toInt(); if ( element.hasAttribute("width") && element.hasAttribute("height") ) { itemData.setSize = true; itemData.size = TQRect( element.attribute( "offset-x", "0" ).toInt(), element.attribute( "offset-y", "0" ).toInt(), element.attribute( "width", "120" ).toInt(), element.attribute( "height", "120" ).toInt() ); } else itemData.setSize = false; itemData.angleDegrees = element.attribute( "angle", "0" ).toInt(); itemData.flipped = element.attribute( "flip", "0" ).toInt(); itemData.orientation = element.attribute( "orientation", "-1" ).toInt(); itemData.parentId = element.attribute( "parent", TQString() ); m_itemDataMap[id] = itemData; TQDomNode node = element.firstChild(); while ( !node.isNull() ) { TQDomElement childElement = node.toElement(); if ( !childElement.isNull() ) { const TQString tagName = childElement.tagName(); if ( tagName == "item" ) { // We're reading in a file saved in the older format, with // child items nestled, so we must specify that the new item // has the currently parsed item as its parent. elementToItemData(childElement); TQString childId = childElement.attribute( "id", TQString() ); if ( !childId.isNull() ) m_itemDataMap[childId].parentId = id; } else if ( tagName == "data" ) { TQString dataId = childElement.attribute( "id", TQString() ); if ( !dataId.isNull() ) { TQString dataType = childElement.attribute( "type", TQString() ); TQString value = childElement.attribute( "value", TQString() ); if ( dataType == "string" || dataType == "multiline" ) m_itemDataMap[id].dataString[dataId] = value; else if ( dataType == "number" ) m_itemDataMap[id].dataNumber[dataId] = value.toDouble(); else if ( dataType == "color" ) m_itemDataMap[id].dataColor[dataId] = TQColor(value); else if ( dataType == "raw" ) m_itemDataMap[id].dataRaw[dataId] = toTQBitArray(value); else if ( dataType == "bool" ) m_itemDataMap[id].dataBool[dataId] = bool(value.toInt()); else kdError() << k_funcinfo << "Unknown data type of \""<itemList() ); if ( ICNDocument *icnd = dynamic_cast(itemDocument) ) { addConnectors( icnd->connectorList() ); addNodes( icnd->nodeList() ); if ( FlowCodeDocument *fcd = dynamic_cast(itemDocument) ) { if ( fcd->microSettings() ) setMicroData( fcd->microSettings()->microData() ); } } m_documentType = itemDocument->type(); } void ItemDocumentData::generateUniqueIDs( ItemDocument *itemDocument ) { if (!itemDocument) return; TQStringMap replaced; replaced[""] = TQString(); replaced[TQString()] = TQString(); ItemDataMap newItemDataMap; ConnectorDataMap newConnectorDataMap; NodeDataMap newNodeDataMap; //BEGIN Go through and replace the old ids { const ItemDataMap::iterator end = m_itemDataMap.end(); for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != end; ++it ) { if ( !replaced.contains( it.key() ) ) replaced[it.key()] = itemDocument->generateUID(it.key()); newItemDataMap[replaced[it.key()]] = it.data(); } } { const NodeDataMap::iterator end = m_nodeDataMap.end(); for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != end; ++it ) { if ( !replaced.contains( it.key() ) ) replaced[it.key()] = itemDocument->generateUID(it.key()); newNodeDataMap[replaced[it.key()]] = it.data(); } } { const ConnectorDataMap::iterator end = m_connectorDataMap.end(); for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != end; ++it ) { if ( !replaced.contains( it.key() ) ) replaced[it.key()] = itemDocument->generateUID(it.key()); newConnectorDataMap[replaced[it.key()]] = it.data(); } } //END Go through and replace the old ids //BEGIN Go through and replace the internal references to the ids { const ItemDataMap::iterator end = newItemDataMap.end(); for ( ItemDataMap::iterator it = newItemDataMap.begin(); it != end; ++it ) { it.data().parentId = replaced[it.data().parentId]; } } { const ConnectorDataMap::iterator end = newConnectorDataMap.end(); for ( ConnectorDataMap::iterator it = newConnectorDataMap.begin(); it != end; ++it ) { it.data().startNodeParent = replaced[it.data().startNodeParent]; it.data().endNodeParent = replaced[it.data().endNodeParent]; it.data().startNodeId = replaced[it.data().startNodeId]; it.data().endNodeId = replaced[it.data().endNodeId]; } } //END Go through and replace the internal references to the ids m_itemDataMap = newItemDataMap; m_connectorDataMap = newConnectorDataMap; m_nodeDataMap = newNodeDataMap; } void ItemDocumentData::translateContents( int dx, int dy ) { //BEGIN Go through and replace the old ids { const ItemDataMap::iterator end = m_itemDataMap.end(); for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != end; ++it ) { it.data().x += dx; it.data().y += dx; } } { const NodeDataMap::iterator end = m_nodeDataMap.end(); for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != end; ++it ) { it.data().x += dx; it.data().y += dy; } } { const ConnectorDataMap::iterator end = m_connectorDataMap.end(); for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != end; ++it ) { const TQPointList::iterator routeEnd = it.data().route.end(); for ( TQPointList::iterator routeIt = it.data().route.begin(); routeIt != routeEnd; ++routeIt ) { *routeIt += TQPoint( dx/8, dy/8 ); } } } } void ItemDocumentData::restoreDocument( ItemDocument *itemDocument ) { if ( !itemDocument ) return; ICNDocument *icnd = dynamic_cast(itemDocument); FlowCodeDocument *fcd = dynamic_cast(icnd); if ( fcd && !m_microData.id.isEmpty() ) { fcd->setPicType(m_microData.id); fcd->microSettings()->restoreFromMicroData(m_microData); } mergeWithDocument(itemDocument,false); { ItemList removeItems = itemDocument->itemList(); removeItems.remove((Item*)0l); const ItemDataMap::iterator end = m_itemDataMap.end(); for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != end; ++it ) removeItems.remove( itemDocument->itemWithID(it.key()) ); const ItemList::iterator removeEnd = removeItems.end(); for ( ItemList::iterator it = removeItems.begin(); it != removeEnd; ++it ) { if ( (*it)->canvas() && (*it)->type() != PicItem::typeString() ) (*it)->removeItem(); } } if (icnd) { { NodeList removeNodes = icnd->nodeList(); removeNodes.remove((Node*)0l); const NodeDataMap::iterator end = m_nodeDataMap.end(); for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != end; ++it ) removeNodes.remove( icnd->nodeWithID( it.key() ) ); const NodeList::iterator removeEnd = removeNodes.end(); for ( NodeList::iterator it = removeNodes.begin(); it != removeEnd; ++it ) { if ( (*it)->canvas() && !(*it)->isChildNode() ) (*it)->removeNode(); } } { ConnectorList removeConnectors = icnd->connectorList(); removeConnectors.remove((Connector*)0l); const ConnectorDataMap::iterator end = m_connectorDataMap.end(); for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != end; ++it ) removeConnectors.remove( icnd->connectorWithID(it.key()) ); const ConnectorList::iterator removeEnd = removeConnectors.end(); for ( ConnectorList::iterator it = removeConnectors.begin(); it != removeEnd; ++it ) { if ( (*it)->canvas() ) (*it)->removeConnector(); } } } itemDocument->flushDeleteList(); } void ItemDocumentData::mergeWithDocument( ItemDocument *itemDocument, bool selectNew ) { if ( !itemDocument ) return; ICNDocument *icnd = dynamic_cast(itemDocument); //BEGIN Restore Nodes if (icnd) { const NodeDataMap::iterator nodeEnd = m_nodeDataMap.end(); for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != nodeEnd; ++it ) { if ( !icnd->nodeWithID( it.key() ) ) { TQString id = it.key(); if ( itemDocument->type() == Document::dt_circuit ) new ECNode( icnd, Node::ec_junction, Node::dir_up, TQPoint( int(it.data().x), int(it.data().y) ), &id ); else if ( itemDocument->type() == Document::dt_flowcode ) new FPNode( icnd, Node::fp_junction, Node::dir_up, TQPoint( int(it.data().x), int(it.data().y) ), &id ); } } for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != nodeEnd; ++it ) { Node *node = icnd->nodeWithID( it.key() ); if (node) node->move( it.data().x, it.data().y ); } } //END Restore Nodes //BEGIN Restore items const ItemDataMap::iterator itemEnd = m_itemDataMap.end(); for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != itemEnd; ++it ) { if ( !it.data().type.isEmpty() && !itemDocument->itemWithID( it.key() ) ) { Item *item = itemLibrary()->createItem(it.data().type, itemDocument, false, it.key().utf8(), false); if ( item && !itemDocument->isValidItem(item) ) { kdWarning() << "Attempted to create invalid item with id: " << it.key() << endl; item->removeItem(); itemDocument->flushDeleteList(); item = 0l; } if (item) { //HACK We move the item now before restoreFromItemData is called later, in case it is to be parented //(as we don't want to move children)... item->move( it.data().x, it.data().y ); } } } for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != itemEnd; ++it ) { Item *item = itemDocument->itemWithID(it.key()); if (!item) continue; item->restoreFromItemData( it.data() ); item->finishedCreation(); if (selectNew) itemDocument->select(item); item->show(); } //END Restore Items //BEGIN Restore Connectors if (icnd) { const ConnectorDataMap::iterator connectorEnd = m_connectorDataMap.end(); for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != connectorEnd; ++it ) { if ( icnd->connectorWithID( it.key() ) ) continue; TQString id = it.key(); Node *startNode = 0l; Node *endNode = 0l; if ( it.data().startNodeIsChild ) { CNItem *item = icnd->cnItemWithID( it.data().startNodeParent ); if (!item) kdError() << k_funcinfo << "Unable to find node parent with id: "<childNode( it.data().startNodeCId ); } else startNode = icnd->nodeWithID( it.data().startNodeId ); if ( it.data().endNodeIsChild ) { CNItem *item = icnd->cnItemWithID( it.data().endNodeParent ); if (!item) kdError() << k_funcinfo << "Unable to find node parent with id: "<childNode( it.data().endNodeCId ); } else endNode = icnd->nodeWithID( it.data().endNodeId ); if ( !startNode || !endNode ) { kdError() << k_funcinfo << "End and start nodes for the connector do not both exist" << endl; } else { Connector *connector = new Connector( startNode, endNode, icnd, &id ); startNode->addOutputConnector(connector); endNode->addInputConnector(connector); } } for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != connectorEnd; ++it ) { Connector *connector = icnd->connectorWithID( it.key() ); if (connector) { connector->restoreFromConnectorData( it.data() ); if (selectNew) icnd->select(connector); } } } //END Restore Connectors // This is kind of hackish, but never mind if ( FlowCodeDocument *fcd = dynamic_cast(itemDocument) ) { const ItemList fcdItems = fcd->itemList(); const ItemList::const_iterator fcdItemsEnd = fcdItems.constEnd(); for ( ItemList::const_iterator it = fcdItems.constBegin(); it != fcdItemsEnd; ++it ) { if ( FlowContainer * fc = dynamic_cast((Item*)*it) ) fc->updateContainedVisibility(); } } } void ItemDocumentData::setMicroData( const MicroData &data ) { m_microData = data; } void ItemDocumentData::addItems( const ItemList &itemList ) { const ItemList::const_iterator end = itemList.constEnd(); for ( ItemList::const_iterator it = itemList.constBegin(); it != end; ++it ) { if ( *it && (*it)->canvas() && (*it)->type() != PicItem::typeString() ) addItemData( (*it)->itemData(), (*it)->id() ); } } void ItemDocumentData::addConnectors( const ConnectorList &connectorList ) { const ConnectorList::const_iterator end = connectorList.constEnd(); for ( ConnectorList::const_iterator it = connectorList.constBegin(); it != end; ++it ) { if ( *it && (*it)->canvas() ) { if ( (*it)->startNode() && (*it)->endNode() ) addConnectorData( (*it)->connectorData(), (*it)->id() ); else kdDebug() << k_funcinfo << " *it="<<*it<<" (*it)->startNode()="<<(*it)->startNode()<<" (*it)->endNode()="<<(*it)->endNode()<canvas() && !(*it)->isChildNode() ) addNodeData( (*it)->nodeData(), (*it)->id() ); } } void ItemDocumentData::addItemData( ItemData itemData, TQString id ) { m_itemDataMap[id] = itemData; } void ItemDocumentData::addConnectorData( ConnectorData connectorData, TQString id ) { m_connectorDataMap[id] = connectorData; } void ItemDocumentData::addNodeData( NodeData nodeData, TQString id ) { m_nodeDataMap[id] = nodeData; } //END class ItemDocumentData //BEGIN class ItemData ItemData::ItemData() { x = 0; y = 0; z = -1; angleDegrees = 0; flipped = false; orientation = -1; setSize = false; } //END class ItemData //BEGIN class ConnectorData ConnectorData::ConnectorData() { manualRoute = false; startNodeIsChild = false; endNodeIsChild = false; } //END class ConnectorData //BEGIN class NodeData NodeData::NodeData() { x = 0; y = 0; } //END class NodeDaata //BEGIN class PinData PinData::PinData() { type = PinSettings::pt_input; state = PinSettings::ps_off; } //END class PinData //BEGIN class MicroData MicroData::MicroData() { } void MicroData::reset() { id = TQString(); pinMap.clear(); } //END class MicroData //BEGIN class SubcircuitData SubcircuitData::SubcircuitData() : ItemDocumentData( Document::dt_circuit ) { } void SubcircuitData::initECSubcircuit( ECSubcircuit * ecSubcircuit ) { if (!ecSubcircuit) return; generateUniqueIDs( ecSubcircuit->itemDocument() ); // Generate a list of the External Connections, sorting by x coordinate std::multimap< double, TQString > extCon; ItemDataMap::iterator itemEnd = m_itemDataMap.end(); for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != itemEnd; ++it ) { if ( it.data().type == "ec/external_connection" ) extCon.insert( std::make_pair( it.data().x, it.key() ) ); } // How many external connections do we have? ecSubcircuit->setNumExtCon(extCon.size()); // Sort the connections into the pins of the subcircuit by y coordinate std::multimap< double, TQString > leftPins; std::multimap< double, TQString > rightPins; int at = 0; int size = (extCon.size()/2) + (extCon.size()%2); const std::multimap< double, TQString >::iterator extConEnd = extCon.end(); for ( std::multimap< double, TQString >::iterator it = extCon.begin(); it != extConEnd; ++it ) { if ( at < size ) leftPins.insert( std::make_pair( m_itemDataMap[it->second].y, it->second ) ); else rightPins.insert( std::make_pair( m_itemDataMap[it->second].y, it->second ) ); at++; } // Remove the external connections (recording their names and associated numerical position) int nodeId = 0; typedef TQMap IntMap; IntMap nodeMap; const std::multimap< double, TQString >::iterator leftPinsEnd = leftPins.end(); for ( std::multimap< double, TQString >::iterator it = leftPins.begin(); it != leftPinsEnd; ++it ) { nodeMap[ it->second ] = nodeId; ecSubcircuit->setExtConName( nodeId, m_itemDataMap[ it->second ].dataString["name"] ); nodeId++; m_itemDataMap.remove( it->second ); } nodeId = extCon.size()-1; const std::multimap< double, TQString >::iterator rightPinsEnd = rightPins.end(); for ( std::multimap< double, TQString >::iterator it = rightPins.begin(); it != rightPinsEnd; ++it ) { nodeMap[ it->second ] = nodeId; ecSubcircuit->setExtConName( nodeId, m_itemDataMap[ it->second ].dataString["name"] ); nodeId--; m_itemDataMap.remove( it->second ); } // Replace connector references to the old External Connectors to the nodes const ConnectorDataMap::iterator connectorEnd = m_connectorDataMap.end(); for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != connectorEnd; ++it ) { if ( it.data().startNodeIsChild && nodeMap.contains(it.data().startNodeParent ) ) { it.data().startNodeCId = TQString::number( nodeMap[it.data().startNodeParent] ); it.data().startNodeParent = ecSubcircuit->id(); } if ( it.data().endNodeIsChild && nodeMap.contains(it.data().endNodeParent ) ) { it.data().endNodeCId = TQString::number( nodeMap[it.data().endNodeParent] ); it.data().endNodeParent = ecSubcircuit->id(); } } // Create all the new stuff mergeWithDocument( ecSubcircuit->itemDocument(), false ); // Parent and hide the new stuff itemEnd = m_itemDataMap.end(); for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != itemEnd; ++it) { Component * component = static_cast(ecSubcircuit->itemDocument()->itemWithID( it.key() )); if (component) { component->setParentItem(ecSubcircuit); component->updateConnectorPoints(false); component->setVisible(false); component->setCanvas(0l); ecSubcircuit->connect( ecSubcircuit, TQT_SIGNAL(subcircuitDeleted()), component, TQT_SLOT(removeItem()) ); } } for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != connectorEnd; ++it ) { Connector * connector = (static_cast(ecSubcircuit->itemDocument()))->connectorWithID( it.key() ); if (connector) { connector->updateConnectorPoints(false); connector->setVisible(false); connector->setCanvas(0l); ecSubcircuit->connect( ecSubcircuit, TQT_SIGNAL(subcircuitDeleted()), connector, TQT_SLOT(removeConnector()) ); } } const NodeDataMap::iterator nodeEnd = m_nodeDataMap.end(); for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != nodeEnd; ++it ) { Node * node = (static_cast(ecSubcircuit->itemDocument()))->nodeWithID( it.key() ); if (node) { node->setVisible(false); node->setCanvas(0l); ecSubcircuit->connect( ecSubcircuit, TQT_SIGNAL(subcircuitDeleted()), node, TQT_SLOT(removeNode()) ); } } ecSubcircuit->doneSCInit(); } //END class SubcircuitData