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