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