Warning, file /office/calligra/filters/libmsooxml/MsooXmlDiagramReader_p.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * This file is part of Office 2007 Filters for Calligra
0003  *
0004  * Copyright (C) 2010 Sebastian Sauer <sebsauer@kdab.com>
0005  * Copyright (c) 2010 Carlos Licea <carlos@kdab.com>
0006  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
0007  *
0008  * Contact: Suresh Chande suresh.chande@nokia.com
0009  *
0010  * This library is free software; you can redistribute it and/or
0011  * modify it under the terms of the GNU Lesser General Public License
0012  * version 2.1 as published by the Free Software Foundation.
0013  *
0014  * This library is distributed in the hope that it will be useful, but
0015  * WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0017  * Lesser General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Lesser General Public
0020  * License along with this library; if not, write to the Free Software
0021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0022  * 02110-1301 USA
0023  *
0024  */
0025 #include "MsooXmlDiagramReader_p.h"
0026 
0027 #include <typeinfo>
0028 #include <iterator>
0029 #include <QXmlStreamReader>
0030 #include <KoXmlWriter.h>
0031 #include <KoGenStyles.h>
0032 #include <KoEmbeddedDocumentSaver.h>
0033 #include <KoShapeSavingContext.h>
0034 #include "MsooXmlDebug.h"
0035 
0036 #define MSOOXML_CURRENT_NS "dgm"
0037 #define MSOOXML_CURRENT_CLASS MsooXmlDiagramReader
0038 #define BIND_READ_CLASS MSOOXML_CURRENT_CLASS
0039 
0040 #include <MsooXmlReader.h>
0041 #include <MsooXmlReader_p.h>
0042 #include <MsooXmlCommonReader.h>
0043 #include <MsooXmlUtils.h>
0044 #include <MsooXmlDiagramReader.h>
0045 
0046 #include <QTextStream>
0047 
0048 #include <algorithm>
0049 
0050 namespace MSOOXML { namespace Diagram {
0051 
0052 //#define ASSERT_X(condition, errormessage) Q_ASSERT_X(condition, __FUNCTION__, errormessage)
0053 #define ASSERT_X(condition, errormessage) 
0054 #define DEBUG_DUMP debugMsooXml << QString("%1%2").arg(QString(' ').repeated(level*2)).arg(m_tagName)
0055 //#define DEBUG_DUMP debugMsooXml << QString("%1Dgm::%2::%3").arg(QString(' ').repeated(level)).arg(typeid(this).name()).arg(__FUNCTION__) << this << "atom=" << m_tagName
0056 #define DEBUG_WRITE debugMsooXml << QString("Dgm::%1::%2").arg(typeid(this).name()).arg(__FUNCTION__) << "atom=" << m_tagName
0057 
0058 }}
0059 
0060 using namespace MSOOXML::Diagram;
0061 using namespace MSOOXML;
0062 
0063 /****************************************************************************************************/
0064 
0065 Context::Context()
0066     : m_rootPoint(0)
0067     , m_connections(new ConnectionListNode)
0068     , m_rootLayout(new Diagram::LayoutNodeAtom)
0069     , m_parentLayout(m_rootLayout)
0070     , m_currentNode(0) {
0071 }
0072 
0073 Context::~Context() {
0074     //TODO make sure this is no memoryleak
0075     //delete m_rootPoint;
0076     //delete m_connections;
0077 }
0078         
0079 AbstractNode* Context::currentNode() const {
0080     return m_currentNode;
0081 }
0082 
0083 void Context::setCurrentNode(AbstractNode* node) {
0084     m_currentNode = node;
0085 }
0086 
0087 ValueCache::ValueCache() : m_rect( QRectF( 0.0f, 0.0f, 100.0f, 100.0f ) ), m_unmodified( true ), m_negativeWidth( false ), m_negativeHeight( false ) {}
0088 
0089 bool ValueCache::hasNegativeWidth() const {
0090     return m_negativeWidth;
0091 }
0092 
0093 bool ValueCache::hasNegativeHeight() const {
0094     return m_negativeHeight;
0095 }
0096 
0097 qreal ValueCache::value( const QString& name, bool *valid ) const {
0098     if ( valid )
0099         *valid = true;
0100     if ( isRectValue( name ) )
0101         return rectValue( name );
0102     if ( valid && ! m_mapping.contains( name ) )
0103         *valid = false;
0104     return m_mapping[ name ];
0105 }
0106 
0107 bool ValueCache::valueExists( const QString& name ) {
0108     return isRectValue( name ) || m_mapping.contains( name );
0109 }
0110 
0111 void ValueCache::setValue( const QString& name, qreal value ) {
0112     if ( isRectValue( name ) )
0113         setRectValue( name, value );
0114     else
0115         m_mapping[ name ] = value;
0116 }
0117 
0118 qreal ValueCache::operator[]( const QString& name ) const  {
0119     return value( name );
0120 }
0121 
0122 ValueCache::ResultWrapper ValueCache::operator[]( const char* name ) {
0123     return ResultWrapper( this, QString::fromLatin1( name ) );
0124 }
0125 
0126 ValueCache::ResultWrapper ValueCache::operator[]( const QString& name ) {
0127     return ResultWrapper( this, name );
0128 }
0129 
0130 ValueCache::operator QMap< QString, qreal >() const {
0131     QMap < QString, qreal > result = m_mapping;
0132     result[ "l" ] = m_rect.left();
0133     result[ "r" ] = m_rect.right();
0134     result[ "t" ] = m_rect.top();
0135     result[ "b" ] = m_rect.bottom();
0136     result[ "w" ] = m_rect.width();
0137     result[ "h" ] = m_rect.height();
0138     result[ "ctrX" ] = m_rect.center().rx();
0139     result[ "ctrY" ] = m_rect.center().ry();
0140     return result;
0141 }
0142 
0143 bool ValueCache::isRectValue( const QString& name ) const {
0144     return name == "l" || name == "r" || name == "w" || name == "h" || name == "t" || name == "b" || name == "ctrX" || name == "ctrY";
0145 }
0146 
0147 qreal ValueCache::rectValue( const QString& name ) const {
0148     if ( name == "l")
0149         return m_rect.left();
0150     if ( name == "r" )
0151         return m_rect.right();
0152     if ( name == "w" )
0153         return m_rect.width();
0154     if ( name == "h" )
0155         return m_rect.height();
0156     if ( name == "t" )
0157         return m_rect.top();
0158     if ( name == "b" )
0159         return m_rect.bottom();
0160     if ( name == "ctrX" )
0161         return m_rect.center().rx();
0162     if ( name == "ctrY" )
0163         return m_rect.center().ry();
0164     return 0.0;
0165 }
0166 #include <limits>
0167 void ValueCache::setRectValue( const QString& name, qreal value ) {
0168     if ( name == "l") {
0169         m_rect.moveLeft( value );
0170     } else if ( name == "r" ) {
0171         m_rect.moveRight( value );
0172     } else if ( name == "w" ) {
0173         m_rect.setWidth( value );
0174     } else if ( name == "h" ) {
0175         //TODO this is a hack, as its not really described how to handle infinite values during layouting
0176         if ( value != std::numeric_limits<qreal>::infinity() )
0177             m_rect.setHeight( value );
0178         else
0179             m_rect.setHeight( m_rect.width() );
0180     } else if ( name == "t" ) {
0181         m_rect.moveTop( value );
0182     } else if ( name == "b" ) {
0183         m_rect.moveBottom( value );
0184     } else if ( name == "ctrX" ) {
0185         m_rect.moveCenter( QPointF( value, m_rect.center().y() ) );
0186     } else if ( name == "ctrY" ) {
0187         m_rect.moveCenter( QPointF( m_rect.center().x(), value ) );
0188     } else {
0189         ASSERT_X( false, QString("TODO unhandled name=%1 value=%2").arg(name).arg(value).toLocal8Bit() );
0190     }
0191     m_unmodified = false;
0192 }
0193 
0194 /****************************************************************************************************/
0195 
0196 AbstractNode::AbstractNode(const QString &tagName) : m_tagName(tagName), m_parent(0) {}
0197 AbstractNode::~AbstractNode() { qDeleteAll(children()); }
0198 
0199 void AbstractNode::dump(Context* context, int level) {    
0200     foreach(AbstractNode* node, children())
0201         node->dump(context, level + 1);    
0202 }
0203 
0204 void AbstractNode::dump( QTextStream& device ) {
0205     foreach(AbstractNode* node, children())
0206         node->dump( device );
0207 }
0208 
0209 void AbstractNode::readElement(Context*, MsooXmlDiagramReader*) {
0210 }
0211 
0212 void AbstractNode::readAll(Context* context, MsooXmlDiagramReader* reader) {
0213     while (!reader->atEnd()) {
0214         QXmlStreamReader::TokenType tokenType = reader->readNext();
0215         if(tokenType == QXmlStreamReader::Invalid || tokenType == QXmlStreamReader::EndDocument) break;
0216         if(!reader->isStartElement() && reader->qualifiedName() == m_tagName) break;
0217         readElement(context, reader);
0218     }
0219 }
0220 
0221 AbstractNode* AbstractNode::parent() const {
0222     return m_parent;
0223 }
0224 
0225 QList<AbstractNode*> AbstractNode::children() const {
0226     if(m_cachedChildren.isEmpty()) {
0227         const int count = m_appendedChildren.count()+m_orderedChildren.count();
0228         for(int i = 0, k = -1; i < count; ++i) {
0229             if(m_orderedChildren.contains(i)) {
0230                 foreach(AbstractNode* n, m_orderedChildren[i])
0231                     m_cachedChildren.append(n);
0232             } else {
0233                 m_cachedChildren.append(m_appendedChildren[++k]);
0234             }
0235         }
0236     }
0237     return m_cachedChildren;
0238 }
0239 
0240 void AbstractNode::insertChild(int index, AbstractNode* node) {
0241     //Q_ASSERT(!m_orderedChildren.contains(index));
0242     Q_ASSERT(!m_orderedChildrenReverse.contains(node));
0243     Q_ASSERT(!m_appendedChildren.contains(node));
0244     Q_ASSERT(!node->m_parent);
0245     node->m_parent = this;
0246     if(m_orderedChildren.contains(index))
0247         m_orderedChildren[index].append(node);
0248     else
0249         m_orderedChildren[index] = QList<AbstractNode*>() << node;
0250     m_orderedChildrenReverse[node] = index;
0251     m_cachedChildren.clear();
0252     //LayoutNodeAtom* layNode = dynamic_cast< LayoutNodeAtom* >( node );
0253 }
0254 
0255 void AbstractNode::addChild(AbstractNode* node) {
0256     Q_ASSERT(!node->m_parent);
0257     Q_ASSERT(!m_orderedChildrenReverse.contains(node));
0258     node->m_parent = this;
0259     m_appendedChildren.append(node);
0260     m_cachedChildren.clear();
0261     //LayoutNodeAtom* layNode = dynamic_cast< LayoutNodeAtom* >( this );
0262 }
0263 
0264 void AbstractNode::removeChild(AbstractNode* node) {
0265     Q_ASSERT(node->m_parent == this);
0266     node->m_parent = 0;
0267     if(m_orderedChildrenReverse.contains(node)) {
0268         int index = m_orderedChildrenReverse.take(node);
0269         QList<AbstractNode*> nodes = m_orderedChildren[index];
0270         nodes.removeAll(node);
0271         m_orderedChildren[index] = nodes;
0272     } else {
0273         m_appendedChildren.removeAll(node);
0274     }
0275     m_cachedChildren.clear();
0276 }
0277 
0278 QList<AbstractNode*> AbstractNode::descendant() const {
0279     QList<AbstractNode*> list = children();
0280     foreach(AbstractNode* node, children())
0281         foreach(AbstractNode* n, node->descendant())
0282             list.append(n);
0283     return list;
0284 }
0285 
0286 QList<AbstractNode*> AbstractNode::peers() const {
0287     QList<AbstractNode*> list;
0288     if (m_parent)
0289         foreach(AbstractNode* node, m_parent->children())
0290             if(node != this)
0291                 list.append(node);
0292     return list;
0293 }                
0294 
0295 /****************************************************************************************************/
0296 
0297 void PointNode::dump(Context* context, int level) {
0298     DEBUG_DUMP << "type=" << m_type << "modelId=" << m_modelId << "cxnId=" << m_cxnId;
0299     AbstractNode::dump(context, level);
0300 }
0301 
0302 void PointNode::readElement(Context* context, MsooXmlDiagramReader* reader) {
0303     if (reader->isStartElement()) {
0304         if (reader->qualifiedName() == QLatin1String("dgm:prSet")) {
0305             prSet[ QLatin1String( "dgm:prSet" ) ] = reader->attributes().value( "phldrT" ).toString();
0306         } else if (reader->qualifiedName() == QLatin1String("dgm:spPr")) {
0307             //TODO
0308         } else if (reader->qualifiedName() == QLatin1String("dgm:t")) {
0309             readTextBody(context, reader);
0310         }
0311     }
0312 }
0313 
0314 void MSOOXML::Diagram::ConnectionNode::dump(QTextStream& device) {
0315     foreach(AbstractNode* node, peers() ) {
0316         ConnectionNode* connNode = dynamic_cast< ConnectionNode* > ( node );
0317         PointNode* pointNode = dynamic_cast< PointNode* > ( node );
0318         if ( connNode )
0319             device << "\"" << m_tagName << m_modelId << "\" -> \"" << connNode->m_tagName << connNode->m_modelId << "\"\n";
0320         else if ( pointNode )
0321             device << "\"" << m_tagName << m_modelId << "\" -> \"" << pointNode->m_tagName << pointNode->m_modelId << "\"\n";
0322     }
0323     foreach(AbstractNode* node, children()) {
0324         ConnectionNode* connNode = dynamic_cast< ConnectionNode* > ( node );
0325         PointNode* pointNode = dynamic_cast< PointNode* > ( node );
0326         if ( connNode )
0327             device << "\"" << m_tagName << m_modelId << "\" -> \"" << connNode->m_tagName << connNode->m_modelId << "\"\n";
0328         else if ( pointNode )
0329             device << "\"" << m_tagName << m_modelId << "\" -> \"" << pointNode->m_tagName << pointNode->m_modelId << "\"\n";
0330     }
0331     MSOOXML::Diagram::AbstractNode::dump(device);
0332 }
0333 
0334 void PointNode::readAll(Context* context, MsooXmlDiagramReader* reader) {
0335     const QXmlStreamAttributes attrs(reader->attributes());
0336     TRY_READ_ATTR_WITHOUT_NS_INTO(modelId, m_modelId)
0337     TRY_READ_ATTR_WITHOUT_NS_INTO(type, m_type)
0338     if (m_type.isEmpty()) m_type = "node";
0339     if (m_type == QLatin1String("parTrans") || m_type == QLatin1String("sibTrans"))
0340         TRY_READ_ATTR_WITHOUT_NS_INTO(cxnId, m_cxnId)
0341     else
0342         m_cxnId.clear();
0343     AbstractNode::readAll(context, reader);
0344 }
0345 
0346 void PointNode::readTextBody(Context*, MsooXmlDiagramReader* reader) {
0347     //m_text.clear();
0348     enum { Start, Paragraph, TextRun } s;
0349     s = Start;
0350     while (!reader->atEnd()) {
0351         reader->readNext();
0352         if(reader->isEndElement() && reader->qualifiedName() == QLatin1String("dgm:t")) break;
0353         switch(s) {
0354             case Start:
0355                 if (reader->isStartElement() && reader->qualifiedName() == QLatin1String("a:p")) s = Paragraph;
0356                 break;
0357             case Paragraph:
0358                 if (reader->qualifiedName() == QLatin1String("a:r")) // text run
0359                 s = reader->isStartElement() ? TextRun : Start;
0360             break;
0361             case TextRun:
0362                 if (reader->qualifiedName() == QLatin1String("a:t")) {
0363                     if(reader->isStartElement()) {
0364                         if(!m_text.isEmpty()) m_text += ' '; // concat multiple strings into one result
0365                         m_text += reader->readElementText();
0366                     } else
0367                         s = Paragraph;
0368                 }
0369                 break;
0370         }        
0371     }
0372     if ( m_text.isEmpty() )
0373         m_text = prSet.value( QLatin1String("dgm:prSet") );
0374 }
0375 
0376 /****************************************************************************************************/
0377 
0378 void PointListNode::dump(Context* context, int level) {
0379     //DEBUG_DUMP;
0380     AbstractNode::dump(context, level);
0381 }
0382 
0383 void PointListNode::dump( QTextStream& device ) {
0384     AbstractNode::dump( device );
0385 }
0386 
0387 /****************************************************************************************************/
0388 
0389 void PointListNode::readElement(Context* context, MsooXmlDiagramReader* reader) {
0390     if (reader->isStartElement()) {
0391         if (reader->qualifiedName() == QLatin1String("dgm:pt")) {
0392             PointNode *n = new PointNode;
0393             addChild(n);
0394             n->readAll(context, reader);
0395         }
0396     }
0397 }
0398 
0399 void ConnectionNode::dump(Context*, int level) {
0400     DEBUG_DUMP << "modelId=" << m_modelId << "type=" << m_type << "srcId=" << m_srcId << "destId=" << m_destId;
0401     //AbstractNode::dump(context, level);
0402 }
0403 
0404 void MSOOXML::Diagram::PointNode::dump(QTextStream& device) {
0405     foreach(AbstractNode* node, peers() ) {
0406         ConnectionNode* connNode = dynamic_cast< ConnectionNode* > ( node );
0407         PointNode* pointNode = dynamic_cast< PointNode* > ( node );
0408         if ( connNode )
0409             device << "\"" << m_tagName << m_modelId << "\" -> \"" << connNode->m_tagName << connNode->m_modelId << "\"[label=\"" << /*m_tagName << m_modelId << " " <<*/ m_text << "\"]\n";
0410         else if ( pointNode )
0411             device << "\"" << m_tagName << m_modelId << "\" -> \"" << pointNode->m_tagName << pointNode->m_modelId << "\"[label=\"" << /*m_tagName << m_modelId << " " <<*/ m_text << "\"]\n";
0412     }
0413     foreach(AbstractNode* node, children()) {
0414         ConnectionNode* connNode = dynamic_cast< ConnectionNode* > ( node );
0415         PointNode* pointNode = dynamic_cast< PointNode* > ( node );
0416         if ( connNode )
0417             device << "\"" << m_tagName << m_modelId << "\" -> \"" << connNode->m_tagName << connNode->m_modelId << "\"[label=\"" << /*m_tagName << m_modelId << " " <<*/ m_text << "\"]\n";
0418         else if ( pointNode )
0419             device << "\"" << m_tagName << m_modelId << "\" -> \"" << pointNode->m_tagName << pointNode->m_modelId << "\"[label=\"" << /*m_tagName << m_modelId << " " <<*/ m_text << "\"]\n";
0420     }
0421     MSOOXML::Diagram::AbstractNode::dump(device);
0422 }
0423 
0424 void ConnectionNode::readElement(Context* context, MsooXmlDiagramReader* reader) {
0425     if (reader->isStartElement()) {
0426         if (reader->qualifiedName() == QLatin1String("dgm:cxn")) {
0427             ConnectionNode *n = new ConnectionNode;
0428             addChild(n);
0429             n->readAll(context, reader);
0430         }
0431     }
0432 }
0433 
0434 void ConnectionNode::readAll(Context* context, MsooXmlDiagramReader* reader) {
0435     const QXmlStreamAttributes attrs(reader->attributes());
0436     TRY_READ_ATTR_WITHOUT_NS_INTO(modelId, m_modelId)
0437     TRY_READ_ATTR_WITHOUT_NS_INTO(type, m_type)
0438     if (m_type.isEmpty()) m_type = "parOf";
0439     TRY_READ_ATTR_WITHOUT_NS_INTO(srcId, m_srcId)
0440     TRY_READ_ATTR_WITHOUT_NS_INTO(destId, m_destId)
0441     TRY_READ_ATTR_WITHOUT_NS_INTO(presId, m_presId)
0442     TRY_READ_ATTR_WITHOUT_NS_INTO(parTransId, m_parTransId)
0443     TRY_READ_ATTR_WITHOUT_NS_INTO(sibTransId, m_sibTransId)
0444     TRY_READ_ATTR_WITHOUT_NS(srcOrd)
0445     TRY_READ_ATTR_WITHOUT_NS(destOrd)
0446     m_srcOrd = srcOrd.toInt();
0447     m_destOrd = destOrd.toInt();
0448     AbstractNode::readAll(context, reader);
0449 }
0450 
0451 /****************************************************************************************************/
0452 
0453 void ConnectionListNode::dump(Context* context, int level) {
0454     //DEBUG_DUMP;
0455     AbstractNode::dump(context, level);
0456 }
0457 
0458 void ConnectionListNode::dump( QTextStream& device ) {
0459     //DEBUG_DUMP;
0460     AbstractNode::dump( device );
0461 }
0462 
0463 void ConnectionListNode::readElement(Context* context, MsooXmlDiagramReader* reader) {
0464     if (reader->isStartElement()) {
0465         if (reader->qualifiedName() == QLatin1String("dgm:cxn")) {
0466             ConnectionNode *n = new ConnectionNode;
0467             addChild(n);
0468             n->readAll(context, reader);
0469         }
0470     }
0471 }
0472 
0473 /****************************************************************************************************/
0474 
0475 AbstractAtom::AbstractAtom(const QString &tagName) : QSharedData(), m_tagName(tagName) {}
0476 AbstractAtom::~AbstractAtom() {}
0477 
0478 void AbstractAtom::dump(Context* context, int level) {
0479     //DEBUG_DUMP;
0480     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, m_children) {
0481         atom->dump(context, level + 1);
0482     }
0483 }
0484 
0485 void AbstractAtom::readElement(Context* context, MsooXmlDiagramReader* reader) {
0486     if (reader->isStartElement()) {
0487         AbstractAtom *node = 0;
0488 
0489         if (reader->qualifiedName() == QLatin1String("dgm:layoutNode")) {
0490             node = new LayoutNodeAtom;
0491         } else if (reader->qualifiedName() == QLatin1String("dgm:shape")) {
0492             node = new ShapeAtom;
0493         } else if (reader->qualifiedName() == QLatin1String("dgm:alg")) {
0494             node = new AlgorithmAtom;
0495         } else if (reader->qualifiedName() == QLatin1String("dgm:presOf")) {
0496             node = new PresentationOfAtom;
0497         } else if (reader->qualifiedName() == QLatin1String("dgm:choose")) {
0498             node = new ChooseAtom;
0499         } else if (reader->qualifiedName() == QLatin1String("dgm:forEach")) {
0500             node = new ForEachAtom;
0501         } else if (reader->qualifiedName() == QLatin1String("dgm:constrLst")) {
0502             node = new ListAtom(reader->qualifiedName());
0503         } else if (reader->qualifiedName() == QLatin1String("dgm:ruleLst")) {
0504             node = new ListAtom(reader->qualifiedName());
0505         } else if (reader->qualifiedName() == QLatin1String("dgm:adj")) {
0506             node = new AdjustAtom;
0507         } else if (reader->qualifiedName() == QLatin1String("dgm:adjLst")) {
0508             node = new ListAtom(reader->qualifiedName());
0509         } else if (reader->qualifiedName() == QLatin1String("dgm:varLst")) {
0510             while (!reader->atEnd()) {
0511                 QXmlStreamReader::TokenType tokenType = reader->readNext();
0512                 if(tokenType == QXmlStreamReader::Invalid || tokenType == QXmlStreamReader::EndDocument) break;
0513                 if(!reader->isStartElement() && reader->qualifiedName() == "dgm:varLst") break;
0514                 if(reader->isStartElement()) {
0515                     const QXmlStreamAttributes attrs(reader->attributes());
0516                     TRY_READ_ATTR_WITHOUT_NS(val)
0517                     context->m_parentLayout->setVariable(reader->name().toString(), val);
0518                 }
0519             }
0520         } else {
0521             debugMsooXml<<"TODO atom="<<m_tagName<<"qualifiedName="<<reader->qualifiedName();
0522         }
0523         
0524         if (node) {
0525             QExplicitlySharedDataPointer<AbstractAtom> ptr(node);
0526             addChild(ptr);
0527             ptr->readAll(context, reader);
0528         }
0529     }
0530 }
0531 
0532 void AbstractAtom::readAll(Context* context, MsooXmlDiagramReader* reader) {
0533     while (!reader->atEnd()) {
0534         QXmlStreamReader::TokenType tokenType = reader->readNext();
0535         if(tokenType == QXmlStreamReader::Invalid || tokenType == QXmlStreamReader::EndDocument) break;
0536         if(!reader->isStartElement() && reader->qualifiedName() == m_tagName) break;
0537         readElement(context, reader);
0538     }
0539 }
0540 
0541 void AbstractAtom::build(Context* context) {
0542     //typedef QList< QExplicitlySharedDataPointer< AbstractAtom > > SharedAtomList;
0543     //for( int i = 0; i < m_children.count(); ++i ) m_children[ i ]->build( context );
0544     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, m_children) {
0545         atom->build(context);
0546     }
0547 }
0548 
0549 void AbstractAtom::finishBuild(Context* context) {
0550     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, m_children) {
0551         atom->finishBuild(context);
0552     }
0553 }
0554 
0555 void AbstractAtom::layoutAtom(Context* context) {
0556     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, m_children) {
0557         if (LayoutNodeAtom* layAtom = dynamic_cast< LayoutNodeAtom* >( atom.data() ))
0558             layAtom->setNeedsRelayout( true );
0559         atom->layoutAtom(context);
0560     }
0561 }
0562 
0563 void AbstractAtom::writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles) {
0564     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, m_children)
0565         atom->writeAtom(context, xmlWriter, styles);
0566 }
0567 
0568 QExplicitlySharedDataPointer<LayoutNodeAtom> AbstractAtom::parentLayout() const {
0569     LayoutNodeAtom* p = 0;
0570     for(QExplicitlySharedDataPointer<AbstractAtom> a = parent(); a && !p; a = a->parent())
0571         p = dynamic_cast<LayoutNodeAtom*>(a.data());
0572     return QExplicitlySharedDataPointer<LayoutNodeAtom>(p);
0573 }
0574 
0575 QExplicitlySharedDataPointer<AbstractAtom> AbstractAtom::parent() const {
0576     return m_parent;
0577 } 
0578 
0579 QVector< QExplicitlySharedDataPointer<AbstractAtom> > AbstractAtom::children() const {
0580     return m_children;
0581 }
0582 
0583 int AbstractAtom::indexOfChild(AbstractAtom* node) const {
0584     for ( int i = 0; i < m_children.count(); ++i )
0585         if ( m_children[ i ].data() == node )
0586             return i;
0587     return -1;
0588 }
0589 
0590 void AbstractAtom::addChild(AbstractAtom* node) {
0591     addChild(QExplicitlySharedDataPointer<AbstractAtom>(node));
0592 }
0593 
0594 void AbstractAtom::addChild(QExplicitlySharedDataPointer<AbstractAtom> node) {
0595     node->m_parent = this;
0596     m_children.append(node);
0597 }
0598 
0599 void AbstractAtom::insertChild(int index, AbstractAtom* node) {
0600     insertChild(index, QExplicitlySharedDataPointer<AbstractAtom>(node));
0601 }
0602 
0603 void AbstractAtom::insertChild(int index, QExplicitlySharedDataPointer<AbstractAtom> node) {
0604     node->m_parent = this;
0605     if ( index < m_children.count() )
0606       m_children.insert(index, node);
0607     else
0608       m_children.append( node );
0609 }
0610 
0611 void AbstractAtom::removeChild(QExplicitlySharedDataPointer<AbstractAtom> node) {
0612     const int index = m_children.indexOf(node);
0613     Q_ASSERT(index >= 0);
0614     m_children.remove(index);
0615     node->m_parent = QExplicitlySharedDataPointer<AbstractAtom>();
0616 }
0617 
0618 QList<AbstractNode*> AbstractAtom::fetchAxis(Context* context, const QString& _axis, const QString &_ptType, const QString& _start, const QString& _count, const QString& _step) const {
0619     const QStringList axisList = _axis.split(' ', QString::SkipEmptyParts);
0620     const QStringList typeList = _ptType.split(' ', QString::SkipEmptyParts);
0621     const QStringList startList = _start.split(' ', QString::SkipEmptyParts);
0622     const QStringList countList = _count.split(' ', QString::SkipEmptyParts);
0623     const QStringList stepList = _step.split(' ', QString::SkipEmptyParts);
0624     QList<AbstractNode*> result;
0625     Q_ASSERT(context->currentNode());
0626     result << context->currentNode();
0627     for(int i = 0; i < axisList.count(); ++i) {
0628         result = fetchAxis(context, result, axisList[i], typeList.value(i), startList.value(i), countList.value(i), stepList.value(i));
0629     }
0630     return result;
0631 }
0632 
0633 QList<AbstractNode*> AbstractAtom::fetchAxis(Context* context, QList<AbstractNode*> list, const QString& axis, const QString &ptType, const QString& start, const QString& count, const QString& step) const {
0634     QList<AbstractNode*> result;
0635 
0636     // fill the result-list according to the defined axis value
0637     foreach(AbstractNode* node, list) {
0638         if(axis == QLatin1String("ancst")) { // Ancestor
0639             for(AbstractNode* n = node; n; n = n->parent())
0640                 result.append(n);
0641         } else if(axis == QLatin1String("ancstOrSelf")) { // Ancestor Or Self
0642             for(AbstractNode* n = node; n; n = n->parent())
0643                 result.append(n);
0644             result.append(node);
0645         } else if(axis == QLatin1String("ch")) { // Children
0646             foreach(AbstractNode* n, node->children())
0647                 result.append(n);
0648         } else if(axis == QLatin1String("des")) { // Descendant
0649             foreach(AbstractNode* n, node->descendant())
0650                 result.append(n);
0651         } else if(axis == QLatin1String("desOrSelf")) { // Descendant Or Self
0652             foreach(AbstractNode* n, node->descendant())
0653                 result.append(n);
0654             result.append(node);
0655         } else if(axis == QLatin1String("follow")) { // Follow
0656             foreach(AbstractNode* peer, node->peers()) {
0657                 result.append(peer);
0658                 foreach(AbstractNode* n, peer->descendant())
0659                     result.append(n);
0660             }
0661         } else if(axis == QLatin1String("followSib")) { // Follow Sibling
0662             foreach(AbstractNode* n, node->peers())
0663                 result.append(n);
0664         } else if(axis == QLatin1String("par")) { // Parent
0665             if (AbstractNode* n = node->parent())
0666                 result.append(n);
0667         } else if(axis == QLatin1String("preced")) { // Preceding
0668             warnMsooXml<<"TODO preced";
0669             //TODO
0670         } else if(axis == QLatin1String("precedSib")) { // Preceding Sibling
0671             warnMsooXml<<"TODO precedSib";
0672             //TODO
0673         } else if(axis == QLatin1String("root")) { // Root
0674             result.append(context->m_rootPoint);
0675         } else if(axis == QLatin1String("self")) { // Self
0676             result.append(node);
0677         }
0678     }
0679 
0680     // optionally filter the list
0681     if(!ptType.isEmpty()) {
0682         QList<AbstractNode*> list = result;
0683         result.clear();
0684         foreach(AbstractNode* node, list) {
0685             if(PointNode* pt = dynamic_cast<PointNode*>(node)) {
0686                 if(ptType == pt->m_type || ptType == "all" || (ptType == "nonAsst" && pt->m_type != "asst" ) || (ptType == "nonNorm" && pt->m_type != "norm")) {
0687                     result.append(pt);
0688                 }
0689             }
0690         }
0691     }
0692 
0693     // evaluate optional forEach-conditions
0694     if(!start.isEmpty() || !count.isEmpty() || !step.isEmpty()) {
0695         const int _start = start.isEmpty() ? 1 : start.toInt();
0696         const int _count = count.isEmpty() ? 0 : count.toInt();
0697         const int _step =  step.isEmpty() ? 1 : step.toInt();
0698         result = foreachAxis(context, result, _start, _count, _step);
0699     }
0700 
0701     return result;
0702 }
0703 
0704 QList<AbstractNode*> AbstractAtom::foreachAxis(Context*, const QList<AbstractNode*> &list, int start, int count, int step) const {
0705     QList<AbstractNode*> result;
0706     const int _start = qMax(0, start - 1);
0707     const int _step = qMax(1, step);
0708     for(int i = _start; i < list.count(); i += _step) {
0709         result.append(list[i]);
0710         if(/*count > 0 &&*/ result.count() == count) break;
0711     }
0712     return result;
0713 }
0714 
0715 /****************************************************************************************************/
0716 
0717 AlgorithmAtom* AlgorithmAtom::clone(Context* context) {
0718     AlgorithmAtom* atom = new AlgorithmAtom;
0719     atom->m_type = m_type;
0720     atom->m_params = m_params;
0721     foreach(QExplicitlySharedDataPointer<AbstractAtom> a, m_children)
0722         atom->addChild(a->clone(context));
0723     return atom;
0724 }
0725 
0726 void AlgorithmAtom::dump(Context* context, int level) {
0727     DEBUG_DUMP << "type=" << typeAsString() << "params=" << m_params;
0728     AbstractAtom::dump(context, level);
0729 }
0730 
0731 void AlgorithmAtom::readAll(Context* context, MsooXmlDiagramReader* reader) {
0732     const QXmlStreamAttributes attrs(reader->attributes());
0733     TRY_READ_ATTR_WITHOUT_NS(type)
0734     if(type == QLatin1String("composite")) m_type = CompositeAlg;
0735     else if(type == QLatin1String("conn")) m_type = ConnectorAlg;
0736     else if(type == QLatin1String("cycle")) m_type = CycleAlg;
0737     else if(type == QLatin1String("hierChild")) m_type = HierChildAlg;
0738     else if(type == QLatin1String("hierRoot")) m_type = HierRootAlg;
0739     else if(type == QLatin1String("lin")) m_type = LinearAlg;
0740     else if(type == QLatin1String("pyra")) m_type = PyramidAlg;
0741     else if(type == QLatin1String("snake")) m_type = SnakeAlg;
0742     else if(type == QLatin1String("sp")) m_type = SpaceAlg;
0743     else if(type == QLatin1String("tx")) m_type = TextAlg;
0744     else m_type = UnknownAlg;
0745     AbstractAtom::readAll(context, reader);
0746 }
0747 
0748 void AlgorithmAtom::readElement(Context*, MsooXmlDiagramReader* reader) {
0749     if (reader->isStartElement()) {
0750         if (reader->qualifiedName() == QLatin1String("dgm:param")) {
0751             const QXmlStreamAttributes attrs(reader->attributes());
0752             TRY_READ_ATTR_WITHOUT_NS(type)
0753             TRY_READ_ATTR_WITHOUT_NS(val)
0754             m_params[type] = val;
0755         }
0756     }
0757 }
0758 
0759 QString AlgorithmAtom::typeAsString() const {
0760     QString s;
0761     switch(m_type) {
0762         case UnknownAlg: s = "Unknown"; break;
0763         case CompositeAlg: s = "Composite"; break;
0764         case ConnectorAlg: s = "Connector"; break;
0765         case CycleAlg: s = "Cycle"; break;
0766         case HierChildAlg: s = "HierChild"; break;
0767         case HierRootAlg: s = "HierRoot"; break;
0768         case LinearAlg: s = "Linear"; break;
0769         case PyramidAlg: s = "Pyramid"; break;
0770         case SnakeAlg: s = "Snake"; break;
0771         case SpaceAlg: s = "Space"; break;
0772         case TextAlg: s = "Text"; break;
0773     }
0774     return s;
0775 }
0776 
0777 /****************************************************************************************************/
0778 
0779 LayoutNodeAtom* LayoutNodeAtom::clone(Context* context) {
0780     LayoutNodeAtom* atom = new LayoutNodeAtom;
0781     atom->m_name = m_name;
0782     atom->m_values = m_values;
0783     atom->m_factors = m_factors;
0784     atom->m_countFactors = m_countFactors;
0785     foreach(QExplicitlySharedDataPointer<AbstractAtom> a, m_children)
0786         atom->addChild(a->clone(context));
0787     atom->m_rotateAngle = m_rotateAngle;
0788     atom->m_needsReinit = m_needsReinit;
0789     atom->m_needsRelayout = m_needsRelayout;
0790     atom->m_childNeedsRelayout = m_childNeedsRelayout;
0791     atom->m_variables = m_variables;
0792     atom->m_firstLayout = m_firstLayout;
0793     atom->setAxis(context, axis( context ));
0794     return atom;
0795 }
0796 
0797 void LayoutNodeAtom::dump(Context* context, int level) {
0798     QStringList list;
0799     foreach(AbstractNode* n, axis( context ))
0800         if(PointNode* p = dynamic_cast<PointNode*>(n))
0801             list.append( QString("modelId=%1 type=%2 cxnId=%3").arg(p->m_modelId).arg(p->m_type).arg(p->m_cxnId) );
0802         else
0803             list.append( QString("tagName=%1").arg(n->m_tagName) );
0804     //DEBUG_DUMP << "name=" << m_name << "variables=" << m_variables << "values=" << finalValues();
0805     DEBUG_DUMP << "name=" << m_name << list;
0806     AbstractAtom::dump(context, level);
0807 }
0808 
0809 void LayoutNodeAtom::readAll(Context* context, MsooXmlDiagramReader* reader) {
0810     const QXmlStreamAttributes attrs(reader->attributes());
0811     TRY_READ_ATTR_WITHOUT_NS_INTO(name, m_name)
0812     //TRY_READ_ATTR_WITHOUT_NS_INTO(styleLbl, m_styleLbl)
0813     QExplicitlySharedDataPointer<LayoutNodeAtom> ptr(this);
0814     QExplicitlySharedDataPointer<LayoutNodeAtom> oldLayout = context->m_parentLayout;
0815     context->m_parentLayout = ptr;
0816     AbstractAtom::readAll(context, reader);
0817     context->m_parentLayout = oldLayout;
0818 }
0819 
0820 /*
0821 class ConstraintPredicate
0822 {
0823     public:
0824         bool operator()( const QExplicitlySharedDataPointer<MSOOXML::Diagram::AbstractAtom> &value ) {
0825             ListAtom *atom = dynamic_cast< ListAtom* >( value.data() );
0826             if ( !atom )
0827                 return true;
0828             foreach( QExplicitlySharedDataPointer<AbstractAtom> val, atom->children() )
0829                 if ( dynamic_cast< ConstraintAtom* >( val.data() ) )
0830                     return false;
0831             return true;
0832         }
0833 };
0834 */
0835 
0836 void LayoutNodeAtom::build(Context* context) {
0837 #if 0
0838     QExplicitlySharedDataPointer<LayoutNodeAtom> oldLayout = context->m_parentLayout;
0839     context->m_parentLayout = this;
0840     context->m_layoutPointMap[ this ] = context->currentNode();
0841     typedef QVector< QExplicitlySharedDataPointer<AbstractAtom> > AtomPList;
0842     AtomPList::iterator it = std::stable_partition( m_children.begin(), m_children.end(), ConstraintPredicate() );
0843     std::copy( it, m_children.end(), std::back_inserter( m_constraintsToBuild ) );
0844     m_children.erase( it, m_children.end() );
0845     AbstractAtom::build(context);
0846     foreach( QExplicitlySharedDataPointer<AbstractAtom> constr, m_constraintsToBuild )
0847         constr->build( context );
0848     m_constraintsToBuild.clear();
0849     context->m_parentLayout = oldLayout;
0850 #else
0851     QExplicitlySharedDataPointer<LayoutNodeAtom> oldLayout = context->m_parentLayout;
0852     context->m_parentLayout = this;
0853     AbstractNode* oldCurrentNode = context->currentNode();
0854 
0855     AbstractAtom::build(context);
0856 
0857     context->setCurrentNode(oldCurrentNode);
0858     context->m_parentLayout = oldLayout;
0859 #endif
0860 }
0861 
0862 void LayoutNodeAtom::finishBuild(Context* context) {
0863     QExplicitlySharedDataPointer<LayoutNodeAtom> oldLayout = context->m_parentLayout;
0864     context->m_parentLayout = this;
0865     AbstractAtom::finishBuild(context);
0866     context->m_parentLayout = oldLayout;
0867     
0868     delete m_algorithmImpl;
0869     m_algorithmImpl = 0;
0870     QExplicitlySharedDataPointer<AlgorithmAtom> alg = algorithm();
0871     switch(alg ? alg->m_type : AlgorithmAtom::UnknownAlg) {
0872         case AlgorithmAtom::UnknownAlg:
0873             warnMsooXml << "Layout with name=" << m_name << "defines an unknown algorithm.";
0874             // fall through and use the composite-algorithm
0875         case AlgorithmAtom::CompositeAlg: m_algorithmImpl = new CompositeAlgorithm; break;
0876         case AlgorithmAtom::ConnectorAlg: m_algorithmImpl = new ConnectorAlgorithm; break;
0877         case AlgorithmAtom::CycleAlg: m_algorithmImpl = new CycleAlgorithm; break;
0878         case AlgorithmAtom::HierChildAlg: m_algorithmImpl = new HierarchyAlgorithm(false); break;
0879         case AlgorithmAtom::HierRootAlg: m_algorithmImpl = new HierarchyAlgorithm(true); break;
0880         case AlgorithmAtom::LinearAlg: m_algorithmImpl = new LinearAlgorithm; break;
0881         case AlgorithmAtom::PyramidAlg: m_algorithmImpl = new LinearAlgorithm; break;
0882         case AlgorithmAtom::SnakeAlg: m_algorithmImpl = new SnakeAlgorithm; break;
0883         case AlgorithmAtom::SpaceAlg: m_algorithmImpl = new SpaceAlg; break;
0884         case AlgorithmAtom::TextAlg: m_algorithmImpl = new TextAlgorithm; break;
0885     }
0886 }
0887 
0888 void LayoutNodeAtom::layoutAtom(Context* context) {
0889     if(m_algorithmImpl) {
0890         m_algorithmImpl->doInit(context, QExplicitlySharedDataPointer<LayoutNodeAtom>(this));
0891     }
0892     if(m_needsRelayout && m_algorithmImpl) {
0893         m_needsRelayout = false;
0894         m_childNeedsRelayout = true;
0895         m_algorithmImpl->doLayout();
0896     }
0897     if(m_childNeedsRelayout && m_algorithmImpl) {
0898         m_childNeedsRelayout = false;
0899         m_algorithmImpl->doLayoutChildren();
0900     }
0901 }
0902 
0903 void LayoutNodeAtom::writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles) {
0904     QExplicitlySharedDataPointer<LayoutNodeAtom> oldLayout = context->m_parentLayout;
0905     context->m_parentLayout = this;
0906     AbstractAtom::writeAtom(context, xmlWriter, styles);
0907     context->m_parentLayout = oldLayout;
0908 }
0909 
0910 QList< QExplicitlySharedDataPointer<ConstraintAtom> > LayoutNodeAtom::constraints() const {
0911     QList< QExplicitlySharedDataPointer<ConstraintAtom> > result;
0912     foreach( QExplicitlySharedDataPointer<AbstractAtom> atom, m_children )
0913     {
0914         ConstraintAtom* constraintAtom = dynamic_cast< ConstraintAtom* >( atom.data() );
0915         if ( constraintAtom ) {
0916             result.append( QExplicitlySharedDataPointer<ConstraintAtom>(constraintAtom));
0917         } else if (ListAtom *list = dynamic_cast< ListAtom* >( atom.data() ) ) {
0918             foreach( QExplicitlySharedDataPointer<AbstractAtom> val, list->children() ) {
0919                 constraintAtom =  dynamic_cast< ConstraintAtom* >( val.data() );
0920                 if ( constraintAtom )
0921                     result.append(QExplicitlySharedDataPointer<ConstraintAtom>(constraintAtom));
0922             }
0923         }
0924     }
0925     return result;
0926 }
0927 
0928 QList< QExplicitlySharedDataPointer<ShapeAtom> > LayoutNodeAtom::shapes() const {
0929     QList< QExplicitlySharedDataPointer<ShapeAtom> > result;
0930     foreach( QExplicitlySharedDataPointer<AbstractAtom> atom, m_children ) {
0931         ShapeAtom* shapeAtom = dynamic_cast< ShapeAtom* >( atom.data() );
0932         if ( shapeAtom ) {
0933             result.append(QExplicitlySharedDataPointer<ShapeAtom>(dynamic_cast< ShapeAtom* >( atom.data() )));
0934         } else if (ListAtom *list = dynamic_cast< ListAtom* >( atom.data() ) ) {
0935             foreach( QExplicitlySharedDataPointer<AbstractAtom> val, list->children() ) {
0936                 shapeAtom = dynamic_cast< ShapeAtom* >( val.data() );
0937                 if ( shapeAtom )
0938                     result.append(QExplicitlySharedDataPointer<ShapeAtom>(shapeAtom));
0939             }
0940         }
0941     }
0942     return result;
0943 }
0944 
0945 AbstractAlgorithm* LayoutNodeAtom::algorithmImpl() const {
0946     return m_algorithmImpl;
0947 }
0948 
0949 QExplicitlySharedDataPointer<AlgorithmAtom> LayoutNodeAtom::algorithm() const {
0950     foreach(QExplicitlySharedDataPointer<AbstractAtom> child, children())
0951         if(AlgorithmAtom* alg = dynamic_cast<AlgorithmAtom*>(child.data()))
0952             return QExplicitlySharedDataPointer<AlgorithmAtom>(alg);
0953     return QExplicitlySharedDataPointer<AlgorithmAtom>();
0954 }
0955 
0956 QList<AbstractNode*> LayoutNodeAtom::axis(Context* context) const {
0957     return context->m_layoutPointMap.values(this);
0958 }
0959 
0960 void LayoutNodeAtom::setAxis(Context* context, const QList<AbstractNode*> &axis) {
0961     Q_UNUSED(context);
0962     // first remove the previous axis
0963     foreach(AbstractNode* node, context->m_layoutPointMap.values(this)) {
0964         context->m_pointLayoutMap.remove(node, this);
0965     }
0966     context->m_layoutPointMap.remove(this);
0967     Q_ASSERT(!context->m_pointLayoutMap.values().contains(this));
0968     Q_ASSERT(!context->m_layoutPointMap.keys().contains(this));
0969     // then set the new axis
0970     foreach(AbstractNode* node, axis) {
0971         context->m_layoutPointMap.insertMulti(this, node);
0972         context->m_pointLayoutMap.insertMulti(node, this);
0973     }
0974     // job done, new layout needed
0975     setNeedsRelayout(true);
0976 }
0977 
0978 void LayoutNodeAtom::setAxis(Context* context, PresentationOfAtom* atom) {
0979     setAxis(context, fetchAxis(context, atom->m_axis, atom->m_ptType, atom->m_start, atom->m_count, atom->m_step));
0980 }
0981 
0982 void LayoutNodeAtom::setNeedsReinit(bool needsReinit) {
0983     if(m_needsReinit == needsReinit) return;
0984     m_needsReinit = needsReinit;
0985     if(m_needsReinit) // if we need to be re-initialized then our children need to be too
0986         foreach(QExplicitlySharedDataPointer<AbstractAtom> child, children())
0987             if(LayoutNodeAtom* childLayoutAtom = dynamic_cast<LayoutNodeAtom*>(child.data())) {
0988                 childLayoutAtom->setNeedsReinit(true);
0989             }
0990 }
0991 
0992 void LayoutNodeAtom::setNeedsRelayout(bool needsRelayout) {
0993     if(needsRelayout == m_needsRelayout) return;
0994     m_needsRelayout = needsRelayout;
0995     if(m_needsRelayout) // let parent-layouts know that we need a relayout
0996         if(QExplicitlySharedDataPointer<LayoutNodeAtom> p = parentLayout())
0997             p->m_childNeedsRelayout = true;
0998 }
0999 
1000 AlgorithmAtom::Algorithm LayoutNodeAtom::algorithmType() const {
1001     if(QExplicitlySharedDataPointer<AlgorithmAtom> alg = algorithm())
1002         return alg->m_type;
1003     return AlgorithmAtom::UnknownAlg;
1004 }
1005 
1006 QMap<QString,QString> LayoutNodeAtom::algorithmParams() const {
1007     if(QExplicitlySharedDataPointer<AlgorithmAtom> alg = algorithm())
1008         return alg->m_params;
1009     return QMap<QString,QString>();
1010 }
1011 
1012 QString LayoutNodeAtom::algorithmParam(const QString &name, const QString &defaultValue) const {
1013     QMap<QString,QString> params = algorithmParams();
1014     return params.contains(name) ? params[name] : defaultValue;
1015 }
1016 
1017 QString LayoutNodeAtom::variable(const QString &name, bool checkParents) const {
1018     if(m_variables.contains(name))
1019         return m_variables[name];
1020     if(checkParents)
1021         if(QExplicitlySharedDataPointer<LayoutNodeAtom> p = parentLayout())
1022             return p->variable(name, checkParents);
1023     return QString();
1024 }
1025 
1026 QMap<QString, QString> LayoutNodeAtom::variables() const { return m_variables; }
1027 void LayoutNodeAtom::setVariable(const QString &name, const QString &value) { m_variables[name] = value; }
1028 
1029 QMap<QString, qreal> LayoutNodeAtom::finalValues() const {
1030     //TODO cache
1031     //debugMsooXml << m_name;
1032     ValueCache result = m_values;
1033     //QMap< QString, qreal > print = m_values;
1034     //debugMsooXml << "prefinal: " << print;
1035     //debugMsooXml << "final values";
1036     for( QMap< QString, qreal>::const_iterator it = m_factors.constBegin(); it != m_factors.constEnd(); ++it ) {
1037         result[ it.key() ] = result[ it.key() ] * it.value() / qreal ( m_countFactors[ it.key() ] );        
1038         //debugMsooXml << "key " << it.key() << " value: " << it.value() << " count: " << m_countFactors[ it.key() ];
1039     }
1040     //debugMsooXml << "end of final values";
1041     return result;
1042 }
1043 
1044 QVector< QExplicitlySharedDataPointer<LayoutNodeAtom> > LayoutNodeAtom::fetchLayouts(Context* context, const QString &forAxis, const QString &forName, const QString &ptType) const {
1045     QVector< QExplicitlySharedDataPointer<LayoutNodeAtom> > list;
1046     if ( forAxis == "self" || forAxis.isEmpty() ) {
1047         list.append( QExplicitlySharedDataPointer<LayoutNodeAtom>(const_cast<LayoutNodeAtom*>(this)) );
1048     } else {
1049         if ( forAxis == "ch" ) { // Children
1050             list = childrenLayouts();
1051         } else if ( forAxis == "des" ) { // Descendant
1052             list = descendantLayouts();
1053         } else {
1054             ASSERT_X(false, QString("Unsupported forAxis '%1'").arg( forAxis ).toLocal8Bit());
1055         }
1056     }
1057     QVector< QExplicitlySharedDataPointer<LayoutNodeAtom> > result;
1058     foreach(const QExplicitlySharedDataPointer<LayoutNodeAtom> &l, list) {
1059         if (!forName.isEmpty() && forName != l->m_name) {
1060             continue;
1061         }
1062         if (!ptType.isEmpty()) {
1063             bool ptTypeMatches = false;
1064             foreach(AbstractNode* node, l->axis( context )) {
1065                 if ( PointNode *ptNode = dynamic_cast< PointNode* >( node ) ) {
1066                     if (ptType != ptNode->m_type)
1067                         continue;
1068                 } else if ( ConnectionNode *connNode = dynamic_cast< ConnectionNode* >( node ) ) {
1069                     if (ptType != connNode->m_type)
1070                         continue;
1071                 }
1072                 ptTypeMatches = true;
1073                 break;
1074             }
1075             if (!ptTypeMatches) {
1076                 continue;
1077             }
1078         }
1079         result.append(l);
1080     }
1081     return result;
1082 }
1083 
1084 QVector< QExplicitlySharedDataPointer<LayoutNodeAtom> > LayoutNodeAtom::childrenLayouts() const {
1085     QVector< QExplicitlySharedDataPointer<LayoutNodeAtom> > result;
1086     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, children())
1087         if(LayoutNodeAtom* l = dynamic_cast<LayoutNodeAtom*>(atom.data()))
1088             result.append(QExplicitlySharedDataPointer<LayoutNodeAtom>(l));
1089     return result;
1090 }
1091 
1092 QVector< QExplicitlySharedDataPointer<LayoutNodeAtom> > LayoutNodeAtom::descendantLayouts() const {
1093     QVector< QExplicitlySharedDataPointer<LayoutNodeAtom> > result = childrenLayouts();
1094     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, children())
1095         if(LayoutNodeAtom* l = dynamic_cast<LayoutNodeAtom*>(atom.data()))
1096             foreach(QExplicitlySharedDataPointer<LayoutNodeAtom> atom, l->descendantLayouts())
1097                 result.append(atom);
1098     return result;
1099 }
1100         
1101 QPair<LayoutNodeAtom*,LayoutNodeAtom*> LayoutNodeAtom::neighbors() const {
1102     QExplicitlySharedDataPointer<LayoutNodeAtom> parentlayout = parentLayout();
1103     Q_ASSERT(parentlayout);
1104     QList<LayoutNodeAtom*> siblingLayouts;
1105     int myindex = -1;
1106     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, parent()->children()) {
1107         if(LayoutNodeAtom* l = dynamic_cast<LayoutNodeAtom*>(atom.data())) {
1108             if(l == this) myindex = siblingLayouts.count();
1109             siblingLayouts.append(l);
1110         }
1111     }
1112     Q_ASSERT(myindex >= 0); // our parent should know about us else something is fundamental broken
1113     if(siblingLayouts.count() < 3) // if we don't have enough neighbors then abort and return NULL for both
1114         return QPair<LayoutNodeAtom*,LayoutNodeAtom*>(0,0);
1115 
1116     // Look if our index is the first or last in the list and if that's the case then wrap around the list
1117     // if the used algorithm-type is expected to produced a "circle".
1118     int srcIndex = myindex - 1;
1119     int dstIndex = myindex + 1;
1120     if(srcIndex < 0) {
1121         if(parentlayout->algorithmType() != AlgorithmAtom::CycleAlg)
1122             return QPair<LayoutNodeAtom*,LayoutNodeAtom*>(0,0);
1123         srcIndex = siblingLayouts.count() - 1;
1124     }
1125     if(dstIndex < siblingLayouts.count()) {
1126         --myindex;
1127     } else {
1128         if(parentlayout->algorithmType() != AlgorithmAtom::CycleAlg)
1129             return QPair<LayoutNodeAtom*,LayoutNodeAtom*>(0,0);
1130         dstIndex = 0;
1131     }
1132 
1133     LayoutNodeAtom* srcAtom = siblingLayouts[srcIndex];
1134     LayoutNodeAtom* dstAtom = siblingLayouts[dstIndex];
1135     return QPair<LayoutNodeAtom*,LayoutNodeAtom*>(srcAtom,dstAtom);
1136 }
1137 
1138 QSizeF LayoutNodeAtom::childrenUsedSize() const {
1139     qreal w = 0;
1140     qreal h = 0;
1141     foreach( const QExplicitlySharedDataPointer<LayoutNodeAtom> &l, childrenLayouts() ) {
1142         QMap< QString, qreal > vals = l->finalValues();
1143         if ( l->algorithmType() != AlgorithmAtom::SpaceAlg ) {
1144             h += vals[ "h" ];
1145             w += vals[ "w" ];
1146         }
1147     }
1148     return QSizeF(w, h);
1149 }
1150 
1151 QSizeF LayoutNodeAtom::childrenTotalSize() const {
1152     qreal w = 0;
1153     qreal h = 0;
1154     foreach( const QExplicitlySharedDataPointer<LayoutNodeAtom> &l, childrenLayouts() ) {
1155         QMap< QString, qreal > vals = l->finalValues();
1156         h += vals[ "h" ];
1157         w += vals[ "w" ];
1158     }
1159     return QSizeF(w, h);
1160 }
1161 
1162 qreal LayoutNodeAtom::distanceTo(LayoutNodeAtom* otherAtom) const {
1163     //TODO specs are missing details from which exact point to calc the distance from...
1164 #if 0
1165     QMap<QString, qreal> srcValues = this->m_values;
1166     QMap<QString, qreal> dstValues = otherAtom->m_values;
1167     //QMap<QString, qreal> srcFactors = this->m_factors;
1168     //QMap<QString, qreal> dstFactors = otherAtom->m_factors;
1169     //QMap<QString, int> srcCountFactors = this->m_countFactors;
1170     //QMap<QString, int> dstCountFactors = otherAtom->m_countFactors;
1171 #else
1172     QMap<QString, qreal> srcValues = this->finalValues();
1173     QMap<QString, qreal> dstValues = otherAtom->finalValues();
1174 #endif
1175     qreal srcX = srcValues["l"];// + srcValues["ctrX"];
1176     qreal srcY = srcValues["t"];// + srcValues["ctrY"];
1177     qreal dstX = dstValues["l"];// + dstValues["ctrX"];
1178     qreal dstY = dstValues["t"];// + dstValues["ctrY"];
1179     // qreal srcX = srcValues["l"] + srcValues["ctrX"] + srcValues["w"] / 2;
1180     // qreal srcY = srcValues["t"] + srcValues["ctrY"] + srcValues["h"] / 2;
1181     // qreal dstX = dstValues["l"] + dstValues["ctrX"] + dstValues["w"] / 2;
1182     // qreal dstY = dstValues["t"] + dstValues["ctrY"] + dstValues["h"] / 2;
1183     qreal diffX = dstX - srcX;
1184     qreal diffY = dstY - srcY;
1185     //qreal diffX = dstX - srcX - srcValues["w"]/2 - dstValues["w"] / 2;
1186     //qreal diffY = dstY - srcY - srcValues["h"]/2 - dstValues["h"] / 2;
1187     return sqrt(diffX*diffX + diffY*diffY);
1188 }
1189 
1190 /****************************************************************************************************/
1191 
1192 ConstraintAtom* ConstraintAtom::clone(Context* context) {
1193     ConstraintAtom* atom = new ConstraintAtom;
1194     atom->m_fact = m_fact;
1195     atom->m_for = m_for;
1196     atom->m_forName = m_forName;
1197     atom->m_op = m_op;
1198     atom->m_ptType = m_ptType;
1199     atom->m_refPtType = m_refPtType;
1200     atom->m_refType = m_refType;
1201     atom->m_refFor = m_refFor;
1202     atom->m_refForName = m_refForName;
1203     atom->m_type = m_type;
1204     atom->m_value = m_value;
1205     foreach(QExplicitlySharedDataPointer<AbstractAtom> a, m_children)
1206         atom->addChild(a->clone(context));
1207     return atom;
1208 }
1209 
1210 QString ConstraintAtom::dump() const {
1211     QString s;
1212     if(!m_fact.isEmpty()) s += QString("fact=%1 ").arg(m_fact);
1213     if(!m_for.isEmpty()) s += QString("for=%1 ").arg(m_for);
1214     if(!m_forName.isEmpty()) s += QString("forName=%1 ").arg(m_forName);
1215     if(!m_op.isEmpty()) s += QString("op=%1 ").arg(m_op);
1216     if(!m_ptType.isEmpty()) s += QString("ptType=%1 ").arg(m_ptType);
1217     if(!m_refPtType.isEmpty()) s += QString("refPtType=%1 ").arg(m_refPtType);
1218     if(!m_refType.isEmpty()) s += QString("refType=%1 ").arg(m_refType);
1219     if(!m_refFor.isEmpty()) s += QString("refFor=%1 ").arg(m_refFor);
1220     if(!m_refForName.isEmpty()) s += QString("refForName=%1 ").arg(m_refForName);
1221     if(!m_type.isEmpty()) s += QString("type=%1 ").arg(m_type);
1222     if(!m_value.isEmpty()) s += QString("val=%1 ").arg(m_value);
1223     return s.trimmed();
1224 }
1225 
1226 void ConstraintAtom::dump(Context*, int level) {
1227     DEBUG_DUMP << dump();
1228 }
1229 
1230 void ConstraintAtom::readAll(Context*, MsooXmlDiagramReader* reader) {
1231     const QXmlStreamAttributes attrs(reader->attributes());
1232     TRY_READ_ATTR_WITHOUT_NS_INTO(fact, m_fact)
1233     TRY_READ_ATTR_WITHOUT_NS_INTO(for, m_for)
1234     TRY_READ_ATTR_WITHOUT_NS_INTO(forName, m_forName)
1235     TRY_READ_ATTR_WITHOUT_NS_INTO(op, m_op)
1236     TRY_READ_ATTR_WITHOUT_NS_INTO(ptType, m_ptType)
1237     TRY_READ_ATTR_WITHOUT_NS_INTO(refPtType, m_refPtType)
1238     TRY_READ_ATTR_WITHOUT_NS_INTO(refType, m_refType)
1239     TRY_READ_ATTR_WITHOUT_NS_INTO(refFor, m_refFor)
1240     TRY_READ_ATTR_WITHOUT_NS_INTO(refForName, m_refForName)
1241     TRY_READ_ATTR_WITHOUT_NS_INTO(type, m_type)
1242     TRY_READ_ATTR_WITHOUT_NS_INTO(val, m_value)
1243     //AbstractAtom::readAll(context, reader);
1244 }
1245 
1246 void ConstraintAtom::build(Context* context) {
1247     AbstractAtom::build(context);
1248 }
1249 
1250 void ConstraintAtom::finishBuild(Context* context) {
1251 #if 0
1252     QExplicitlySharedDataPointer<ConstraintAtom> ptr(this);
1253     QVector< QExplicitlySharedDataPointer<ConstraintAtom> > addedConstraints;
1254 
1255     // first evaluate on which layouts this constraint should be applied.
1256     if ( m_for == "self" || m_for.isEmpty() ) {
1257         // nothing to do cause this constraint is already attached to the correct layout.
1258         Q_ASSERT( context->m_parentLayout->constraints().contains(ptr) );
1259     } else {
1260         // We need to select the chosen data-points and determinate the layoutNotes which are connected with
1261         // them to look where we need to move this constraint to.
1262         QList<AbstractNode*> nodes;
1263         if ( m_for == "ch" ) { // Children
1264             nodes = context->currentNode()->children();
1265         } else if ( m_for == "des" ) { // Descendant
1266             nodes = context->currentNode()->descendant();
1267         } else {
1268             Q_ASSERT_X(false, __FUNCTION__, QString("Constraint with unhandled 'for' %1").arg( dump() ).toLocal8Bit());
1269         }
1270 
1271         QVector< AbstractNode* > childDataPoints;
1272         foreach( AbstractNode* node, nodes ) {
1273             if ( !m_ptType.isEmpty() ) {
1274                 if ( PointNode *ptNode = dynamic_cast< PointNode* >( node ) ) {
1275                     if (m_ptType != ptNode->m_type)
1276                         continue;
1277                 } else if ( ConnectionNode *connNode = dynamic_cast< ConnectionNode* >( node ) ) {
1278                     if (m_ptType != connNode->m_type)
1279                         continue;
1280                 }
1281             }
1282             childDataPoints.append( node );
1283         }
1284 
1285         /*TODO why the following? how does that make sense?
1286         if ( m_ptType.isEmpty() )
1287             childDataPoints.append( context->currentNode() );
1288         if ( m_refPtType.isEmpty() )
1289             refChildDataPoints.append( context->currentNode() );
1290         */
1291 
1292         Q_ASSERT( !childDataPoints.isEmpty() );
1293 
1294         bool constraintedWasApplied = false;
1295         foreach(AbstractNode* node, childDataPoints) {
1296             foreach(LayoutNodeAtom* a, context->m_pointLayoutMap.values(node)) {
1297                 if ( !m_forName.isEmpty() && a->m_name != m_forName )
1298                     continue;
1299 
1300                 QExplicitlySharedDataPointer<ConstraintAtom> clonedPtr( ptr->clone(context) );
1301                 a->addChild(clonedPtr);
1302                 addedConstraints.append(clonedPtr);
1303                 constraintedWasApplied = true;
1304             }
1305         }
1306         if (!constraintedWasApplied) dump(0,2);
1307         Q_ASSERT_X(constraintedWasApplied, __FUNCTION__, QString("Constraint could not be applied %1").arg( dump() ).toLocal8Bit());
1308 
1309         // this constraint is handled now and we can detach it
1310         Q_ASSERT( context->m_parentLayout->constraints().contains(ptr) );
1311         parent()->removeChild(ptr);
1312     }
1313     // and now evaluated the referenced layout definitions
1314     if ( m_refFor == "self" || m_refFor.isEmpty() ) {
1315         /*
1316         foreach(QExplicitlySharedDataPointer<ConstraintAtom> constraint, addedConstraints) {
1317             constraint->m_referencedLayouts.append( context->m_parentLayout );
1318         }
1319         */
1320     } else  {
1321         QList<AbstractNode*> nodes;
1322         if ( m_refFor == "ch" ) { // Children
1323             nodes = context->currentNode()->children();
1324         } else if ( m_refFor == "des" ) { // Descendant
1325             nodes = context->currentNode()->descendant();
1326         } else {
1327             Q_ASSERT_X(false, __FUNCTION__, QString("Constraint with unhandled 'refFor' %1").arg( dump() ).toLocal8Bit());
1328         }
1329 
1330         QVector< AbstractNode* > childDataPoints;
1331         foreach( AbstractNode* node, nodes ) {
1332             if ( !m_refPtType.isEmpty() ) {
1333                 if ( PointNode *ptNode = dynamic_cast< PointNode* >( node ) ) {
1334                     if (m_refPtType != ptNode->m_type)
1335                         continue;
1336                 } else if ( ConnectionNode *connNode = dynamic_cast< ConnectionNode* >( node ) ) {
1337                     if (m_refPtType != connNode->m_type)
1338                         continue;
1339                 }
1340             }
1341             childDataPoints.append( node );
1342         }
1343 
1344         Q_ASSERT( !childDataPoints.isEmpty() );
1345 
1346         bool referenceWasApplied = false;
1347         foreach(AbstractNode* node, childDataPoints) {
1348             Q_ASSERT(context->m_pointLayoutMap.contains(node));
1349             foreach(LayoutNodeAtom* a, context->m_pointLayoutMap.values(node)) {
1350                 if ( !m_refForName.isEmpty() && a->m_name != m_refForName )
1351                     continue;
1352 
1353                 QExplicitlySharedDataPointer<LayoutNodeAtom> aPtr( a );
1354                 foreach(QExplicitlySharedDataPointer<ConstraintAtom> constraint, addedConstraints) {
1355                     constraint->m_referencedLayouts.append( aPtr );
1356                 }
1357                 referenceWasApplied = true;
1358             }
1359         }
1360         Q_ASSERT_X(referenceWasApplied, __FUNCTION__, QString("Reference of constraint could not be applied %1").arg( dump() ).toLocal8Bit());
1361     }
1362 #else
1363     Q_UNUSED(context);
1364 #endif
1365 }
1366 
1367 void ConstraintAtom::applyConstraint(Context* context, LayoutNodeAtom* atom) {
1368     // Following block shows how we tried to determinate the layouts using there data-points. But that seems to be
1369     // wrong (with me07_basic_radial.xlsx) cause 'for' and 'refFor' are referring to the layout-tree and not the
1370     // data-tree which can be rather different.
1371 #if 0
1372     QExplicitlySharedDataPointer<ConstraintAtom> ptr(this);
1373     QList< LayoutNodeAtom* > applyLayouts;
1374     QList< LayoutNodeAtom* > referencedLayouts;
1375     if ( m_for == "self" || m_for.isEmpty() ) {
1376         applyLayouts.append( atom /* context->m_parentLayout.data() */ );
1377     } else {
1378         QList<AbstractNode*> nodes;
1379         if ( m_for == "ch" ) { // Children
1380             nodes = context->currentNode()->children();
1381         } else if ( m_for == "des" ) { // Descendant
1382             nodes = context->currentNode()->descendant();
1383         } else {
1384             Q_ASSERT_X(false, __FUNCTION__, QString("Constraint with unhandled 'for' %1").arg( dump() ).toLocal8Bit());
1385         }
1386         QVector< AbstractNode* > childDataPoints;
1387         foreach( AbstractNode* node, nodes ) {
1388             if ( !m_ptType.isEmpty() ) {
1389                 if ( PointNode *ptNode = dynamic_cast< PointNode* >( node ) ) {
1390                     if (m_ptType != ptNode->m_type)
1391                         continue;
1392                 } else if ( ConnectionNode *connNode = dynamic_cast< ConnectionNode* >( node ) ) {
1393                     if (m_ptType != connNode->m_type)
1394                         continue;
1395                 } else {
1396                     Q_ASSERT_X(false, __FUNCTION__, QString("Unhandled ptType=%1 for node=%2").arg(m_ptType).arg(node->m_tagName).toLocal8Bit());
1397                 }
1398             }
1399             childDataPoints.append( node );
1400         }
1401         Q_ASSERT_X(!childDataPoints.isEmpty(), __FUNCTION__, QString("No data-points selected for constraint %1").arg(dump()).toLocal8Bit());
1402         foreach(AbstractNode* node, childDataPoints) {
1403             foreach(LayoutNodeAtom* a, context->m_pointLayoutMap.values(node)) {
1404                 if ( m_forName.isEmpty() || a->m_name == m_forName )
1405                     applyLayouts.append( a );
1406             }
1407         }
1408         Q_ASSERT_X(!applyLayouts.isEmpty(), __FUNCTION__, QString("Failed to determinate the layout on which to apply the constraint %1").arg( dump() ).toLocal8Bit());
1409     }
1410     if ( m_refFor == "self" || m_refFor.isEmpty() ) {
1411         referencedLayouts.append( atom /* context->m_parentLayout.data() */ );
1412     } else  {
1413         QList<AbstractNode*> nodes;
1414         if ( m_refFor == "ch" ) { // Children
1415             nodes = context->currentNode()->children();
1416         } else if ( m_refFor == "des" ) { // Descendant
1417             nodes = context->currentNode()->descendant();
1418         } else {
1419             Q_ASSERT_X(false, __FUNCTION__, QString("Constraint with unhandled 'refFor' %1").arg( dump() ).toLocal8Bit());
1420         }
1421         QVector< AbstractNode* > childDataPoints;
1422         foreach( AbstractNode* node, nodes ) {
1423             if ( !m_refPtType.isEmpty() ) {
1424                 if ( PointNode *ptNode = dynamic_cast< PointNode* >( node ) ) {
1425                     if (m_refPtType != ptNode->m_type)
1426                         continue;
1427                 } else if ( ConnectionNode *connNode = dynamic_cast< ConnectionNode* >( node ) ) {
1428                     if (m_refPtType != connNode->m_type)
1429                         continue;
1430                 } else {
1431                     Q_ASSERT_X(false, __FUNCTION__, QString("Unhandled ptType=%1 for node=%2").arg(m_ptType).arg(node->m_tagName).toLocal8Bit());
1432                 }
1433             }
1434             childDataPoints.append( node );
1435         }
1436         Q_ASSERT_X(!childDataPoints.isEmpty(), __FUNCTION__, QString("No data-points selected for constraint %1").arg(dump()).toLocal8Bit());
1437         foreach(AbstractNode* node, childDataPoints)
1438             foreach(LayoutNodeAtom* a, context->m_pointLayoutMap.values(node))
1439                 if ( m_refForName.isEmpty() || a->m_name == m_refForName )
1440                     referencedLayouts.append(a);
1441         Q_ASSERT_X(!referencedLayouts.isEmpty(), __FUNCTION__, QString("Failed to determinate the referenced layouts for the constraint %1").arg( dump() ).toLocal8Bit());
1442     }
1443 #else
1444     QVector< QExplicitlySharedDataPointer<LayoutNodeAtom> > applyLayouts = atom->fetchLayouts(context, m_for, m_forName, m_ptType);
1445     QVector< QExplicitlySharedDataPointer<LayoutNodeAtom> > referencedLayouts = atom->fetchLayouts(context, m_refFor, m_refForName, m_refPtType);
1446 
1447     ASSERT_X(!applyLayouts.isEmpty(), QString("Failed to determinate the layouts for the constraint %1").arg( dump() ).toLocal8Bit());
1448     ASSERT_X(!referencedLayouts.isEmpty(), QString("Failed to determinate the referenced layouts for the constraint %1").arg( dump() ).toLocal8Bit());
1449     debugMsooXml << dump();
1450 
1451     foreach(const QExplicitlySharedDataPointer<LayoutNodeAtom> &applyLayout, applyLayouts) {
1452         debugMsooXml << "AppLayout: " << applyLayout->m_name;
1453         if( !m_value.isEmpty() ) {
1454             bool ok;
1455             qreal value = m_value.toDouble( &ok );
1456             ASSERT_X(ok, QString("Layout with name=%1 defines none-double value=%2").arg( atom->m_name ).arg( m_value ).toLocal8Bit());
1457             debugMsooXml << "applyValue: " << value;
1458             if (ok) {
1459                 //applyLayout->m_factors.clear();
1460                 //applyLayout->m_countFactors.clear();
1461                 applyLayout->m_values[ m_type ] = value;
1462                 applyLayout->setNeedsRelayout( true );
1463             }
1464         } else {
1465             //TODO proper handle the case where more then one layouts are referenced (means proper eval the constraints operator)
1466             LayoutNodeAtom* referencedLayout = referencedLayouts.isEmpty() ? atom : referencedLayouts.first().data();
1467             Q_ASSERT(referencedLayout);
1468 
1469             AbstractAlgorithm* r = referencedLayout->algorithmImpl();
1470             ASSERT_X(r, QString("No algorithm in referenced layout=%1 for constraint='%2'").arg( referencedLayout->m_name ).arg( dump() ).toLocal8Bit());
1471 
1472             const QMap<QString, qreal> values = referencedLayout->finalValues();
1473             const QString type = m_refType.isEmpty() ? m_type : m_refType;
1474 
1475             qreal value = -1.0;
1476             if( values.contains( type ) ) {
1477                 value = values[ type ];
1478                 debugMsooXml << "finalValue: " << value;
1479             } else {
1480                 value = r ? r->defaultValue( type, values ) : -1.0;
1481                 ASSERT_X(value >= 0.0, QString("algorithm=%1 value=%2 constraint='%3'").arg( r ? r->name() : "NULL" ).arg( value ).arg( dump() ).toLocal8Bit());
1482                 if (value < 0.0) continue;
1483                 debugMsooXml << "default Value: " << value;
1484             }
1485             applyLayout->m_values[ m_type ] = value;
1486             applyLayout->setNeedsRelayout( true );
1487             //applyLayout->m_factors.clear();
1488             //applyLayout->m_countFactors.clear();
1489         }
1490         if ( !m_fact.isEmpty() ) {
1491             bool ok;
1492             qreal v = m_fact.toDouble( &ok );
1493             ASSERT_X(ok, QString("Layout with name=%1 defines none-double factor=%2").arg( atom->m_name ).arg( m_fact ).toLocal8Bit());
1494             debugMsooXml << "fact: " << v;
1495             if (ok) {
1496                 applyLayout->m_factors[ m_type ] += v;
1497                 applyLayout->m_countFactors[ m_type ] += 1;
1498                 //applyLayout->m_values[ m_type ] = applyLayout->m_values[ m_type ] * v;
1499                 applyLayout->setNeedsRelayout( true );
1500             }
1501         }
1502     }
1503 #endif
1504 }
1505 
1506 /****************************************************************************************************/
1507 
1508 AdjustAtom* AdjustAtom::clone(Context*) {
1509     AdjustAtom* atom = new AdjustAtom;
1510     atom->m_index = m_index;
1511     atom->m_value = m_value;
1512     return atom;
1513 }
1514 
1515 void AdjustAtom::dump(Context*, int level) {
1516     DEBUG_DUMP << "index=" << m_index << "value=" << m_value;
1517 }
1518 
1519 void AdjustAtom::readAll(Context*, MsooXmlDiagramReader* reader) {
1520     const QXmlStreamAttributes attrs(reader->attributes());
1521     TRY_READ_ATTR_WITHOUT_NS(idx)
1522     m_index = idx.toInt();
1523     TRY_READ_ATTR_WITHOUT_NS(val)
1524     m_value = val.toDouble();
1525 }
1526 
1527 // http://social.msdn.microsoft.com/Forums/en-US/os_binaryfile/thread/74f86b76-37be-4087-b5b0-cf2fc68d5595/
1528 void AdjustAtom::applyAdjustment(Context* /* context */, LayoutNodeAtom* /* atom */) {
1529     ASSERT_X(m_index >= 0 && m_index < context->m_shapeList.count(), QString("Index is out of bounds, index=%1 min=0 max=%2").arg(m_index).arg(context->m_shapeList.count()-1).toLocal8Bit());
1530     //TODO
1531     //ShapeAtom *shape = context->m_shapeList.at(m_index);
1532     //if (m_value > 90) m_value = 360 - (m_value - 90);
1533     //shape->parentLayout()->m_rotateAngle = m_value;
1534 }
1535 
1536 /****************************************************************************************************/
1537 
1538 RuleAtom* RuleAtom::clone(Context*) {
1539     RuleAtom* atom = new RuleAtom;
1540     atom->m_fact = m_fact;
1541     atom->m_for = m_for;
1542     atom->m_forName = m_forName;
1543     atom->m_max = m_max;
1544     atom->m_ptType = m_ptType;
1545     atom->m_type = m_type;
1546     atom->m_value = m_value;
1547     return atom;
1548 }
1549 
1550 void RuleAtom::dump(Context*, int level) {
1551     QString s;
1552     if(!m_fact.isEmpty()) s += QString("fact=%1 ").arg(m_fact);
1553     if(!m_for.isEmpty()) s += QString("for=%1 ").arg(m_for);
1554     if(!m_forName.isEmpty()) s += QString("forName=%1 ").arg(m_forName);
1555     if(!m_max.isEmpty()) s += QString("max=%1 ").arg(m_max);
1556     if(!m_ptType.isEmpty()) s += QString("ptType=%1 ").arg(m_ptType);
1557     if(!m_type.isEmpty()) s += QString("type=%1 ").arg(m_type);
1558     if(!m_value.isEmpty()) s += QString("val=%1 ").arg(m_value);
1559     DEBUG_DUMP << s;
1560 }
1561 
1562 void RuleAtom::readAll(Context*, MsooXmlDiagramReader* reader) {
1563     const QXmlStreamAttributes attrs(reader->attributes());
1564     TRY_READ_ATTR_WITHOUT_NS_INTO(fact, m_fact)
1565     TRY_READ_ATTR_WITHOUT_NS_INTO(for, m_for)
1566     TRY_READ_ATTR_WITHOUT_NS_INTO(forName, m_forName)
1567     TRY_READ_ATTR_WITHOUT_NS_INTO(max, m_max)
1568     TRY_READ_ATTR_WITHOUT_NS_INTO(ptType, m_ptType)
1569     TRY_READ_ATTR_WITHOUT_NS_INTO(type, m_type)
1570     TRY_READ_ATTR_WITHOUT_NS_INTO(val, m_value)
1571 }
1572 
1573 /****************************************************************************************************/
1574 
1575 ListAtom* ListAtom::clone(Context* context) {
1576     ListAtom* atom = new ListAtom(m_tagName);
1577     foreach(QExplicitlySharedDataPointer<AbstractAtom> a, m_children)
1578         atom->addChild(a->clone(context));
1579     return atom;
1580 }
1581 
1582 void ListAtom::dump(Context* context, int level) {
1583     DEBUG_DUMP;
1584     AbstractAtom::dump(context, level);
1585 }
1586 
1587 void ListAtom::readElement(Context* context, MsooXmlDiagramReader* reader) {
1588     if (reader->isStartElement()) {
1589         QExplicitlySharedDataPointer<AbstractAtom> node;
1590         if (reader->qualifiedName() == QLatin1String("dgm:constr")) {
1591             node = QExplicitlySharedDataPointer<AbstractAtom>(new ConstraintAtom);
1592         } else if (reader->qualifiedName() == QLatin1String("dgm:adj")) {
1593             node = QExplicitlySharedDataPointer<AbstractAtom>(new AdjustAtom);
1594         } else if (reader->qualifiedName() == QLatin1String("dgm:rule")) {
1595             node = QExplicitlySharedDataPointer<AbstractAtom>(new RuleAtom);
1596         }
1597         if (node) {
1598             addChild(node);
1599             node->readAll(context, reader);
1600         }
1601     }
1602 }
1603 
1604 /****************************************************************************************************/
1605 
1606 ShapeAtom* ShapeAtom::clone(Context* context) {
1607     ShapeAtom* atom = new ShapeAtom;
1608     atom->m_type = m_type;
1609     atom->m_blip = m_blip;
1610     atom->m_hideGeom = m_hideGeom;
1611     foreach(QExplicitlySharedDataPointer<AbstractAtom> a, m_children)
1612         atom->addChild(a->clone(context));
1613     return atom;
1614 }
1615 
1616 QList< QExplicitlySharedDataPointer<AdjustAtom> > ShapeAtom::adjustments() const {
1617     QList< QExplicitlySharedDataPointer<AdjustAtom> > result;
1618     foreach( QExplicitlySharedDataPointer<AbstractAtom> atom, m_children ) {
1619         AdjustAtom* adjustedAtom = dynamic_cast< AdjustAtom* >( atom.data() );
1620         if ( adjustedAtom ) {
1621             result.append(QExplicitlySharedDataPointer<AdjustAtom>(adjustedAtom));
1622         } else if (ListAtom *list = dynamic_cast< ListAtom* >( atom.data() ) ) {
1623             foreach( QExplicitlySharedDataPointer<AbstractAtom> val, list->children() ) {
1624                 adjustedAtom = dynamic_cast< AdjustAtom* >( val.data() );
1625                 if ( adjustedAtom )
1626                     result.append(QExplicitlySharedDataPointer<AdjustAtom>(adjustedAtom));
1627         }
1628         }
1629     }
1630     return result;
1631 }
1632 
1633 void ShapeAtom::dump(Context* context, int level) {
1634     DEBUG_DUMP << "type=" << m_type << "hideGeom=" << m_hideGeom << "blip=" << m_blip;
1635     AbstractAtom::dump(context, level);
1636 }
1637 
1638 void ShapeAtom::readAll(Context* context, MsooXmlDiagramReader* reader) {
1639     const QXmlStreamAttributes attrs(reader->attributes());
1640     TRY_READ_ATTR_WITHOUT_NS_INTO(type, m_type)
1641     //if (m_type.isEmpty()) m_type = "obj";
1642     TRY_READ_ATTR_WITHOUT_NS_INTO(blip, m_blip)
1643     TRY_READ_ATTR_WITHOUT_NS(hideGeom)
1644     m_hideGeom = hideGeom.toInt();
1645     AbstractAtom::readAll(context, reader);
1646 }
1647 
1648 void ShapeAtom::build(Context* context) {
1649     Q_ASSERT(!context->m_shapeList.contains(this));
1650     context->m_shapeList.append(this);
1651     AbstractAtom::build(context);
1652 }
1653 
1654 //TODO use filters/libmso/ODrawToOdf.h
1655 void ShapeAtom::writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles) {
1656     Q_ASSERT(context->m_parentLayout);
1657     if(m_type.isEmpty() || m_hideGeom) return;
1658     QMap<QString,QString> params = context->m_parentLayout->algorithmParams();
1659     QMap<QString, qreal> values = context->m_parentLayout->finalValues();
1660     debugMsooXml << values;
1661     //Q_ASSERT(values.contains("l"));
1662     //Q_ASSERT(values.contains("t"));
1663     //if(!values.contains("w")) values["w"]=100;
1664     //if(!values.contains("h")) values["h"]=100;
1665     Q_ASSERT(values.contains("w"));
1666     Q_ASSERT(values.contains("h"));
1667     //Q_ASSERT(values.contains("ctrX"));
1668     //Q_ASSERT(values.contains("ctrY"));
1669     qreal x  = values.value("l");
1670     qreal y  = values.value("t");
1671     qreal w  = values.value("w");
1672     qreal h  = values.value("h");
1673     qreal cx = values.value("ctrX");
1674     qreal cy = values.value("ctrY");
1675     /*
1676     QFile shapeListFile( "shapeList.txt" );
1677     QString cxt = QString::number( cx );
1678     QString cyt = QString::number( cy );
1679     QString wt = QString::number( w );
1680     QString ht = QString::number( h );
1681     QString lbrack = "(";
1682     QString rbrack = ")\n";
1683     QString space = " ";
1684     shapeListFile.open( QFile::WriteOnly | QFile::Append );
1685     shapeListFile.write( lbrack.toLatin1() );
1686     shapeListFile.write( cxt.toLatin1() );
1687     shapeListFile.write( space.toLatin1() );
1688     shapeListFile.write( cyt.toLatin1() );
1689     shapeListFile.write( space.toLatin1() );
1690     shapeListFile.write( wt.toLatin1() );
1691     shapeListFile.write( space.toLatin1() );
1692     shapeListFile.write( ht.toLatin1() );
1693     shapeListFile.write( rbrack.toLatin1() );
1694     shapeListFile.close();
1695     */
1696 
1697 #if 0
1698     //TODO can spacing between the siblings applied by shriking the shapes or is it needed to apply them along the used algorithm?
1699     if(values.contains("sibSp")) {
1700         qreal sibSp = values["sibSp"];
1701         Q_ASSERT(w >= sibSp);
1702         Q_ASSERT(h >= sibSp);
1703         if(w >= sibSp && h >= sibSp) {
1704             x += sibSp;
1705             y += sibSp;
1706             w -= sibSp;
1707             h -= sibSp;
1708         } else {
1709             warnMsooXml<<"Sibling spacing is bigger then width/height! Skipping sibSp-value! width="<<w<<"height="<<h<<"sibSp="<<sibSp;
1710             context->m_parentLayout->dump(context, 10);
1711         }
1712     }
1713 #endif
1714 
1715     DEBUG_WRITE << "type=" << m_type << "blip=" << m_blip << "hideGeom=" << m_hideGeom << "geometry=" << x+cx << y+cy << w << h;
1716     //Q_ASSERT(x >= 0.0); Q_ASSERT(y >= 0.0); Q_ASSERT(cx >= 0.0); Q_ASSERT(cy >= 0.0); // they can be negative
1717     if (w < 0.0) w = -w;
1718     if (h < 0.0) h = -h;
1719 
1720     xmlWriter->startElement("draw:custom-shape");
1721     //xmlWriter->addAttribute("draw:layer", "layout");
1722 
1723     if (!context->m_parentLayout->m_name.isEmpty())
1724         xmlWriter->addAttribute("draw:name", context->m_parentLayout->m_name);
1725 
1726     KoGenStyle style = KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic");
1727     style.addProperty("draw:fill", "solid" /*none*/, KoGenStyle::GraphicType);
1728     style.addProperty("draw:opacity", "50%");
1729     style.addProperty("draw:textarea-horizontal-align", "center");
1730     style.addProperty("draw:textarea-vertical-align", "middle");
1731     style.addProperty("fo:wrap-option", "wrap");
1732 
1733     //const qreal m_svgX = x + qMax(0.0, qMin(w, cx - w/2));
1734     //const qreal m_svgY = y + qMax(0.0, qMin(h, cy - h/2));
1735     const qreal m_svgX = x/* + cx*/;
1736     const qreal m_svgY = y/* + cy*/;
1737 
1738     const qreal rotateAngle = context->m_parentLayout->m_rotateAngle; //0=right 45=bottom 90=left 135=top 180=right
1739     if(rotateAngle == 0) {
1740         xmlWriter->addAttribute("svg:x", QString("%1px").arg(m_svgX));
1741         xmlWriter->addAttribute("svg:y", QString("%1px").arg(m_svgY));
1742     }
1743     xmlWriter->addAttribute("svg:width", QString("%1px").arg(w));
1744     xmlWriter->addAttribute("svg:height", QString("%1px").arg(h));
1745     if(rotateAngle != 0) {
1746         QMatrix matrix;
1747         matrix.translate(m_svgX + 0.5 * w, m_svgY + 0.5 * h);
1748         matrix.rotate(rotateAngle);
1749         matrix.translate(-0.5 * w, -0.5 * h);
1750         xmlWriter->addAttribute("draw:transform", QString("matrix(%1 %2 %3 %4 %5pt %6pt)").arg(matrix.m11()).arg(matrix.m12()).arg(matrix.m21()).arg(matrix.m22()).arg(matrix.dx()) .arg(matrix.dy()));
1751     }
1752 
1753     if (m_type == QLatin1String("conn")) {
1754         /*
1755         QList<AbstractNode*> axis = context->m_parentLayout->axis();
1756         foreach(AbstractNode* n, axis) n->dump(context,10);        
1757         Q_ASSERT(axis.count() == 1);
1758         Q_ASSERT(static_cast<PointNode*>(axis.first())->m_type == "sibTrans");
1759         const QString cxnId = static_cast<PointNode*>(axis.first())->m_cxnId;
1760         Q_ASSERT(!static_cast<PointNode*>(axis.first())->m_cxnId.isEmpty());
1761         ConnectionNode* connection = 0;
1762         foreach(AbstractNode* node, context->m_connections->children()) {
1763             ConnectionNode* n = dynamic_cast<ConnectionNode*>(node);
1764             if(n && n->m_modelId == cxnId) {
1765                 connection = n;
1766                 break;
1767             }
1768         }
1769         Q_ASSERT(connection);
1770         //connection->m_srcId;
1771         //connection->m_destId;
1772         */
1773         style.addProperty("draw:fill-color", "#9999ff");
1774     } else {
1775         style.addProperty("draw:fill-color", "#3333ff");
1776     }
1777 
1778     const QString styleName = styles->insert(style);
1779     xmlWriter->addAttribute("draw:style-name", styleName);
1780     //xmlWriter->addAttribute("draw:text-style-name", "P2");
1781 
1782     //xmlWriter->startElement("svg:desc");
1783     //xmlWriter->endElement();
1784 
1785     QList<PointNode*> textlist;
1786     foreach(AbstractNode* n, context->m_parentLayout->axis( context )) {
1787         if(PointNode* pn = dynamic_cast<PointNode*>(n))
1788             if(!pn->m_text.isEmpty())
1789                 textlist.prepend(pn);
1790     }
1791 
1792     if (!textlist.isEmpty()) {
1793         foreach(PointNode* pn, textlist) {
1794             bool bulletEnabled = QVariant(context->m_parentLayout->variable("bulletEnabled", false)).toBool();
1795             if (bulletEnabled) {
1796                 int level = 0;
1797                 for(AbstractNode* n = pn->parent(); n; n = n->parent(), ++level);
1798                 if(level < 2) // seems only level2 has bullets while level1 has not even if bulletEnabled=1 (see me07_horizontal_bullet_list.xlsx).
1799                     bulletEnabled = false;
1800             }
1801             if (bulletEnabled) {
1802                 xmlWriter->startElement("text:list");
1803                 KoListStyle listStyle;
1804                 KoListLevelProperties llp;
1805                 llp.setLevel(1);
1806                 llp.setBulletCharacter(QChar(0x2022));
1807                 listStyle.setLevelProperties(llp);
1808                 KoGenStyle style(KoGenStyle::ListAutoStyle);
1809                 QByteArray array;
1810                 QBuffer buffer(&array);
1811                 KoXmlWriter tmpXmlWriter(&buffer);
1812                 KoEmbeddedDocumentSaver embeddedSaver;
1813                 KoShapeSavingContext context(tmpXmlWriter, *styles, embeddedSaver);
1814                 listStyle.saveOdf(style, context);
1815                 xmlWriter->addAttribute("text:style-name", styles->insert(style));
1816                 xmlWriter->startElement("text:list-item");
1817             }
1818             xmlWriter->startElement("text:p");
1819             xmlWriter->addTextNode(pn->m_text);
1820             xmlWriter->endElement();
1821             if (bulletEnabled) {
1822                 xmlWriter->endElement();
1823                 xmlWriter->endElement();
1824             }
1825         }
1826     }
1827 
1828     if (m_type == QLatin1String("ellipse")) {
1829         xmlWriter->startElement("draw:enhanced-geometry");
1830         xmlWriter->addAttribute("draw:enhanced-path", "U 10800 10800 10800 10800 0 360 Z N");
1831         xmlWriter->addAttribute("draw:glue-points", "10800 0 3163 3163 0 10800 3163 18437 10800 21600 18437 18437 21600 10800 18437 3163");
1832         xmlWriter->addAttribute("draw:type", "ellipse");
1833         //xmlWriter->addAttribute("svg:viewBox", "0 0 21600 21600");
1834         xmlWriter->endElement();
1835     } else if (m_type == QLatin1String("cycle")) {
1836         xmlWriter->startElement("draw:enhanced-geometry");
1837         xmlWriter->addAttribute("draw:enhanced-path", "M 0 414114 C 0 304284 43630 198953 121292 121291 198954 43630 304285 0 414115 0 523945 0 629276 43630 706938 121292 784599 198954 828229 304285 828229 414115 828229 523945 784599 629276 706938 706938 629277 784599 523945 828229 414115 828229 304285 828229 198954 784599 121292 706938 43631 629276 1 523945 1 414115 L 0 414114 Z N");
1838         xmlWriter->addAttribute("draw:glue-point-leaving-directions", "-90, -90, -90, -90, -90, -90, -90, -90, -90, -90");
1839         xmlWriter->addAttribute("draw:glue-points", "?f21 ?f22 ?f23 ?f24 ?f25 ?f26 ?f27 ?f28 ?f29 ?f30 ?f27 ?f31 ?f25 ?f32 ?f23 ?f31 ?f33 ?f30 ?f21 ?f22");
1840         xmlWriter->addAttribute("draw:type", "circle");
1841         //xmlWriter->addAttribute("draw:text-areas", "?f34 ?f36 ?f35 ?f37");
1842         //xmlWriter->addAttribute("svg:viewBox", "0 0 828228 828228");
1843         xmlWriter->endElement();
1844     } else if (m_type == QLatin1String("rect")) {
1845         xmlWriter->startElement("draw:enhanced-geometry");
1846         xmlWriter->addAttribute("draw:enhanced-path", "M 0 0 L 1393031 0 1393031 557212 0 557212 0 0 Z N");
1847         xmlWriter->addAttribute("draw:glue-point-leaving-directions", "-90, -90, -90, -90, -90");
1848         xmlWriter->addAttribute("draw:glue-points", "?f12 ?f13 ?f14 ?f13 ?f14 ?f15 ?f12 ?f15 ?f12 ?f13");
1849         xmlWriter->addAttribute("draw:type", "non-primitive");
1850         //xmlWriter->addAttribute("draw:text-areas", "?f16 ?f18 ?f17 ?f19");
1851         //xmlWriter->addAttribute("svg:viewBox", "0 0 1393031 557212");
1852         xmlWriter->endElement();
1853     } else if (m_type == QLatin1String("roundRect")) {
1854         xmlWriter->startElement("draw:enhanced-geometry");
1855         xmlWriter->addAttribute("draw:enhanced-path", "M 0 97707 C 0 71793 10294 46941 28618 28618 46942 10294 71794 0 97707 0 L 804191 0 C 830105 0 854957 10294 873280 28618 891604 46942 901898 71794 901898 97707 L 901898 488526 C 901898 514440 891604 539292 873280 557615 854956 575939 830104 586233 804191 586233 L 97707 586233 C 71793 586233 46941 575939 28618 557615 10294 539291 0 514439 0 488526 L 0 97707 Z N");
1856         xmlWriter->addAttribute("draw:glue-point-leaving-directions", "-90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90");
1857         xmlWriter->addAttribute("draw:glue-points", "?f20 ?f21 ?f22 ?f23 ?f24 ?f25 ?f26 ?f25 ?f27 ?f23 ?f28 ?f21 ?f28 ?f29 ?f27 ?f30 ?f26 ?f31 ?f24 ?f31 ?f22 ?f30 ?f20 ?f29 ?f20 ?f21");
1858         xmlWriter->addAttribute("draw:type", "non-primitive");
1859         //xmlWriter->addAttribute("draw:text-areas", "?f32 ?f34 ?f33 ?f35");
1860         //xmlWriter->addAttribute("svg:viewBox", "0 0 901898 586233");
1861         xmlWriter->endElement();
1862     } else if (m_type == QLatin1String("pie")) {
1863         xmlWriter->startElement("draw:enhanced-geometry");
1864         xmlWriter->addAttribute("draw:enhanced-path", "M 1152145 0 C 1563767 0 1944120 219599 2149931 576074 2355741 932549 2355740 1371744 2149929 1728219 L 1152144 1152144 C 1152144 768096 1152145 384048 1152145 0 Z N");
1865         xmlWriter->addAttribute("draw:glue-point-leaving-directions", "-90, -90, -90, -90, -90");
1866         xmlWriter->addAttribute("draw:glue-points", "?f16 ?f17 ?f18 ?f19 ?f20 ?f21 ?f22 ?f23 ?f16 ?f17");
1867         xmlWriter->addAttribute("draw:type", "non-primitive");
1868         //xmlWriter->addAttribute("draw:text-areas", "?f24 ?f26 ?f25 ?f27");
1869         //xmlWriter->addAttribute("svg:viewBox", "0 0 2304288 2304288");
1870         xmlWriter->endElement();
1871     } else if (m_type == QLatin1String("diamond")) {
1872         xmlWriter->startElement("draw:enhanced-geometry");
1873         xmlWriter->addAttribute("draw:enhanced-path", "M ?f0 ?f7 L ?f11 ?f2 ?f1 ?f7 ?f11 ?f3 Z N");
1874         //xmlWriter->addAttribute("draw:path-stretchpoint-x", "21600");
1875         //xmlWriter->addAttribute("draw:path-stretchpoint-y", "21600");
1876         xmlWriter->addAttribute("draw:type", "non-primitive");
1877         //xmlWriter->addAttribute("draw:text-areas", "?f10 ?f6 ?f12 ?f13");
1878         //xmlWriter->addAttribute("svg:viewBox", "0 0 21600 21600");
1879         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "left"); xmlWriter->addAttribute("draw:name", "f0"); xmlWriter->endElement();
1880         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "right");  xmlWriter->addAttribute("draw:name", "f1");xmlWriter->endElement();
1881         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "top");  xmlWriter->addAttribute("draw:name", "f2");xmlWriter->endElement();
1882         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "bottom");  xmlWriter->addAttribute("draw:name", "f3");xmlWriter->endElement();
1883         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "?f3 - ?f2");  xmlWriter->addAttribute("draw:name", "f4");xmlWriter->endElement();
1884         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "?f4 / 2");  xmlWriter->addAttribute("draw:name", "f5");xmlWriter->endElement();
1885         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "?f4 / 4");  xmlWriter->addAttribute("draw:name", "f6");xmlWriter->endElement();
1886         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "?f2 + ?f5");  xmlWriter->addAttribute("draw:name", "f7");xmlWriter->endElement();
1887         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "?f1 - ?f0");  xmlWriter->addAttribute("draw:name", "f8");xmlWriter->endElement();
1888         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "?f8 / 2");  xmlWriter->addAttribute("draw:name", "f9");xmlWriter->endElement();
1889         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "?f8 / 4");  xmlWriter->addAttribute("draw:name", "f10");xmlWriter->endElement();
1890         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "?f0 + ?f9");  xmlWriter->addAttribute("draw:name", "f11");xmlWriter->endElement();
1891         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "?f8 * 3 / 4");  xmlWriter->addAttribute("draw:name", "f12");xmlWriter->endElement();
1892         xmlWriter->startElement("draw:equation"); xmlWriter->addAttribute("draw:formula", "?f4 * 3 / 4");  xmlWriter->addAttribute("draw:name", "f13");xmlWriter->endElement();
1893         xmlWriter->endElement();
1894     } else if (m_type == QLatin1String("trapezoid")) {
1895         xmlWriter->startElement("draw:enhanced-geometry");
1896         xmlWriter->addAttribute("draw:enhanced-path", "M 0 914400 L 761997 0 762003 0 1524000 914400 0 914400 Z N");
1897         xmlWriter->addAttribute("draw:glue-point-leaving-directions", "-90, -90, -90, -90, -90");
1898         xmlWriter->addAttribute("draw:glue-points", "?f14 ?f15 ?f16 ?f17 ?f18 ?f17 ?f19 ?f15 ?f14 ?f15");
1899         xmlWriter->addAttribute("draw:type", "non-primitive");
1900         //xmlWriter->addAttribute("draw:text-areas", "?f20 ?f22 ?f21 ?f23");
1901         //xmlWriter->addAttribute("svg:viewBox", "0 0 1524000 914400");
1902         xmlWriter->endElement();
1903     } else if (m_type == QLatin1String("conn")) { // Connection shape type
1904         enum EndStyle { Arrow, Auto, NoArrow };
1905         EndStyle endstyle = Arrow;
1906         if(params.contains("endSty")) {
1907             const QString endStyle = params["endSty"];
1908             if(endStyle == "auto") {
1909                 //TODO specs say that the algorithm needs to define the style but it misses details how...
1910             } else if(endStyle == "noArr") {
1911                 endstyle = NoArrow;
1912             }
1913         }
1914         if(endstyle == NoArrow) { // just a connecting line without arrow
1915             xmlWriter->startElement("draw:enhanced-geometry");
1916             xmlWriter->addAttribute("draw:enhanced-path", "M 1627875 92938 A ?f54 ?f55 ?f56 ?f57 1627875 92938 ?f51 ?f53  W ?f58 ?f59 ?f60 ?f61 1627875 92938 ?f51 ?f53 N");
1917             //xmlWriter->addAttribute("draw:glue-point-leaving-directions", "-90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90");
1918             //xmlWriter->addAttribute("draw:glue-points", "?f20 ?f21 ?f22 ?f23 ?f24 ?f25 ?f26 ?f25 ?f27 ?f23 ?f28 ?f21 ?f28 ?f29 ?f27 ?f30 ?f26 ?f31 ?f24 ?f31 ?f22 ?f30 ?f20 ?f29 ?f20 ?f21");
1919             xmlWriter->addAttribute("draw:type", "non-primitive");
1920             //xmlWriter->addAttribute("draw:text-areas", "?f11 ?f13 ?f12 ?f14");
1921             //xmlWriter->addAttribute("svg:viewBox", "0 0 2341473 2341473");
1922             xmlWriter->endElement();
1923         } else { // arrow-right
1924             xmlWriter->startElement("draw:enhanced-geometry");
1925             xmlWriter->addAttribute("draw:enhanced-path", "M 0 55905 L 110087 55905 110087 0 220174 139764 110087 279527 110087 223622 0 223622 0 55905 Z N");
1926             xmlWriter->addAttribute("draw:glue-point-leaving-directions", "-90, -90, -90, -90, -90, -90, -90, -90");
1927             xmlWriter->addAttribute("draw:glue-points", "?f16 ?f17 ?f18 ?f17 ?f18 ?f19 ?f20 ?f21 ?f18 ?f22 ?f18 ?f23 ?f16 ?f23 ?f16 ?f17");
1928             xmlWriter->addAttribute("draw:type", "non-primitive");
1929             //xmlWriter->addAttribute("draw:text-areas", "?f24 ?f26 ?f25 ?f27");
1930             //xmlWriter->addAttribute("svg:viewBox", "0 0 220174 279527");
1931             xmlWriter->endElement();
1932         }
1933     } else {
1934         ASSERT_X(false, QString("TODO Handle shape of type=%1").arg(m_type).toUtf8());
1935     }
1936     
1937     xmlWriter->endElement(); // draw:custom-shape
1938 }
1939 
1940 /****************************************************************************************************/
1941 
1942 PresentationOfAtom* PresentationOfAtom::clone(Context* context) {
1943     PresentationOfAtom* atom = new PresentationOfAtom;
1944     atom->m_axis = m_axis;
1945     atom->m_ptType = m_ptType;
1946     atom->m_start = m_start;
1947     atom->m_step = m_step;
1948     atom->m_count = m_count;
1949     atom->m_hideLastTrans = m_hideLastTrans;
1950     foreach(QExplicitlySharedDataPointer<AbstractAtom> a, m_children)
1951         atom->addChild(a->clone(context));
1952     return atom;
1953 }
1954 
1955 bool PresentationOfAtom::isEmpty() const {
1956     return m_axis.isEmpty() && m_ptType.isEmpty() && m_start.isEmpty() && m_step.isEmpty() && m_count.isEmpty() && m_hideLastTrans.isEmpty();
1957 }
1958 
1959 QString PresentationOfAtom::dump() const {
1960     QString s;
1961     if(!m_axis.isEmpty()) s += QString("axis=%1 ").arg(m_axis);
1962     if(!m_ptType.isEmpty()) s += QString("ptType=%1 ").arg(m_ptType);
1963     if(!m_start.isEmpty()) s += QString("start=%1 ").arg(m_start);
1964     if(!m_step.isEmpty()) s += QString("step=%1 ").arg(m_step);
1965     if(!m_count.isEmpty()) s += QString("count=%1 ").arg(m_count);
1966     if(!m_hideLastTrans.isEmpty()) s += QString("hideLastTrans=%1 ").arg(m_hideLastTrans);
1967     return s.trimmed();
1968 }
1969 
1970 void PresentationOfAtom::dump(Context* context, int level) {
1971     DEBUG_DUMP << context->m_parentLayout->m_name << dump();
1972     AbstractAtom::dump(context, level);
1973 }
1974 
1975 void PresentationOfAtom::readAll(Context* context, MsooXmlDiagramReader* reader) {
1976     const QXmlStreamAttributes attrs(reader->attributes());
1977     TRY_READ_ATTR_WITHOUT_NS_INTO(axis, m_axis)
1978     TRY_READ_ATTR_WITHOUT_NS_INTO(ptType, m_ptType)
1979     TRY_READ_ATTR_WITHOUT_NS_INTO(cnt, m_count)
1980     TRY_READ_ATTR_WITHOUT_NS_INTO(hideLastTrans, m_hideLastTrans)
1981         TRY_READ_ATTR_WITHOUT_NS_INTO(st, m_start)
1982     TRY_READ_ATTR_WITHOUT_NS_INTO(step, m_step)
1983     AbstractAtom::readAll(context, reader);
1984 }
1985 
1986 void PresentationOfAtom::build(Context* context) {
1987     // first set the axis according to our layout
1988     Q_ASSERT(context->m_parentLayout->axis( context ).isEmpty());
1989     context->m_parentLayout->setAxis( context, this );
1990 
1991     // and then adjust the current node if 
1992     QList<AbstractNode*> nodes = context->m_parentLayout->axis( context );
1993     if ( nodes.isEmpty() ) {
1994         /*
1995         PointNode* ppp = dynamic_cast<PointNode*>(context->currentNode());
1996         Q_ASSERT(ppp);
1997         debugMsooXml<<QString("modelId=%2 type=%3").arg(ppp->m_modelId).arg(ppp->m_type);
1998         */
1999         ASSERT_X(isEmpty(), QString("Failed to proper apply the non-empty presOf %1").arg(dump()).toLocal8Bit());
2000     } else {
2001         //ASSERT_X(nodes.count() == 1, "Oha. The axis contains more then one note. It's not clear what to do in such cases...");
2002         if (nodes.count() >= 2) warnMsooXml << "TODO The axis contains more then one note. It's not clear what to do in such cases...";
2003         context->setCurrentNode( nodes.first() );
2004     }
2005 }
2006 
2007 /****************************************************************************************************/
2008 
2009 IfAtom* IfAtom::clone(Context* context) {
2010     IfAtom* atom = new IfAtom(m_isTrue);
2011     atom->m_argument = m_argument;
2012     atom->m_axis = m_axis;
2013     atom->m_function = m_function;
2014     atom->m_hideLastTrans = m_hideLastTrans;
2015     atom->m_name = m_name;
2016     atom->m_operator = m_operator;
2017     atom->m_ptType = m_ptType;
2018     atom->m_start = m_start;
2019     atom->m_step = m_step;
2020     atom->m_count = m_count;
2021     atom->m_value = m_value;
2022     foreach(QExplicitlySharedDataPointer<AbstractAtom> a, m_children)
2023         atom->addChild(a->clone(context));
2024     return atom;
2025 }
2026 
2027 void IfAtom::dump(Context* context, int level) {
2028     DEBUG_DUMP<<"name="<<m_name;
2029     //DEBUG_DUMP << "name=" << m_name << "argument=" << m_argument << "axis=" << m_axis << "count=" << m_count << "function=" << m_function << "hideLastTrans=" << m_hideLastTrans << "operator=" << m_operator << "dataPointType=" << m_ptType << "start=" << m_start << "step=" << m_step << "value=" << m_value;
2030     AbstractAtom::dump(context, level);
2031 }
2032 
2033 void IfAtom::readAll(Context* context, MsooXmlDiagramReader* reader) {
2034     const QXmlStreamAttributes attrs(reader->attributes());
2035     TRY_READ_ATTR_WITHOUT_NS_INTO(arg, m_argument)
2036     TRY_READ_ATTR_WITHOUT_NS_INTO(axis, m_axis)
2037     TRY_READ_ATTR_WITHOUT_NS_INTO(cnt, m_count)
2038     TRY_READ_ATTR_WITHOUT_NS_INTO(func, m_function)
2039     TRY_READ_ATTR_WITHOUT_NS_INTO(hideLastTrans, m_hideLastTrans)
2040     TRY_READ_ATTR_WITHOUT_NS_INTO(name, m_name)
2041     TRY_READ_ATTR_WITHOUT_NS_INTO(op, m_operator)
2042     TRY_READ_ATTR_WITHOUT_NS_INTO(ptType, m_ptType)
2043     TRY_READ_ATTR_WITHOUT_NS_INTO(st, m_start)
2044     TRY_READ_ATTR_WITHOUT_NS_INTO(step, m_step)
2045     TRY_READ_ATTR_WITHOUT_NS_INTO(val, m_value)
2046     AbstractAtom::readAll(context, reader);
2047 }
2048 
2049 bool IfAtom::isTrue() const { return m_isTrue; } // is true or false?
2050 
2051 bool IfAtom::testAtom(Context* context) {
2052     QList<AbstractNode*> axis = fetchAxis(context, m_axis, m_ptType, m_start, m_count, m_step);
2053     QString funcValue;
2054     if ( m_name == "Name21" )
2055     {
2056         PointNode* node = dynamic_cast<PointNode* >( context->currentNode() );
2057         Q_ASSERT( node );
2058         debugMsooXml << "RULE21: " << m_axis.count() << " nodeId: " << node->m_modelId;
2059     }
2060     if(m_function == "cnt") { // Specifies a count.
2061         funcValue = QString::number(axis.count());
2062     } else if(m_function == "depth") { // Specifies the depth.
2063         //int depth = 0;
2064         //for(AbstractNode* n = context->currentNode(); n; n = n->parent(), ++depth);
2065         //funcValue = depth;
2066         //TODO
2067         warnMsooXml<<"TODO func=depth";
2068     } else if(m_function == "maxDepth") { // Defines the maximum depth.
2069         //int depth = 0;
2070         //for(AbstractNode* n = context->currentNode(); n; n = n->parent(), ++depth);
2071         //funcValue = depth;
2072         //TODO
2073         warnMsooXml<<"TODO func=maxDepth";
2074     } else if(m_function == "pos") { // Retrieves the position of the node in the specified set of nodes.
2075         const int position = axis.indexOf(context->currentNode()) + 1;
2076         funcValue = QString::number(position);
2077         //TODO 1-based? what index for not-found?
2078         warnMsooXml<<"TODO func=pos funcValue="<<funcValue;
2079     } else if(m_function == "posEven") { // Returns 1 if the specified node is at an even numbered position in the data model.
2080         //const int position = axis.indexOf(context->currentNode())+1;
2081         //funcValue = position>=1 && position % 2 == 0 ? 1 : 0;
2082         //TODO
2083         warnMsooXml<<"TODO func=posEven";
2084     } else if(m_function == "posOdd") { // Returns 1 if the specified node is in an odd position in the data model.
2085         //const int position = axis.indexOf(context->currentNode())+1;
2086         //funcValue = position>=1 && position % 2 != 0 = 1 : 0;
2087         //TODO
2088         warnMsooXml<<"TODO func=posOdd";
2089     } else if(m_function == "revPos") { // Reverse position function.
2090         const int position = axis.indexOf(context->currentNode()) + 1;
2091         funcValue = axis.count()-position;
2092         //TODO lastIndexOf? 1-based? what index for not-found?
2093         warnMsooXml<<"TODO func=revPos";
2094     } else if(m_function == "var") { // Used to reference a variable.
2095         funcValue = context->m_parentLayout->variable(m_argument, true /* check parents */);
2096         if(funcValue.isEmpty()) { // if not defined then use default variable-values
2097             if(m_argument == QLatin1String("dir")) { // Specifies the direction of the diagram.
2098                 funcValue = "norm";
2099             } else {
2100                 warnMsooXml<<"TODO figure out default for variable="<<m_argument;
2101             }
2102         }
2103     }
2104 
2105     bool istrue = false;
2106     if(m_isTrue && !funcValue.isNull()) {
2107         if(m_operator == "equ") {
2108             istrue = funcValue == m_value;
2109         } else {
2110             bool isInt;
2111             const int funcValueInt = funcValue.toInt(&isInt);
2112             const int valueInt = isInt ? m_value.toInt(&isInt) : 0;
2113             if(!isInt) {
2114                 // right, that's untested atm since I didn't found a single document that does it and the specs don't cover
2115                 // such "details" anyways so it seems. So, if you run into this then it's up to you to fix it :)
2116                 warnMsooXml<<"TODO figure out how non-integer comparison is expected to work";
2117             }
2118             if(m_operator == QLatin1String("gt")) {
2119                 istrue = isInt ? funcValueInt > valueInt : funcValue > m_value;
2120             } else if(m_operator == QLatin1String("gte")) {
2121                 istrue = isInt ? funcValueInt >= valueInt : funcValue >= m_value;
2122             } else if(m_operator == QLatin1String("lt")) {
2123                 istrue = isInt ? funcValueInt < valueInt : funcValue < m_value;
2124             } else if(m_operator == QLatin1String("lte")) {
2125                 istrue = isInt ? funcValueInt <= valueInt : funcValue <= m_value;
2126             } else if(m_operator == QLatin1String("neq")) {
2127                 istrue = isInt ? funcValueInt != valueInt : funcValue != m_value;
2128             } else {
2129                 warnMsooXml<<"Unexpected operator="<<m_operator<<"name="<<m_name;
2130             }
2131         }
2132     }
2133     //debugMsooXml<<"name="<<m_name<<"value1="<<funcValue<<"value2="<<m_value<<"operator="<<m_operator<<"istrue="<<istrue;
2134     return istrue;
2135 }
2136 
2137 /****************************************************************************************************/
2138 
2139 ChooseAtom* ChooseAtom::clone(Context* context) {
2140     ChooseAtom* atom = new ChooseAtom;
2141     atom->m_name = m_name;
2142     foreach(QExplicitlySharedDataPointer<AbstractAtom> a, m_children)
2143         atom->addChild(a->clone(context));
2144     return atom;
2145 }
2146 
2147 void ChooseAtom::dump(Context* context, int level) {
2148     DEBUG_DUMP << "name=" << m_name;
2149     AbstractAtom::dump(context, level);
2150 }
2151 
2152 void ChooseAtom::readAll(Context* context, MsooXmlDiagramReader* reader) {
2153     const QXmlStreamAttributes attrs(reader->attributes());
2154     TRY_READ_ATTR_WITHOUT_NS_INTO(name, m_name)
2155     AbstractAtom::readAll(context, reader);
2156 }
2157 
2158 void ChooseAtom::readElement(Context* context, MsooXmlDiagramReader* reader) {
2159     if(reader->isStartElement()) {
2160         if(reader->qualifiedName() == QLatin1String("dgm:if")) {
2161             QExplicitlySharedDataPointer<AbstractAtom> n(new IfAtom(true));
2162             addChild(n);
2163             n->readAll(context, reader);
2164         } else if(reader->qualifiedName() == QLatin1String("dgm:else")) {
2165             QExplicitlySharedDataPointer<AbstractAtom> n(new IfAtom(false));
2166             addChild(n);
2167             n->readAll(context, reader);
2168         }
2169     }
2170 }
2171 
2172 void ChooseAtom::build(Context* context) {
2173     // build up list of IfAtom's that match the defined condition
2174     QVector< QExplicitlySharedDataPointer<AbstractAtom> > ifResult;
2175     QVector< QExplicitlySharedDataPointer<AbstractAtom> > elseResult;
2176     while(!m_children.isEmpty()) {
2177         QExplicitlySharedDataPointer<AbstractAtom> atom = m_children.first();
2178         m_children.remove(0); // detach child
2179         IfAtom* ifatom = static_cast<IfAtom*>(atom.data());
2180         if(ifatom->isTrue()) {
2181             if(ifatom->testAtom(context)) {
2182                 ifResult.append(atom);
2183             }
2184         } else {
2185             elseResult.append(atom);
2186         }
2187     }
2188 
2189 #if 0
2190     // move the children of the selected IfAtom's to our parent
2191     int index = m_parent->indexOfChild(this);
2192     Q_ASSERT(index >= 0);
2193     typedef QVector< QExplicitlySharedDataPointer< AbstractAtom > > AtomPList;
2194     foreach( QExplicitlySharedDataPointer<AbstractAtom> atom, ifResult.isEmpty() ? elseResult : ifResult ) {
2195         AtomPList listResult = atom->children();
2196         // move the constraints to the parent's m_constraintsToBuild
2197         AtomPList::iterator it = std::stable_partition( listResult.begin(), listResult.end(), ConstraintPredicate() );    
2198         std::copy( it, listResult.end(), std::back_inserter( context->m_parentLayout->m_constraintsToBuild ) );
2199         listResult.erase( it, listResult.end() );
2200         // and move the remaining atom's to the parent
2201         foreach( QExplicitlySharedDataPointer<AbstractAtom> a, listResult ) {
2202             atom->removeChild( a );
2203             m_parent->insertChild( ++index, a );
2204             a->build( context );
2205         }
2206     }
2207     QExplicitlySharedDataPointer<AbstractAtom> ptr(this);
2208     m_parent->removeChild(ptr);
2209 #else
2210     // move the children of the selected IfAtom's to our parent
2211     int index = m_parent->indexOfChild(this);
2212     Q_ASSERT(index >= 0);
2213     QVector< QExplicitlySharedDataPointer<AbstractAtom> > atoms;
2214     foreach( QExplicitlySharedDataPointer<AbstractAtom> atom, ifResult.isEmpty() ? elseResult : ifResult ) {
2215         IfAtom * ifAtom = dynamic_cast< IfAtom* >( atom.data() );
2216         if ( ifAtom )
2217             debugMsooXml << "atomNameChosen" << ifAtom->m_name;
2218         foreach( QExplicitlySharedDataPointer<AbstractAtom> a, atom->children() ) {
2219             atom->removeChild( a );
2220             m_parent->insertChild( ++index, a );
2221             atoms.append( a );
2222         }
2223     }
2224 
2225     // and finally detach ourself from our parent since we are done now
2226     QExplicitlySharedDataPointer<AbstractAtom> ptr(this);
2227     m_parent->removeChild(ptr);
2228 
2229     // and start building the moved children
2230     foreach( QExplicitlySharedDataPointer<AbstractAtom> atom, atoms ) {
2231         atom->build( context );
2232     }
2233 #endif
2234 
2235 }
2236 
2237 /****************************************************************************************************/
2238 
2239 ForEachAtom* ForEachAtom::clone(Context* context) {
2240     ForEachAtom* atom = new ForEachAtom;
2241     atom->m_axis = m_axis;
2242     atom->m_hideLastTrans = m_hideLastTrans;
2243     atom->m_name = m_name;
2244     atom->m_ptType = m_ptType;
2245     atom->m_reference = m_reference;
2246     atom->m_start = m_start;
2247     atom->m_step = m_step;
2248     atom->m_count = m_count;
2249     foreach(QExplicitlySharedDataPointer<AbstractAtom> a, m_children)
2250         atom->addChild(a->clone(context));
2251     return atom;
2252 }
2253 
2254 QString ForEachAtom::dump() const {
2255     QString s;
2256     if(!m_name.isEmpty()) s += QString("name=%1 ").arg(m_name);
2257     if(!m_axis.isEmpty()) s += QString("axis=%1 ").arg(m_axis);
2258     if(!m_ptType.isEmpty()) s += QString("ptType=%1 ").arg(m_ptType);
2259     if(!m_reference.isEmpty()) s += QString("reference=%1 ").arg(m_reference);
2260     if(!m_start.isEmpty()) s += QString("start=%1 ").arg(m_start);
2261     if(!m_step.isEmpty()) s += QString("step=%1 ").arg(m_step);
2262     if(!m_count.isEmpty()) s += QString("count=%1 ").arg(m_count);
2263     if(!m_hideLastTrans.isEmpty()) s += QString("hideLastTrans=%1 ").arg(m_hideLastTrans);
2264     return s.trimmed();
2265 }
2266 
2267 void ForEachAtom::dump(Context* context, int level) {
2268     DEBUG_DUMP << dump();
2269     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, m_children)
2270        atom->dump(context, level + 1);
2271 }
2272 
2273 void ForEachAtom::readAll(Context* context, MsooXmlDiagramReader* reader) {
2274     const QXmlStreamAttributes attrs(reader->attributes());
2275     TRY_READ_ATTR_WITHOUT_NS_INTO(axis, m_axis)
2276     TRY_READ_ATTR_WITHOUT_NS_INTO(cnt, m_count)
2277     TRY_READ_ATTR_WITHOUT_NS_INTO(hideLastTrans, m_hideLastTrans)
2278     TRY_READ_ATTR_WITHOUT_NS_INTO(name, m_name)
2279     TRY_READ_ATTR_WITHOUT_NS_INTO(ptType, m_ptType)
2280     TRY_READ_ATTR_WITHOUT_NS_INTO(ref, m_reference)
2281     TRY_READ_ATTR_WITHOUT_NS_INTO(st, m_start)
2282     TRY_READ_ATTR_WITHOUT_NS_INTO(step, m_step)
2283     AbstractAtom::readAll(context, reader);
2284 }
2285 
2286 void ForEachAtom::build(Context* context) {
2287     // determinate which children are selected
2288     QList<AbstractNode*> axis = fetchAxis(context, m_axis, m_ptType, m_start, m_count, m_step);
2289     typedef QPair<AbstractNode*, QList<QExplicitlySharedDataPointer<AbstractAtom> > > NodePair;
2290     QList<NodePair> newChildren;
2291     foreach(AbstractNode* node, axis) {
2292         QList<QExplicitlySharedDataPointer<AbstractAtom> > list;
2293         foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, m_children) {
2294             QExplicitlySharedDataPointer<AbstractAtom> atomCopy(atom->clone(context));
2295             /*
2296             if ( LayoutNodeAtom* layoutAtom = dynamic_cast< LayoutNodeAtom* >( atomCopy.data() ) ) {
2297                 Q_ASSERT(layoutAtom->axis(context).isEmpty());
2298                 layoutAtom->setAxis( context, QList< AbstractNode* >() << node );
2299             }
2300             */
2301             list.append(atomCopy);
2302         }
2303         newChildren.append(NodePair(node, list));
2304     }
2305 
2306     // move the selected children to our parent
2307     int index = m_parent->indexOfChild(this);
2308     Q_ASSERT(index >= 0);
2309     foreach(NodePair p, newChildren) {
2310         foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, p.second) {
2311             m_parent->insertChild(++index, atom);
2312         }
2313     }
2314 
2315     // detach ourself from our parent since we will evaluate the forEach once and forever and won't need it afterwards.
2316     QExplicitlySharedDataPointer<AbstractAtom> ptr(this);
2317     m_parent->removeChild(ptr);
2318 
2319     // and finally build the selected children which needs to be done here cause our own parent will deal
2320     // with a copy of it's children-list and will not know about it's new children during the build.
2321     AbstractNode* oldCurrentNode = context->currentNode();
2322     foreach(NodePair p, newChildren) {
2323         context->setCurrentNode(p.first); // move on to the next node        
2324         foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, p.second) {
2325             atom->build(context);
2326         }
2327     }
2328     context->setCurrentNode(oldCurrentNode);
2329 }
2330 
2331 /****************************************************************************************************/
2332 
2333 AbstractAlgorithm::AbstractAlgorithm() : m_context(0), m_oldCurrentNode(0) {}
2334 
2335 AbstractAlgorithm::~AbstractAlgorithm() {
2336     if(m_context) {
2337         m_context->m_parentLayout = m_parentLayout;
2338         m_context->setCurrentNode(m_oldCurrentNode);
2339     }
2340     qDeleteAll( doubleLayoutContext );
2341 }
2342 
2343 Context* AbstractAlgorithm::context() const { return m_context; }
2344 LayoutNodeAtom* AbstractAlgorithm::layout() const { return m_layout.data(); }
2345 LayoutNodeAtom* AbstractAlgorithm::parentLayout() const { return m_parentLayout.data(); }
2346 
2347 QList<LayoutNodeAtom*> AbstractAlgorithm::childLayouts() const {
2348     QList<LayoutNodeAtom*> result;
2349     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, m_layout->children())
2350         if(LayoutNodeAtom* l = dynamic_cast<LayoutNodeAtom*>(atom.data()))
2351             result.append(l);
2352     return result;
2353 }
2354 
2355 void AbstractAlgorithm::setNodePosition(LayoutNodeAtom* l, qreal x, qreal y, qreal w, qreal h) {
2356 //     QStringList removeList;
2357     l->m_values["l"] = parentLayout()->finalValues()["l"] + x;
2358     l->m_values["t"] = parentLayout()->finalValues()["t"] + y;
2359 //     removeList << "l" << "t";
2360     if (w >= 0.0) {
2361         l->m_values["w"] = w;
2362 //         removeList << "w";
2363     }
2364     if (h >= 0.0) {
2365         l->m_values["h"] = h;
2366 //         removeList << "h";
2367     }
2368     //l->m_values["ctrX"] = 0.0;
2369     //l->m_values["ctrY"] = 0.0;
2370     //l->m_values["r"] = l->m_values["l"] + l->m_values["w"];
2371     //l->m_values.remove("ctrX");
2372     //l->m_values.remove("ctrY");
2373 //     removeList << "ctrX" << "ctrY";
2374 //     foreach(const QString &s, removeList) {
2375 //         //l->m_factors[s] = 1.0;
2376 //         //l->m_countFactors[s] = 1;
2377 //         l->m_factors.remove(s);
2378 //         l->m_countFactors.remove(s);
2379 //     }
2380     l->m_needsReinit = false; // we initialized things above already
2381     l->m_needsRelayout = true; // but we clearly need a layout now
2382     l->m_childNeedsRelayout = true; // and our children need to be relayouted too now
2383 }
2384 
2385 qreal AbstractAlgorithm::defaultValue(const QString& type, const QMap<QString, qreal>& values) {
2386     qreal value = virtualGetDefaultValue(type, values);
2387     if(value < 0.0) {
2388         // If the layout-algorithm doesn't define a default-value then use one of the common default-values.
2389         // See also http://social.msdn.microsoft.com/Forums/en/os_binaryfile/thread/7c823650-7913-4e63-970f-1c5dab3450c4
2390         if (type == "primFontSz") {
2391             value = 36;
2392 //         } else if (type == "tMarg") {
2393 //             Q_ASSERT(values.contains("primFontSz"));
2394 //             value = values.value("primFontSz") * 0.56;
2395 //         } else if (type == "lMarg") {
2396 //             Q_ASSERT(values.contains("primFontSz"));
2397 //             value = values.value("primFontSz") * 0.40;
2398 //         } else if (type == "rMarg") {
2399 //             Q_ASSERT(values.contains("primFontSz"));
2400 //             value = values.value("primFontSz") * 0.42;
2401 //         } else if (type == "bMarg") {
2402 //             Q_ASSERT(values.contains("primFontSz"));
2403 //             value = values.value("primFontSz") * 0.60;
2404         } else if (type.startsWith(QLatin1String("user"))) { // userA, userB, userC, etc.
2405             bool ok;
2406             const qreal v = layout()->variable(type, true /* checkParents */).toDouble(&ok);
2407             value = ok ? v : 0.0;
2408         }
2409     }
2410     return value;
2411 }
2412 
2413 void AbstractAlgorithm::doInit(Context* context, QExplicitlySharedDataPointer<LayoutNodeAtom> layout) {
2414     m_context = context;
2415     m_layout = layout;
2416     m_parentLayout = m_context->m_parentLayout;
2417     m_context->m_parentLayout = m_layout;
2418     m_oldCurrentNode = m_context->currentNode();
2419     virtualDoInit();
2420 }
2421 
2422 void AbstractAlgorithm::doLayout() {
2423     virtualDoLayout();
2424 }
2425 
2426 void AbstractAlgorithm::doLayoutChildren() {
2427     virtualDoLayoutChildren();
2428 }
2429 
2430 qreal AbstractAlgorithm::virtualGetDefaultValue(const QString&, const QMap<QString, qreal>&) {
2431     return -1.0;
2432 }
2433 
2434 void AbstractAlgorithm::virtualDoInit() {
2435     if(layout()->m_needsReinit) {
2436         layout()->m_needsReinit = false; // initialization done
2437         //layout()->m_values = parentLayout()->m_values;
2438         //layout()->m_factors = parentLayout()->m_factors;
2439         //layout()->m_countFactors = parentLayout()->m_countFactors;
2440     }
2441     //QMap<QString, qreal> values = parentLayout()->finalValues();
2442     //Q_ASSERT(values["l"] >= 0.0);
2443     //Q_ASSERT(values["t"] >= 0.0);
2444     //Q_ASSERT(values["w"] > 0.0);
2445     //Q_ASSERT(values["h"] > 0.0);
2446     //Q_ASSERT(values["ctrX"] >= 0.0);
2447     //Q_ASSERT(values["ctrY"] >= 0.0);
2448 }
2449 
2450 // http://msdn.microsoft.com/en-us/library/dd439461(v=office.12).aspx
2451 void AbstractAlgorithm::virtualDoLayout() {
2452     Q_ASSERT( layout() );
2453     Q_ASSERT( !name().isEmpty() );
2454     const QString __name = name();
2455     debugMsooXml << "layout=" << layout()->m_name << "algorithm=" << __name;//name();
2456 
2457     // Specifies the aspect ratio (width to height) of the composite node to use when determining child constraints. A value of 0 specifies to
2458     // leave the width and height constraints unaltered. The algorithm may temporarily shrink one dimension to achieve the specified ratio.
2459     // For example, if a composite node has a width constraint of 20 and height constraint of 10, and if the value of ar is 1.5, the composite
2460     // algorithm uses a width value of 15 to calculate the composite node’s child constraints. However, the algorithm does not propagate this
2461     // value to other nodes.
2462     qreal aspectRatio = layout()->algorithmParam("ar", "0").toDouble();
2463     if (aspectRatio != 0.0)
2464         layout()->m_values["w"] = layout()->finalValues()["h"] * aspectRatio;
2465 
2466     //QVector< QExplicitlySharedDataPointer< LayoutNodeAtom > > allChilds = layout()->childrenLayouts();
2467     //foreach( QExplicitlySharedDataPointer< LayoutNodeAtom > curChild, allChilds )
2468     //    setNodePosition( curChild.data(), layout()->finalValues()[ "l" ], layout()->finalValues()[ "t" ], layout()->finalValues()[ "w" ], layout()->finalValues()[ "h" ] );        
2469 
2470     foreach( QExplicitlySharedDataPointer< ConstraintAtom > constr, layout()->constraints() )
2471         constr->applyConstraint( context(), layout() );
2472 
2473     foreach( QExplicitlySharedDataPointer< ShapeAtom > shape, layout()->shapes() ) 
2474         foreach( QExplicitlySharedDataPointer< AdjustAtom > adj, shape->adjustments() ){
2475             adj->applyAdjustment( context(), layout() );
2476     }
2477 
2478     //foreach( QExplicitlySharedDataPointer< LayoutNodeAtom > curChild, allChilds )
2479     //    setNodePosition( curChild.data(), layout()->finalValues()[ "l" ], layout()->finalValues()[ "t" ], layout()->finalValues()[ "w" ], layout()->finalValues()[ "h" ] );        
2480 }
2481 
2482 void AbstractAlgorithm::virtualDoLayoutChildren() {
2483     foreach(QExplicitlySharedDataPointer<AbstractAtom> atom, layout()->children()) {
2484         if ( LayoutNodeAtom* layAtom = dynamic_cast< LayoutNodeAtom* >( atom.data() ) )
2485             layAtom->setNeedsRelayout( true );
2486         atom->layoutAtom(context());
2487     }
2488 }
2489 
2490 /****************************************************************************************************/
2491 
2492 // http://msdn.microsoft.com/en-us/library/dd439461(v=office.12).aspx
2493 qreal CompositeAlgorithm::virtualGetDefaultValue(const QString& type, const QMap<QString, qreal>& values) {
2494     Q_UNUSED(values);
2495     qreal value = -1.0;
2496     if (type == "w" || type == "h") {
2497         value = 100;
2498     } else if (type == "l" || type == "t") {
2499         value = 0;
2500     } else if (type == "wOff" || type == "hOff" || type == "lOff" || type == "ctrXOff" || type == "rOff" || type == "tOff" || type == "ctrYOff" || type == "bOff") {
2501         value = 0;
2502     }
2503     return value;
2504 }
2505 
2506 /****************************************************************************************************/
2507 
2508 qreal ConnectorAlgorithm::connectorDistance() const {
2509     QPair<LayoutNodeAtom*,LayoutNodeAtom*> neighbors = layout()->neighbors();
2510     LayoutNodeAtom* srcAtom = neighbors.first;
2511     LayoutNodeAtom* dstAtom = neighbors.second;
2512     return (srcAtom && dstAtom) ? srcAtom->distanceTo(dstAtom) : 0.0;
2513 }
2514 
2515 qreal ConnectorAlgorithm::virtualGetDefaultValue(const QString& type, const QMap<QString, qreal>& values) {
2516     qreal value = -1.0;
2517     if (type == "w" || type == "h") {
2518         value = 100;
2519     } else if (type == "connDist") {
2520         value = connectorDistance();
2521     } else if (type == "stemThick") {
2522         value = values.value("h") * 0.60;
2523     } else if (type == "begMarg" || type == "endMarg") {
2524         value = 3.175;
2525     } else if (type == "begPad") {
2526         value = connectorDistance() * 0.22;
2527     } else if (type == "endPad") {
2528         value = connectorDistance() * 0.25;
2529     } else if (type == "bendDist") {
2530         value = connectorDistance() * 0.50;
2531     } else if (type == "hArH") {
2532         value = values.value("h") * 1.00;
2533     } else if (type == "wArH") {
2534         value = values.value("h") * 0.50;
2535     } else if (type == "diam") {
2536         value = connectorDistance() * 1.00;
2537     }
2538     return value;
2539 }
2540 
2541 void ConnectorAlgorithm::virtualDoLayoutChildren() {
2542     // Get a list of all child-layouts of our parent to apply the connector-algorithm on our direct
2543     // neighbors. Also while on it also determinate our own position in that list.
2544     QPair<LayoutNodeAtom*,LayoutNodeAtom*> neighbors = layout()->neighbors();
2545     LayoutNodeAtom* srcAtom = neighbors.first;
2546     LayoutNodeAtom* dstAtom = neighbors.second;
2547     if(!srcAtom || !dstAtom) {
2548         if(layout()->parent()) {
2549             // If there is no source- or destination to connect with then hide our layout by detaching it.
2550             layout()->parent()->removeChild(QExplicitlySharedDataPointer<AbstractAtom>(layout()));
2551         }
2552         return;
2553     }
2554 
2555     // Beginning and end points defines different connection sites available on a node. This can be one of the following values;
2556     // * auto       Specifies that the algorithm will determine the best connection site to use.
2557     // * bCtr       Specifies that the bottom, center connection site is to be used.
2558     // * bL         Specifies that the bottom, left connection site is to be used.
2559     // * bR         Specifies that the bottom right connection site is to be used.
2560     // * ctr        Specifies that the center connection site is to be used.
2561     // * midL       Specifies that the middle left connection site is to be used.
2562     // * midR       Specifies that the middle right connection site is to be used.
2563     // * radial     Specifies connections along a radial path to support the use of connections in cycle diagrams.
2564     // * tCtr       Specifies that the top center connection site is to be used.
2565     // * tL         Specifies that the top left connection site is to be used.
2566     // * tR         Specifies that the top right connection site is to be used.
2567     QString begPts = layout()->algorithmParam("begPts");
2568     QString endPts = layout()->algorithmParam("endPts");
2569     //if (!begPts.isEmpty() && !endPts.isEmpty()) debugMsooXml<<"begPts="<<begPts<<"endPts="<<endPts;
2570 
2571     QMap<QString, qreal> srcValues = srcAtom->finalValues();
2572     QMap<QString, qreal> dstValues = dstAtom->finalValues();
2573     qreal srcX = srcValues["l"];//+srcValues["ctrX"];
2574     qreal srcY = srcValues["t"];//+srcValues["ctrY"];
2575     qreal srcW = srcValues["w"];
2576     qreal srcH = srcValues["h"];
2577     qreal dstX = dstValues["l"];//+dstValues["ctrX"];
2578     qreal dstY = dstValues["t"];//+dstValues["ctrY"];
2579     qreal dstW = dstValues["w"];
2580     qreal dstH = dstValues["h"];
2581     qreal srcCX = srcX + srcW/2.0;
2582     qreal srcCY = srcY + srcH/2.0;
2583     qreal dstCX = dstX + dstW/2.0;
2584     qreal dstCY = dstY + dstH/2.0;
2585     layout()->m_rotateAngle = atan2(dstCY - srcCY, dstCX - srcCX) * 180 / M_PI;
2586 
2587     AbstractAlgorithm::virtualDoLayoutChildren();
2588 }
2589 
2590 /****************************************************************************************************/
2591 
2592 qreal CycleAlgorithm::virtualGetDefaultValue(const QString& type, const QMap<QString, qreal>&) {
2593     qreal value = -1.0;
2594     if (type == "w" || type == "h") {
2595         value = 100;
2596     } else if (type == "diam") {
2597         value = 0;
2598     } else if (type == "sibSp") {
2599         value = 0;
2600     } else if (type == "sp") {
2601         value = 0;
2602     }
2603     return value;
2604 }
2605 
2606 // http://msdn.microsoft.com/en-us/library/dd439451(v=office.12).aspx
2607 void CycleAlgorithm::virtualDoLayout() {
2608     AbstractAlgorithm::virtualDoLayout();
2609 
2610     QList<LayoutNodeAtom*> childs = childLayouts();
2611     ASSERT_X(!childs.isEmpty(), QString("Layout %1 does not have child-layouts").arg(layout()->m_name));
2612     if (childs.isEmpty()) return;
2613 
2614     // Specifies the angle at which the first shape is placed. Angles are in degrees, measured clockwise from a line pointing straight upward from the center of the cycle.
2615     int startAngel = layout()->algorithmParam("stAng", "0").toInt();
2616     // Specifies the angle the cycle spans. Final shapealign text is placed at stAng+spanAng, unless spanAng=360. In that case, the algorithm places the text so that shapes do not overlap.
2617     int spanAngel = layout()->algorithmParam("spanAng", "360").toInt();
2618 
2619     // Specifies where to place nodes in relation to the center circle.
2620     bool firstNodeInCenter = layout()->algorithmParam("ctrShpMap", "none") == "fNode";
2621 
2622     LayoutNodeAtom* nodeInCenter = firstNodeInCenter ? childs.takeFirst() : 0;
2623     const qreal childsCount = childs.count();
2624 
2625     QMap<QString, qreal> values = layout()->finalValues();
2626     const qreal w = values["w"];
2627     const qreal h = values["h"];
2628     const qreal rx = w / 2.0;
2629     const qreal ry = h / 2.0;
2630     qreal num = 360.0 / childsCount;
2631     const bool inverse = startAngel > spanAngel;
2632     if(inverse) num = -num;
2633 
2634     qreal spacing = values.value("sibSp");
2635     qreal dw = ( (2.0 * M_PI * rx - spacing) / childsCount );
2636     qreal dh = ( (2.0 * M_PI * ry - spacing) / childsCount );
2637 
2638     if(nodeInCenter) {
2639         //setNodePosition(nodeInCenter, rx, ry, -1, -1); //dw, dh);
2640         setNodePosition(nodeInCenter, rx, ry, dw, dh);
2641     }
2642 
2643     //for(qreal degree = startAngel; (!childs.isEmpty()) && (inverse ? degree > spanAngel : degree <= spanAngel); degree -= num) {
2644     for(qreal degree = startAngel; (!childs.isEmpty()) && (inverse ? degree > spanAngel : degree <= spanAngel); degree += num) {
2645         const qreal radian = (degree - 90.0) * (M_PI / 180.0);
2646         const qreal x = rx + cos(radian) * rx;
2647         const qreal y = ry + sin(radian) * ry;
2648         LayoutNodeAtom* l = childs.takeFirst();
2649         //setNodePosition(l, x, y, -1, -1);
2650         setNodePosition(l, x, y, dw, dh);
2651     }
2652 }
2653 
2654 /****************************************************************************************************/
2655 
2656 qreal LinearAlgorithm::virtualGetDefaultValue(const QString& type, const QMap<QString, qreal>& values) {
2657     Q_UNUSED(type);
2658     Q_UNUSED(values);
2659     qreal value = -1.0;
2660     /*
2661     if (type == "w" || type == "h") {
2662         value = 100;
2663     }
2664     */
2665     return value;
2666 }
2667 
2668 // http://msdn.microsoft.com/en-us/library/dd439457%28v=office.12%29.aspx
2669 void LinearAlgorithm::virtualDoLayout() {
2670     AbstractAlgorithm::virtualDoLayout();
2671     // TODO handle infinite values somehow sensible
2672 #if 1
2673     QMap< QString, qreal > values = layout()->finalValues();
2674     QString direction = layout()->algorithmParam( "linDir", "fromL" );
2675     qreal x = 0;
2676     qreal y = 0;
2677     if ( direction  == "fromR" )
2678     {
2679         x = values[ "w" ];
2680     }
2681     if ( direction == "fromB" )
2682     {
2683         y = values[ "h" ];
2684     }
2685     QList<LayoutNodeAtom*> childs = childLayouts();
2686     if ( childs.isEmpty() )
2687         return;
2688     LayoutNodeAtom *firstNSpaceNode = nullptr;
2689     LayoutNodeAtom *lastNSpaceNode = nullptr;
2690     debugMsooXml << values;
2691     for ( int i = 0; i < childs.count(); ++ i )
2692     {
2693         if ( direction  == "fromL" )
2694         {
2695             childs[ i ]->m_values[ "l" ] = x;        
2696             debugMsooXml << "XVAL: " << x;
2697             x = childs[ i ]->finalValues()[ "r" ];
2698         }
2699         else if ( direction == "fromR" )
2700         {
2701             childs[ i ]->m_values[ "r" ] = x;
2702             debugMsooXml << "XVAL: " << x;
2703             x = childs[ i ]->finalValues()[ "l" ];
2704         }
2705         else if ( direction == "fromT" )
2706         {
2707             debugMsooXml << "TVAL: " << childs[ i ]->finalValues()[ "t" ];
2708             debugMsooXml << "BVAL: " << childs[ i ]->finalValues()[ "b" ];
2709             childs[ i ]->m_values[ "t" ] = y;
2710             debugMsooXml << "YVAL: " << y;
2711             y = childs[ i ]->finalValues()[ "b" ];
2712         }
2713         else if ( direction == "fromB" )
2714         {
2715             childs[ i ]->m_values[ "b" ] = y;
2716             debugMsooXml << "YVAL: " << y;
2717             y = childs[ i ]->finalValues()[ "t" ];
2718         }
2719         if (childs[ i ]->algorithm()->m_type != AlgorithmAtom::SpaceAlg) {
2720             if ( !firstNSpaceNode )
2721                 firstNSpaceNode = childs[ i ];
2722             lastNSpaceNode = childs[ i ];
2723         }
2724     }
2725     const qreal width = lastNSpaceNode->finalValues()[ "r" ] -  firstNSpaceNode->finalValues()[ "l" ];
2726     const qreal height = lastNSpaceNode->finalValues()[ "b" ] -  firstNSpaceNode->finalValues()[ "t" ];
2727     const qreal widthStretchFactor = values[ "w" ] / width;
2728     const qreal heightStretchFactor = values[ "h" ] / height;
2729     const qreal xOffset = firstNSpaceNode->finalValues()[ "l" ]  < 0 ? -firstNSpaceNode->finalValues()[ "l" ] : 0;
2730     const qreal yOffset = firstNSpaceNode->finalValues()[ "t" ]  < 0 ? -firstNSpaceNode->finalValues()[ "t" ] : 0;
2731     const qreal xOffsetRect = values[ "l" ];
2732     const qreal yOffsetRect = values[ "t" ];
2733     debugMsooXml << width;
2734     debugMsooXml << widthStretchFactor;
2735     debugMsooXml << xOffset;
2736 
2737     for ( int i = 0; i < childs.count(); ++i )
2738     {
2739         if ( direction == "fromL" || direction == "formR" )
2740         {
2741             const qreal aspectRatio = childs[ i ]->finalValues()[ "h" ] / childs[ i ]->finalValues()[ "w" ];
2742             const qreal heightRatio = widthStretchFactor * aspectRatio;
2743             qreal oldCenterX = childs[ i ]->finalValues()[ "ctrX" ];
2744             childs[ i ]->m_values[ "w" ] = childs[ i ]->finalValues()[ "w" ] * widthStretchFactor;
2745             childs[ i ]->m_values[ "h" ] = childs[ i ]->finalValues()[ "h" ] * heightRatio;
2746             oldCenterX *= widthStretchFactor;
2747             oldCenterX += xOffset * widthStretchFactor + xOffsetRect;
2748             childs[ i ]->m_values[ "ctrX" ] = oldCenterX;
2749             childs[ i ]->m_values[ "ctrY" ] = childs[ i ]->finalValues()[ "ctrY" ] + yOffsetRect;
2750         }
2751         else
2752         {
2753             const qreal aspectRatio = childs[ i ]->finalValues()[ "w" ] / childs[ i ]->finalValues()[ "h" ];
2754             const qreal widthRatio = heightStretchFactor * aspectRatio;
2755             qreal oldCenterY = childs[ i ]->finalValues()[ "ctrY" ];
2756             childs[ i ]->m_values[ "w" ] = childs[ i ]->finalValues()[ "w" ] * widthRatio;
2757             childs[ i ]->m_values[ "h" ] = childs[ i ]->finalValues()[ "h" ] * heightStretchFactor;
2758             oldCenterY *= heightStretchFactor;
2759             oldCenterY += yOffset * heightStretchFactor + yOffsetRect;
2760             childs[ i ]->m_values[ "ctrY" ] = oldCenterY;
2761             childs[ i ]->m_values[ "ctrX" ] = childs[ i ]->finalValues()[ "ctrX" ] + xOffsetRect;
2762         }
2763 
2764     }
2765 #endif
2766 #if 0
2767     QString direction = layout()->algorithmParam("linDir", "fromL");
2768     const qreal lMarg = layout()->finalValues()[ "lMarg" ];
2769     const qreal rMarg = layout()->finalValues()[ "rMarg" ];
2770     const qreal tMarg = layout()->finalValues()[ "tMarg" ];
2771     const qreal bMarg = layout()->finalValues()[ "bMarg" ];
2772     const qreal w = layout()->finalValues()["w"] - lMarg - rMarg;
2773     const qreal h = layout()->finalValues()["h"] - bMarg - tMarg;
2774 
2775     QList<LayoutNodeAtom*> childs = childLayouts();
2776     ASSERT_X(!childs.isEmpty(), QString("Layout %1 does not have child-layouts").arg(layout()->m_name));
2777     if (childs.isEmpty()) return;
2778 
2779     const qreal childsCount = childs.count();
2780     debugMsooXml << "REAL CHILD COUNTERRRRRRRRRRRRRR " << childsCount;
2781     const QSizeF usedSize = layout()->childrenUsedSize();
2782     const QSizeF totalSize = layout()->childrenTotalSize();
2783 
2784     int x, y, mx, my;
2785     x = y = mx = my = 0;
2786     if(direction == "fromL") {
2787         mx = w / childsCount;
2788         x = lMarg;
2789     } else if(direction == "fromR") {
2790         x = lMarg + w;
2791         mx = -(w / childsCount);
2792     } else if(direction == "fromT") {
2793         my = h / childsCount;
2794     } else if(direction == "fromB") {
2795         y = h;
2796         my = -(h / childsCount);
2797     }
2798 
2799     // calculate weights
2800     qreal currentX = x;
2801     qreal currentY = y;
2802     qreal currentWidth = 0;
2803     qreal currentHeight = 0;
2804     const int xFactor = mx >= 0 ? 1 : -1;
2805     const int yFactor = my >= 0 ? 1 : -1;
2806     foreach(LayoutNodeAtom* l, childs) {        
2807         QMap< QString, qreal > values = l->finalValues();
2808         if ( l->algorithmType() != AlgorithmAtom::SpaceAlg ) {
2809             debugMsooXml << "NODETYPE: SPACE";
2810             currentWidth = l->finalValues()[ "w" ] / usedSize.width() * w;
2811             currentHeight = l->finalValues()[ "h" ] / usedSize.height() * h;
2812             setNodePosition(l, currentX, currentY, currentWidth, currentHeight);
2813             if ( direction == "fromR" || direction == "fromL" )
2814                 currentX = currentX + xFactor * l->finalValues()[ "w" ];
2815             else
2816                 currentY = currentY + yFactor * l->finalValues()[ "h" ];
2817         } else {
2818             debugMsooXml << "NODETYPE: ELSE";
2819             currentWidth = l->finalValues()[ "w" ] / totalSize.width() * w;
2820             currentHeight = l->finalValues()[ "h" ] / totalSize.height() * h;
2821             if ( direction == "fromR" || direction == "fromL" )
2822                 currentX += currentWidth;
2823             else
2824                 currentY += currentHeight;
2825         }
2826     }
2827 #endif
2828 }
2829 
2830 /****************************************************************************************************/
2831 
2832 qreal SnakeAlgorithm::virtualGetDefaultValue(const QString& type, const QMap<QString, qreal>& values) {
2833     Q_UNUSED(values);
2834     qreal value = -1.0;
2835     if (type == "w" || type == "h") {
2836         value = 100;
2837     } else if (type == "alignOff" || type == "sp" || type == "begPad" || type == "endPad") {
2838         value = 0;
2839     }
2840     return value;
2841 }
2842 
2843 // http://msdn.microsoft.com/en-us/library/dd439436(v=office.12).aspx
2844 void SnakeAlgorithm::virtualDoLayout() {
2845     // Specifies from which corner the snake grows. For example, if the algorithm uses a top left value, the snake grows from the top left.
2846     const QString growDirection = layout()->algorithmParam("grDir", "tL");
2847     // Specifies whether nodes are arranged in rows or columns.
2848     const QString flowDirection = layout()->algorithmParam("flowDir");
2849     // Specifies the direction of the subsequent row or column. For example, if the algorithm initially places the nodes from left to right,
2850     // revDir places the nodes in the next row from right to left. However if the algorithm uses contDir, the nodes on the next row are
2851     // arranged from left to right.
2852     const bool inSameDirection = layout()->algorithmParam("contDir") != "revDir";
2853     // Specifies the offset.
2854     //const QString offset = layout()->algorithmParam("off");
2855 
2856     // Specifies the point at which the diagram starts to snake. The value bal specifies that snaking begin at an even number of rows and
2857     // columns. The value fixed specifies that snaking begin at a fixed point, for example, in a row that contains three nodes. The value
2858     // endCnv specifies that snaking begin when there is no more room for a shape in the row.
2859     //const QString breakpoint = layout()->algorithmParam("bkpt", "endCnv");
2860     // Specifies where the snake should break, if bkpt=fixed.
2861     //const int breakpointFixedValue = layout()->algorithmParam("bkPtFixedVal", "2").toInt();
2862 
2863     QList<LayoutNodeAtom*> childs = childLayouts();
2864     ASSERT_X(!childs.isEmpty(), QString("Layout %1 does not have child-layouts").arg(layout()->m_name));
2865     if (childs.isEmpty()) return;
2866 
2867     bool inRows = flowDirection != "column";
2868     const qreal w = layout()->finalValues()["w"];
2869     const qreal h = layout()->finalValues()["h"];
2870     qreal x = 0;
2871     qreal y = 0;
2872 
2873     if (growDirection == "tR") {
2874         x = w - childs.first()->finalValues()["w"];
2875     } else if (growDirection == "bL") {
2876         y = h - childs.first()->finalValues()["h"];
2877     } else if (growDirection == "bR") {
2878         x = w - childs.first()->finalValues()["w"];
2879         y = h - childs.first()->finalValues()["h"];
2880     }
2881 
2882     //TODO is hardcoding correct here? The specs say default is 100...
2883     qreal mx = 110;
2884     qreal my = 110;
2885     qreal dw = 100;
2886     qreal dh = 100;
2887     //TODO use direction
2888     foreach(LayoutNodeAtom* l, childs) {
2889         if(l->algorithmType() == AlgorithmAtom::SpaceAlg) continue; // specs says 'or does nothing' but not under which conditions :-/
2890         setNodePosition(l, x, y, dw, dh);
2891         if(!inSameDirection) inRows = !inRows;
2892         if(inRows) {
2893             y += my;
2894             if(y+my > h) {
2895                 x += mx;
2896                 y = 0;
2897             }
2898         } else {
2899             x += mx;
2900             if(x+mx > w) {
2901                 x = 0;
2902                 y += my;
2903             }
2904         }
2905     }
2906 }
2907 
2908 /****************************************************************************************************/
2909 
2910 qreal HierarchyAlgorithm::virtualGetDefaultValue(const QString& type, const QMap<QString, qreal>&) {
2911     qreal value = -1.0;
2912     if (type == "w" || type == "h") {
2913         value = 100;
2914     } else if (m_isRoot && (type == "alignOff" || type == "sp")) {
2915         value = 0;
2916     } else if (!m_isRoot && (type == "sibSp" || type == "secSibSp")) {
2917         value = 0;
2918     }
2919     return value;
2920 }
2921 
2922 // http://msdn.microsoft.com/en-us/library/dd439442(v=office.12).aspx
2923 // http://msdn.microsoft.com/en-us/library/dd439449(v=office.12).aspx
2924 void HierarchyAlgorithm::virtualDoLayout() {
2925     debugMsooXml<<"TODO Implement algorithm isRoot="<<m_isRoot;
2926     AbstractAlgorithm::virtualDoLayout();
2927 }
2928 
2929 /****************************************************************************************************/
2930 
2931 qreal PyramidAlgorithm::virtualGetDefaultValue(const QString& type, const QMap<QString, qreal>&) {
2932     qreal value = -1.0;
2933     if (type == "w" || type == "h") {
2934         value = 100;
2935     } else if (type == "pyraAcctRatio") {
2936         value = 0.33;
2937     }
2938     return value;
2939 }
2940 
2941 void PyramidAlgorithm::virtualDoLayout() {
2942     debugMsooXml<<"TODO Implement algorithm";
2943     AbstractAlgorithm::virtualDoLayout();
2944 }
2945 
2946 /****************************************************************************************************/
2947 
2948 //NOTE I start to assume that the parent layout-algorithms are also responsible for setting defaults at children
2949 //layout-algorithms. If that's the case then the question is how/where that happens. To bad the specs are
2950 //missing the most basic information :-(
2951 qreal SpaceAlg::virtualGetDefaultValue(const QString& type, const QMap<QString, qreal>& values) {
2952     Q_UNUSED(values);
2953     qreal value = -1.0;
2954     if (type == "w" || type == "h") {
2955         debugMsooXml<<"TODO type="<<type;
2956         value = 100; //TODO what default value is expected here?
2957     } else if (type == "sibSp") {
2958         debugMsooXml<<"TODO type="<<type;
2959         value = 0; //TODO what default value is expected here?
2960     }
2961     return value;
2962 }
2963 
2964 void SpaceAlg::virtualDoLayout() {
2965     // just don't do anything cause the space-algorithm is just a placeholder-algorithm
2966     AbstractAlgorithm::virtualDoLayout();
2967 }
2968 
2969 /****************************************************************************************************/
2970 
2971 qreal TextAlgorithm::virtualGetDefaultValue(const QString& type, const QMap<QString, qreal>& values) {
2972     qreal value = -1.0;
2973     if (type == "w" || type == "h") {
2974         value = 100;
2975     } else if (type == "primFontSz" || type == "secFontSize") {
2976         value = 100;
2977     } else if (type == "tMarg") {
2978         value = values.value("primFontSz") * 0.78;
2979     } else if (type == "bMarg") {
2980         value = values.value("primFontSz") * 0.60;
2981     } else if (type == "lMarg") {
2982         value = values.value("primFontSz") * 0.42;
2983     } else if (type == "rMarg") {
2984         value = values.value("primFontSz") * 0.42;
2985     }/* else if ( type == "r" && values.contains( "w" ) ) {
2986         value = values["l"] + values["w"];
2987     } else if ( type == "l" && values.contains( "r" ) && values.contains( "w" ) ) {
2988         value = values["r"] - values["w"];
2989     } else if ( type == "l" ) {
2990         value =  0;
2991     }*/
2992     return value;
2993 }
2994 
2995 void TextAlgorithm::virtualDoLayout() {
2996     //TODO implement the text-layout logic
2997     AbstractAlgorithm::virtualDoLayout();
2998 }