You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ktechlab/src/itemdocumentdata.cpp

1341 lines
37 KiB

/***************************************************************************
* 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 <kdebug.h>
#include <kio/netaccess.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <ktempfile.h>
#include <tqbitarray.h>
#include <tqfile.h>
// 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 ( !KIO::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, KIO::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: "<<tagName<<endl;
}
node = node.nextSibling();
}
return true;
}
bool ItemDocumentData::saveData( const KURL &url )
{
if ( url.isLocalFile() )
{
TQFile file( url.path() );
if ( !file.open(IO_WriteOnly) )
{
KMessageBox::sorry( 0l, i18n("Could not open '%1' for writing. Check that you have write permissions").arg(url.path()), i18n("Saving File") );
return false;
}
TQTextStream stream(&file);
stream << toXML();
file.close();
}
else
{
KTempFile file;
*file.textStream() << toXML();
file.close();
if ( !KIO::NetAccess::upload( file.name(), url, 0l ) )
{
KMessageBox::error( 0l, KIO::NetAccess::lastErrorString() );
return false;
}
}
return true;
}
TQString ItemDocumentData::toXML()
{
TQDomDocument doc("KTechlab");
//TODO Add revision information to save file
TQDomElement root = doc.createElement("document");
root.setAttribute( "type", documentTypeString() );
doc.appendChild(root);
{
const ItemDataMap::iterator end = m_itemDataMap.end();
for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != end; ++it )
{
TQDomElement node = itemDataToElement( doc, it.data() );
node.setAttribute( "id", it.key() );
root.appendChild(node);
}
}
{
const ConnectorDataMap::iterator end = m_connectorDataMap.end();
for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != end; ++it )
{
TQDomElement node = connectorDataToElement( doc, it.data() );
node.setAttribute( "id", it.key() );
root.appendChild(node);
}
}
{
const NodeDataMap::iterator end = m_nodeDataMap.end();
for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != end; ++it )
{
TQDomElement node = nodeDataToElement( doc, it.data() );
node.setAttribute( "id", it.key() );
root.appendChild(node);
}
}
if ( m_documentType == Document::dt_flowcode )
{
TQDomElement node = microDataToElement(doc);
root.appendChild(node);
}
return doc.toString();
}
//BEGIN functions for generating / reading TQDomElements
TQDomElement ItemDocumentData::microDataToElement( TQDomDocument &doc )
{
TQDomElement node = doc.createElement("micro");
node.setAttribute( "id", m_microData.id );
{
const PinMappingMap::iterator end = m_microData.pinMappings.end();
for ( PinMappingMap::iterator it = m_microData.pinMappings.begin(); it != end; ++it )
{
TQDomElement pinMapNode = doc.createElement("pinmap");
TQString type;
switch ( it.data().type() )
{
case PinMapping::SevenSegment:
type = "sevensegment";
break;
case PinMapping::Keypad_4x3:
type = "keypad_4x3";
break;
case PinMapping::Keypad_4x4:
type = "keypad_4x4";
break;
case PinMapping::Invalid:
break;
}
pinMapNode.setAttribute( "id", it.key() );
pinMapNode.setAttribute( "type", type );
pinMapNode.setAttribute( "map", it.data().pins().join(" ") );
node.appendChild(pinMapNode);
}
}
{
const PinDataMap::iterator end = m_microData.pinMap.end();
for ( PinDataMap::iterator it = m_microData.pinMap.begin(); it != end; ++it )
{
TQDomElement pinNode = doc.createElement("pin");
pinNode.setAttribute( "id", it.key() );
pinNode.setAttribute( "type", (it.data().type == PinSettings::pt_input) ? "input" : "output" );
pinNode.setAttribute( "state", (it.data().state == PinSettings::ps_off) ? "off" : "on" );
node.appendChild(pinNode);
}
}
{
const TQStringMap::iterator end = m_microData.variableMap.end();
for ( TQStringMap::iterator it = m_microData.variableMap.begin(); it != end; ++it )
{
TQDomElement variableNode = doc.createElement("variable");
variableNode.setAttribute( "name", it.key() );
variableNode.setAttribute( "value", it.data() );
node.appendChild(variableNode);
}
}
return node;
}
void ItemDocumentData::elementToMicroData( TQDomElement element )
{
TQString id = element.attribute( "id", TQString() );
if ( id.isNull() )
id = element.attribute( "pic", TQString() );
if ( id.isNull() )
{
kdError() << k_funcinfo << "Could not find id in element" << endl;
return;
}
m_microData.reset();
m_microData.id = id;
TQDomNode node = element.firstChild();
while ( !node.isNull() )
{
TQDomElement childElement = node.toElement();
if ( !childElement.isNull() )
{
const TQString tagName = childElement.tagName();
if ( tagName == "pinmap" )
{
TQString id = childElement.attribute( "id", TQString() );
TQString typeString = childElement.attribute( "type", TQString() );
if ( !id.isEmpty() && !typeString.isEmpty() )
{
PinMapping::Type type = PinMapping::Invalid;
if ( typeString == "sevensegment" )
type = PinMapping::SevenSegment;
else if ( typeString == "keypad_4x3" )
type = PinMapping::Keypad_4x3;
else if ( typeString == "keypad_4x4" )
type = PinMapping::Keypad_4x4;
PinMapping pinMapping( type );
pinMapping.setPins( TQStringList::split( " ", childElement.attribute( "map", 0 ) ) );
m_microData.pinMappings[id] = pinMapping;
}
}
else if ( tagName == "pin" )
{
TQString pinID = childElement.attribute( "id", TQString() );
if ( !pinID.isEmpty() )
{
m_microData.pinMap[pinID].type = (childElement.attribute( "type", "input" ) == "input" ) ? PinSettings::pt_input : PinSettings::pt_output;
m_microData.pinMap[pinID].state = (childElement.attribute( "state", "off" ) == "off" ) ? PinSettings::ps_off : PinSettings::ps_on;
}
}
else if ( tagName == "variable" )
{
TQString variableId = childElement.attribute( "name", TQString() );
m_microData.variableMap[variableId] = childElement.attribute( "value", TQString() );
}
else
kdError() << k_funcinfo << "Unrecognised element tag name: "<<tagName<<endl;
}
node = node.nextSibling();
}
}
TQDomElement ItemDocumentData::itemDataToElement( TQDomDocument &doc, const ItemData &itemData )
{
TQDomElement node = doc.createElement("item");
node.setAttribute( "type", itemData.type );
node.setAttribute( "x", itemData.x );
node.setAttribute( "y", itemData.y );
if ( itemData.z != -1 )
node.setAttribute( "z", itemData.z );
if ( itemData.setSize )
{
node.setAttribute( "offset-x", itemData.size.x() );
node.setAttribute( "offset-y", itemData.size.y() );
node.setAttribute( "width", itemData.size.width() );
node.setAttribute( "height", itemData.size.height() );
}
// If the "orientation" is >= 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 \""<<dataType<<"\" with id \""<<dataId<<"\""<<endl;
}
}
else if ( tagName == "button" )
{
TQString buttonId = childElement.attribute( "id", TQString() );
if ( !buttonId.isNull() )
m_itemDataMap[id].buttonMap[buttonId] = childElement.attribute( "state", "0" ).toInt();
}
else if ( tagName == "slider" )
{
TQString sliderId = childElement.attribute( "id", TQString() );
if ( !sliderId.isNull() )
m_itemDataMap[id].sliderMap[sliderId] = childElement.attribute( "value", "0" ).toInt();
}
else if ( tagName == "child-node" )
; // Tag name was used in 0.1 file save format
else
kdError() << k_funcinfo << "Unrecognised element tag name: "<<tagName<<endl;
}
node = node.nextSibling();
}
}
TQDomElement ItemDocumentData::nodeDataToElement( TQDomDocument &doc, const NodeData &nodeData )
{
TQDomElement node = doc.createElement("node");
node.setAttribute( "x", nodeData.x );
node.setAttribute( "y", nodeData.y );
return node;
}
void ItemDocumentData::elementToNodeData( TQDomElement element )
{
TQString id = element.attribute( "id", TQString() );
if ( id.isNull() )
{
kdError() << k_funcinfo << "Could not find id in element" << endl;
return;
}
NodeData nodeData;
nodeData.x = element.attribute( "x", "120" ).toInt();
nodeData.y = element.attribute( "y", "120" ).toInt();
m_nodeDataMap[id] = nodeData;
}
TQDomElement ItemDocumentData::connectorDataToElement( TQDomDocument &doc, const ConnectorData &connectorData )
{
TQDomElement node = doc.createElement("connector");
node.setAttribute( "manual-route", connectorData.manualRoute );
TQString route;
const TQPointList::const_iterator end = connectorData.route.end();
for ( TQPointList::const_iterator it = connectorData.route.begin(); it != end; ++it )
{
route.append( TQString::number((*it).x())+"," );
route.append( TQString::number((*it).y())+"," );
}
node.setAttribute( "route", route );
if ( connectorData.startNodeIsChild )
{
node.setAttribute( "start-node-is-child", 1 );
node.setAttribute( "start-node-cid", connectorData.startNodeCId );
node.setAttribute( "start-node-parent", connectorData.startNodeParent );
}
else
{
node.setAttribute( "start-node-is-child", 0 );
node.setAttribute( "start-node-id", connectorData.startNodeId );
}
if ( connectorData.endNodeIsChild )
{
node.setAttribute( "end-node-is-child", 1 );
node.setAttribute( "end-node-cid", connectorData.endNodeCId );
node.setAttribute( "end-node-parent", connectorData.endNodeParent );
}
else
{
node.setAttribute( "end-node-is-child", 0 );
node.setAttribute( "end-node-id", connectorData.endNodeId );
}
return node;
}
void ItemDocumentData::elementToConnectorData( TQDomElement element )
{
TQString id = element.attribute( "id", TQString() );
if ( id.isNull() )
{
kdError() << k_funcinfo << "Could not find id in element" << endl;
return;
}
ConnectorData connectorData;
connectorData.manualRoute = element.attribute( "manual-route", "0" );
TQString route = element.attribute( "route", "" );
TQStringList points = TQStringList::split( ",", route );
const TQStringList::iterator end = points.end();
for ( TQStringList::iterator it = points.begin(); it != end; ++it )
{
int x = (*it).toInt();
it++;
if ( it != end )
{
int y = (*it).toInt();
connectorData.route.append( TQPoint(x,y) );
}
}
connectorData.startNodeIsChild = element.attribute( "start-node-is-child", "0" ).toInt();
if ( connectorData.startNodeIsChild )
{
connectorData.startNodeCId = element.attribute( "start-node-cid", TQString() );
connectorData.startNodeParent = element.attribute( "start-node-parent", TQString() );
}
else
connectorData.startNodeId = element.attribute( "start-node-id", TQString() );
connectorData.endNodeIsChild = element.attribute( "end-node-is-child", "0" ).toInt();
if ( connectorData.endNodeIsChild )
{
connectorData.endNodeCId = element.attribute( "end-node-cid", TQString() );
connectorData.endNodeParent = element.attribute( "end-node-parent", TQString() );
}
else
connectorData.endNodeId = element.attribute( "end-node-id", TQString() );
m_connectorDataMap[id] = connectorData;
}
//END functions for generating / reading TQDomElements
TQString ItemDocumentData::documentTypeString() const
{
switch (m_documentType)
{
case Document::dt_circuit:
return "circuit";
break;
case Document::dt_flowcode:
return "flowcode";
break;
case Document::dt_mechanics:
return "mechanics";
break;
case Document::dt_text:
case Document::dt_none:
default:
return "none";
break;
}
}
TQString ItemDocumentData::revisionString() const
{
return "1";
}
void ItemDocumentData::saveDocumentState( ItemDocument *itemDocument )
{
if (!itemDocument)
return;
reset();
addItems( itemDocument->itemList() );
if ( ICNDocument *icnd = dynamic_cast<ICNDocument*>(itemDocument) )
{
addConnectors( icnd->connectorList() );
addNodes( icnd->nodeList() );
if ( FlowCodeDocument *fcd = dynamic_cast<FlowCodeDocument*>(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<ICNDocument*>(itemDocument);
FlowCodeDocument *fcd = dynamic_cast<FlowCodeDocument*>(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<ICNDocument*>(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(), 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: "<<it.data().startNodeParent<<endl;
else
startNode = item->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: "<<it.data().endNodeParent<<endl;
else
endNode = item->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<FlowCodeDocument*>(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<FlowContainer*>((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()<<endl;
}
}
}
void ItemDocumentData::addNodes( const NodeList &nodeList )
{
const NodeList::const_iterator end = nodeList.constEnd();
for ( NodeList::const_iterator it = nodeList.constBegin(); it != end; ++it )
{
if ( *it && (*it)->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<TQString,int> 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<Component*>(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<ICNDocument*>(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<ICNDocument*>(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