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 }