Logo Search packages:      
Sourcecode: ktechlab version File versions

itemdocumentdata.cpp

/***************************************************************************
 *   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 <qbitarray.h>
#include <qfile.h>


// Converts the QBitArray into a string (e.g. "F289A9E") that can be stored in an xml file
static QString toAsciiHex( QBitArray _data )
{
      QBitArray data = _data;
//    data = qCompress(data);
      
      // Pad out the data to a nice size
      if ( (data.size() % 4) != 0 )
      {
            data.detach();
            data.resize( data.size() + 4 - (data.size()%4) );
      }
      
      QString 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 += QString::number( val, 16 );
      }
      return text;
}

// Converts a string (e.g. "F289A9E") into a QBitArray, the opposite of the above function
static QBitArray toQBitArray( QString text )
{
      unsigned size = text.length();
      QBitArray data(size*4);
      
      for ( unsigned i = 0; i < size; ++i )
      {
            unsigned val = QString(text[i]).toInt( 0l, 16 );
            for ( unsigned j = 0; j < 4; ++j )
                  data[4*i+j] = val & (1 << j);
      }
      
//    data = qUncompress(data);
      
      return data;
}


//BEGIN class ItemDocumentData
ItemDocumentData::ItemDocumentData( uint documentType )
{
      reset();
      m_documentType = documentType;
}


ItemDocumentData::~ItemDocumentData()
{
}


00088 void ItemDocumentData::reset()
{
      m_itemDataMap.clear();
      m_connectorDataMap.clear();
      m_nodeDataMap.clear();
      m_microData.reset();
      m_documentType = Document::dt_none;
}


00098 bool ItemDocumentData::loadData( const KURL &url )
{
      QString 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;
      }
      
      QFile file(target);
      if ( !file.open( IO_ReadOnly ) )
      {
            KMessageBox::sorry( 0l, i18n("Could not open %1 for reading").arg(target) );
            return false;
      }
      
      QString xml;
      QTextStream textStream( &file );
      while ( !textStream.eof() )
            xml += textStream.readLine() + '\n';
      
      file.close();
      return fromXML(xml);
}


00127 bool ItemDocumentData::fromXML( const QString &xml )
{
      reset();
      
      QDomDocument doc( "KTechlab" );
      QString errorMessage;
      if ( !doc.setContent( xml, &errorMessage ) )
      {
            KMessageBox::sorry( 0l, i18n("Couldn't parse xml:\n%1").arg(errorMessage) );
            return false;
      }
      
      QDomElement root = doc.documentElement();
      
      QDomNode node = root.firstChild();
      while ( !node.isNull() )
      {
            QDomElement element = node.toElement();
            if ( !element.isNull() )
            {
                  const QString 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;
}


00175 bool ItemDocumentData::saveData( const KURL &url )
{
      
      if ( url.isLocalFile() )
      {
            QFile 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;
            }
            
            QTextStream 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;
}


00208 QString ItemDocumentData::toXML()
{
      QDomDocument doc("KTechlab");
      //TODO Add revision information to save file
      
      QDomElement 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 )
            {
                  QDomElement 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 )
            {
                  QDomElement 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 )
            {
                  QDomElement node = nodeDataToElement( doc, it.data() );
                  node.setAttribute( "id", it.key() );
                  root.appendChild(node);
            }
      }
      if ( m_documentType == Document::dt_flowcode )
      {
            QDomElement node = microDataToElement(doc);
            root.appendChild(node);
      }
      
      return doc.toString();
}



//BEGIN functions for generating / reading QDomElements
QDomElement ItemDocumentData::microDataToElement( QDomDocument &doc )
{
      QDomElement 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 )
            {
                  QDomElement pinMapNode = doc.createElement("pinmap");
                  
                  QString 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 )
            {
                  QDomElement 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 QStringMap::iterator end = m_microData.variableMap.end();
            for ( QStringMap::iterator it = m_microData.variableMap.begin(); it != end; ++it )
            {
                  QDomElement variableNode = doc.createElement("variable");
                  
                  variableNode.setAttribute( "name", it.key() );
                  variableNode.setAttribute( "value", it.data() );
                  
                  node.appendChild(variableNode);
            }
      }
      
      return node;
}


void ItemDocumentData::elementToMicroData( QDomElement element )
{
      QString id = element.attribute( "id", QString::null );
      
      if ( id.isNull() )
            id = element.attribute( "pic", QString::null );
      
      if ( id.isNull() )
      {
            kdError() << k_funcinfo << "Could not find id in element" << endl;
            return;
      }
      
      m_microData.reset();
      m_microData.id = id;
      
      QDomNode node = element.firstChild();
      while ( !node.isNull() )
      {
            QDomElement childElement = node.toElement();
            if ( !childElement.isNull() )
            {
                  const QString tagName = childElement.tagName();
                  
                  if ( tagName == "pinmap" )
                  {
                        QString id = childElement.attribute( "id", QString::null );
                        QString typeString = childElement.attribute( "type", QString::null );
                        
                        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( QStringList::split( " ", childElement.attribute( "map", 0 ) ) );
                              
                              m_microData.pinMappings[id] = pinMapping;
                        }
                  }
                  
                  else if ( tagName == "pin" )
                  {
                        QString pinID = childElement.attribute( "id", QString::null );
                        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" )
                  {
                        QString variableId = childElement.attribute( "name", QString::null );
                        m_microData.variableMap[variableId] = childElement.attribute( "value", QString::null );
                  }
                  
                  else
                        kdError() << k_funcinfo << "Unrecognised element tag name: "<<tagName<<endl;
            }
            
            node = node.nextSibling();
      }
}


QDomElement ItemDocumentData::itemDataToElement( QDomDocument &doc, const ItemData &itemData )
{
      QDomElement 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 QStringMap::const_iterator stringEnd = itemData.dataString.end();
      for ( QStringMap::const_iterator it = itemData.dataString.begin(); it != stringEnd; ++it )
      {
            QDomElement 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 )
      {
            QDomElement e = doc.createElement("data");
            node.appendChild(e);
            e.setAttribute( "id", it.key() );
            e.setAttribute( "type", "number" );
            e.setAttribute( "value", QString::number(it.data()) );
      }
      
      const QColorMap::const_iterator colorEnd = itemData.dataColor.end();
      for ( QColorMap::const_iterator it = itemData.dataColor.begin(); it != colorEnd; ++it )
      {
            QDomElement e = doc.createElement("data");
            node.appendChild(e);
            e.setAttribute( "id", it.key() );
            e.setAttribute( "type", "color" );
            e.setAttribute( "value", it.data().name() );
      }
      
      const QBitArrayMap::const_iterator rawEnd = itemData.dataRaw.end();
      for ( QBitArrayMap::const_iterator it = itemData.dataRaw.begin(); it != rawEnd; ++it )
      {
            QDomElement 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 )
      {
            QDomElement e = doc.createElement("data");
            node.appendChild(e);
            e.setAttribute( "id", it.key() );
            e.setAttribute( "type", "bool" );
            e.setAttribute( "value", QString::number(it.data()) );
      }
      
      const BoolMap::const_iterator buttonEnd = itemData.buttonMap.end();
      for ( BoolMap::const_iterator it = itemData.buttonMap.begin(); it != buttonEnd; ++it )
      {
            QDomElement e = doc.createElement("button");
            node.appendChild(e);
            e.setAttribute( "id", it.key() );
            e.setAttribute( "state", QString::number(it.data()) );
      }
      
      const IntMap::const_iterator sliderEnd = itemData.sliderMap.end();
      for ( IntMap::const_iterator it = itemData.sliderMap.begin(); it != sliderEnd; ++it )
      {
            QDomElement e = doc.createElement("slider");
            node.appendChild(e);
            e.setAttribute( "id", it.key() );
            e.setAttribute( "value", QString::number(it.data()) );
      }
      
      return node;
}


void ItemDocumentData::elementToItemData( QDomElement element )
{
      QString id = element.attribute( "id", QString::null );
      if ( id.isNull() )
      {
            kdError() << k_funcinfo << "Could not find id in element" << endl;
            return;
      }
      
      ItemData itemData;
      itemData.type = element.attribute( "type", QString::null );
      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 = QRect( 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", QString::null );
      
      m_itemDataMap[id] = itemData;
      
      QDomNode node = element.firstChild();
      while ( !node.isNull() )
      {
            QDomElement childElement = node.toElement();
            if ( !childElement.isNull() )
            {
                  const QString 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);
                        QString childId = childElement.attribute( "id", QString::null );
                        if ( !childId.isNull() )
                              m_itemDataMap[childId].parentId = id;
                  }
                  
                  else if ( tagName == "data" )
                  {
                        QString dataId = childElement.attribute( "id", QString::null );
                        if ( !dataId.isNull() )
                        {
                              QString dataType = childElement.attribute( "type", QString::null );
                              QString value = childElement.attribute( "value", QString::null );
                              
                              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] = QColor(value);
                              else if ( dataType == "raw" )
                                    m_itemDataMap[id].dataRaw[dataId] = toQBitArray(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" )
                  {
                        QString buttonId = childElement.attribute( "id", QString::null );
                        if ( !buttonId.isNull() )
                              m_itemDataMap[id].buttonMap[buttonId] = childElement.attribute( "state", "0" ).toInt();
                  }
                  
                  else if ( tagName == "slider" )
                  {
                        QString sliderId = childElement.attribute( "id", QString::null );
                        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();
      }
}


QDomElement ItemDocumentData::nodeDataToElement( QDomDocument &doc, const NodeData &nodeData )
{
      QDomElement node = doc.createElement("node");
      node.setAttribute( "x", nodeData.x );
      node.setAttribute( "y", nodeData.y );
      return node;
}


void ItemDocumentData::elementToNodeData( QDomElement element )
{
      QString id = element.attribute( "id", QString::null );
      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;
}


QDomElement ItemDocumentData::connectorDataToElement( QDomDocument &doc, const ConnectorData &connectorData )
{
      QDomElement node = doc.createElement("connector");
      
      node.setAttribute( "manual-route", connectorData.manualRoute );
      
      QString route;
      const QPointList::const_iterator end = connectorData.route.end();
      for ( QPointList::const_iterator it = connectorData.route.begin(); it != end; ++it )
      {
            route.append( QString::number((*it).x())+"," );
            route.append( QString::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( QDomElement element )
{
      QString id = element.attribute( "id", QString::null );
      if ( id.isNull() )
      {
            kdError() << k_funcinfo << "Could not find id in element" << endl;
            return;
      }
      
      ConnectorData connectorData;
      
      connectorData.manualRoute = element.attribute( "manual-route", "0" );
      QString route = element.attribute( "route", "" );
      
      QStringList points = QStringList::split( ",", route );
      const QStringList::iterator end = points.end();
      for ( QStringList::iterator it = points.begin(); it != end; ++it )
      {
            int x = (*it).toInt();
            it++;
            if ( it != end )
            {
                  int y = (*it).toInt();
                  connectorData.route.append( QPoint(x,y) );
            }
      }
      
      connectorData.startNodeIsChild = element.attribute( "start-node-is-child", "0" ).toInt();
      if ( connectorData.startNodeIsChild )
      {
            connectorData.startNodeCId = element.attribute( "start-node-cid", QString::null );
            connectorData.startNodeParent = element.attribute( "start-node-parent", QString::null );
      }
      else
            connectorData.startNodeId = element.attribute( "start-node-id", QString::null );
      
      
      connectorData.endNodeIsChild = element.attribute( "end-node-is-child", "0" ).toInt();
      if ( connectorData.endNodeIsChild )
      {
            connectorData.endNodeCId = element.attribute( "end-node-cid", QString::null );
            connectorData.endNodeParent = element.attribute( "end-node-parent", QString::null );
      }
      else
            connectorData.endNodeId = element.attribute( "end-node-id", QString::null );
      
      m_connectorDataMap[id] = connectorData;
}
//END functions for generating / reading QDomElements



QString 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;
      }
}


QString ItemDocumentData::revisionString() const
{
      return "1";
}


00753 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();
}


00778 void ItemDocumentData::generateUniqueIDs( ItemDocument *itemDocument )
{
      if (!itemDocument)
            return;
      
      QStringMap replaced;
      replaced[""] = QString::null;
      replaced[QString::null] = QString::null;
      
      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;
}


00852 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 QPointList::iterator routeEnd = it.data().route.end();
                  for ( QPointList::iterator routeIt = it.data().route.begin(); routeIt != routeEnd; ++routeIt )
                  {
                        *routeIt += QPoint( dx/8, dy/8 );
                  }
            }
      }
}


00885 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();
}


00954 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() ) )
                  {
                        QString id = it.key();
                        if ( itemDocument->type() == Document::dt_circuit )
                              new ECNode( icnd, Node::ec_junction, Node::dir_up, QPoint( 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, QPoint( 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;
                  
                  QString 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() );
      }
}


01142 void ItemDocumentData::addItemData( ItemData itemData, QString id )
{
      m_itemDataMap[id] = itemData;
}


01148 void ItemDocumentData::addConnectorData( ConnectorData connectorData, QString id )
{
      m_connectorDataMap[id] = connectorData;
}


01154 void ItemDocumentData::addNodeData( NodeData nodeData, QString 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 = QString::null;
      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, QString > 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, QString > leftPins;
      std::multimap< double, QString > rightPins;
      int at = 0;
      int size = (extCon.size()/2) + (extCon.size()%2);
      const std::multimap< double, QString >::iterator extConEnd = extCon.end();
      for ( std::multimap< double, QString >::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 QMap<QString,int> IntMap;
      IntMap nodeMap;
      const std::multimap< double, QString >::iterator leftPinsEnd = leftPins.end();
      for ( std::multimap< double, QString >::iterator it = leftPins.begin(); it != leftPinsEnd; ++it )
      {
            nodeMap[ it->second ] = nodeId;
            ecSubcircuit->setExtConName( nodeId, m_itemDataMap[ it->second ].dataString["name"].data() );
            nodeId++;
            m_itemDataMap.remove( it->second );
      }
      nodeId = extCon.size()-1;
      const std::multimap< double, QString >::iterator rightPinsEnd = rightPins.end();
      for ( std::multimap< double, QString >::iterator it = rightPins.begin(); it != rightPinsEnd; ++it )
      {
            nodeMap[ it->second ] = nodeId;
            ecSubcircuit->setExtConName( nodeId, m_itemDataMap[ it->second ].dataString["name"].data() );
            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 = QString::number( nodeMap[it.data().startNodeParent] );
                  it.data().startNodeParent = ecSubcircuit->id();
                  
            }
            if ( it.data().endNodeIsChild && nodeMap.contains(it.data().endNodeParent ) )
            {
                  it.data().endNodeCId = QString::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, SIGNAL(subcircuitDeleted()), component, 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, SIGNAL(subcircuitDeleted()), connector, 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, SIGNAL(subcircuitDeleted()), node, SLOT(removeNode()) );
            }
      }
      
      ecSubcircuit->doneSCInit();
}
//END class SubcircuitData


Generated by  Doxygen 1.6.0   Back to index