2
* This file is part of Office 2007 Filters for KOffice
4
* Copyright (C) 2010 Sebastian Sauer <sebsauer@kdab.com>
5
* Copyright (c) 2010 Carlos Licea <carlos@kdab.com>
6
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
8
* Contact: Suresh Chande suresh.chande@nokia.com
10
* This library is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Lesser General Public License
12
* version 2.1 as published by the Free Software Foundation.
14
* This library is distributed in the hope that it will be useful, but
15
* WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* Lesser General Public License for more details.
19
* You should have received a copy of the GNU Lesser General Public
20
* License along with this library; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26
#include "MsooXmlDiagramReader.h"
28
#define MSOOXML_CURRENT_NS "dgm"
29
#define MSOOXML_CURRENT_CLASS MsooXmlDiagramReader
30
#define BIND_READ_CLASS MSOOXML_CURRENT_CLASS
32
#include <MsooXmlReader_p.h>
33
#include <MsooXmlUtils.h>
34
#include <KoXmlWriter.h>
35
#include <KoGenStyles.h>
36
//#include <QXmlQuery>
37
//#include <QAbstractUriResolver>
40
namespace MSOOXML { namespace Diagram {
42
/****************************************************************************************************
43
* The following classes where designed after the way the dmg-namespace is described in the
44
* MSOOXML-specs and how it was done in oo.org.
47
* - http://wiki.services.openoffice.org/wiki/SmartArt
48
* - http://msdn.microsoft.com/en-us/magazine/cc163470.aspx
52
qDebug() << QString("%1Dgm::%2::%3").arg(QString(' ').repeated(level)).arg(typeid(this).name()).arg(__FUNCTION__) << this << "atom=" << m_tagName
54
qDebug() << QString("Dgm::%1::%2").arg(typeid(this).name()).arg(__FUNCTION__) << "atom=" << m_tagName
59
class ConnectionListNode;
65
/// The evaluation context that is passed around and contains all kind of state-informations.
69
AbstractNode* m_rootPoint;
70
ConnectionListNode* m_connections;
71
LayoutNodeAtom* m_rootLayout;
72
LayoutNodeAtom* m_parentLayout;
73
QMap<QString, LayoutNodeAtom*> m_layoutMap;
76
AbstractNode* currentNode() const { return m_currentNode; }
77
void setCurrentNode(AbstractNode* node);
79
AbstractNode* m_currentNode; // the moving context node
82
/****************************************************************************************************
83
* It follws the classes used within the data-model to build up a tree of data-nodes.
86
/// The AbstractNode is the base class to handle the diagram data-model (content of data1.xml).
90
const QString m_tagName;
91
explicit AbstractNode(const QString &tagName) : m_tagName(tagName), m_parent(0) {}
92
virtual ~AbstractNode() { qDeleteAll(m_children); }
93
virtual void dump(Context* context, int level) {
94
foreach(AbstractNode* node, m_children)
95
node->dump(context, level + 1);
97
virtual void readElement(Context*, MsooXmlDiagramReader*) {
99
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
100
while (!reader->atEnd()) {
101
QXmlStreamReader::TokenType tokenType = reader->readNext();
102
if(tokenType == QXmlStreamReader::Invalid || tokenType == QXmlStreamReader::EndDocument) break;
103
if (!reader->isStartElement() && reader->qualifiedName() == m_tagName) break;
104
readElement(context, reader);
107
AbstractNode* parent() const { return m_parent; }
108
QList<AbstractNode*> children() const { return m_children; }
109
void addChild(AbstractNode* node) {
110
Q_ASSERT(!node->m_parent);
111
node->m_parent = this;
112
m_children.append(node);
114
void removeChild(AbstractNode* node) {
115
Q_ASSERT(node->m_parent == this);
117
m_children.removeAll(node);
119
QList<AbstractNode*> descendant() const {
120
QList<AbstractNode*> list = m_children;
121
foreach(AbstractNode* node, m_children)
122
foreach(AbstractNode* n, node->descendant())
126
QList<AbstractNode*> peers() const {
127
QList<AbstractNode*> list;
129
foreach(AbstractNode* node, m_parent->m_children)
135
AbstractNode* m_parent;
136
QList<AbstractNode*> m_children;
139
/// A point in the data-model.
140
class PointNode : public AbstractNode
146
explicit PointNode() : AbstractNode("dgm:pt") {}
147
virtual ~PointNode() {}
148
virtual void dump(Context* context, int level) {
149
DEBUG_DUMP << "modelId=" << m_modelId << "type=" << m_type << "cxnId=" << m_cxnId;
150
AbstractNode::dump(context, level);
152
virtual void readElement(Context*, MsooXmlDiagramReader* reader) {
153
if (reader->isStartElement()) {
154
if (reader->qualifiedName() == QLatin1String("dgm:prSet")) {
156
} else if (reader->qualifiedName() == QLatin1String("dgm:spPr")) {
158
} else if (reader->qualifiedName() == QLatin1String("dgm:t")) {
163
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
164
const QXmlStreamAttributes attrs(reader->attributes());
165
TRY_READ_ATTR_WITHOUT_NS_INTO(modelId, m_modelId)
166
TRY_READ_ATTR_WITHOUT_NS_INTO(type, m_type)
167
if (m_type.isEmpty()) m_type = "node";
168
if (m_type == QLatin1String("parTrans") || m_type == QLatin1String("sibTrans"))
169
TRY_READ_ATTR_WITHOUT_NS_INTO(cxnId, m_cxnId)
172
AbstractNode::readAll(context, reader);
176
/// A list of points in the data-model.
177
class PointListNode : public AbstractNode
180
explicit PointListNode() : AbstractNode("dgm:ptLst") {}
181
virtual ~PointListNode() {}
182
virtual void dump(Context* context, int level) {
184
AbstractNode::dump(context, level);
186
virtual void readElement(Context* context, MsooXmlDiagramReader* reader) {
187
if (reader->isStartElement()) {
188
if (reader->qualifiedName() == QLatin1String("dgm:pt")) {
189
PointNode *n = new PointNode;
191
n->readAll(context, reader);
197
/// A connection between two nodes in the data-model.
198
class ConnectionNode : public AbstractNode
206
QString m_sibTransId;
209
explicit ConnectionNode() : AbstractNode("dgm:cxn"), m_srcOrd(0), m_destOrd(0) {}
210
virtual ~ConnectionNode() {}
211
virtual void dump(Context*, int level) {
212
DEBUG_DUMP << "modelId=" << m_modelId << "type=" << m_type << "srcId=" << m_srcId << "destId=" << m_destId;
214
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
215
const QXmlStreamAttributes attrs(reader->attributes());
216
TRY_READ_ATTR_WITHOUT_NS_INTO(modelId, m_modelId)
217
TRY_READ_ATTR_WITHOUT_NS_INTO(type, m_type)
218
if (m_type.isEmpty()) m_type = "parOf";
219
TRY_READ_ATTR_WITHOUT_NS_INTO(srcId, m_srcId)
220
TRY_READ_ATTR_WITHOUT_NS_INTO(destId, m_destId)
221
TRY_READ_ATTR_WITHOUT_NS_INTO(presId, m_presId)
222
TRY_READ_ATTR_WITHOUT_NS_INTO(sibTransId, m_sibTransId)
223
TRY_READ_ATTR_WITHOUT_NS(srcOrd)
224
TRY_READ_ATTR_WITHOUT_NS(destOrd)
225
m_srcOrd = srcOrd.toInt();
226
m_destOrd = destOrd.toInt();
227
AbstractNode::readAll(context, reader);
231
/// A list of connections in the data-model.
232
class ConnectionListNode : public AbstractNode
235
explicit ConnectionListNode() : AbstractNode("dgm:cxnLst") {}
236
virtual ~ConnectionListNode() {}
237
virtual void dump(Context* context, int level) {
239
AbstractNode::dump(context, level);
241
virtual void readElement(Context* context, MsooXmlDiagramReader* reader) {
242
if (reader->isStartElement()) {
243
if (reader->qualifiedName() == QLatin1String("dgm:cxn")) {
244
ConnectionNode *n = new ConnectionNode;
246
n->readAll(context, reader);
252
/****************************************************************************************************
253
* So much for the nodes. Now the atoms are following which are used to add some logic to the
254
* data-model and they do provide the functionality to build up a hierarchical layout tree.
257
/// Base class for layout-operations (content of layout1.xml)
261
const QString m_tagName;
262
explicit AbstractAtom(const QString &tagName) : m_tagName(tagName), m_parent(0) {}
263
virtual ~AbstractAtom() { qDeleteAll(m_children); }
264
virtual void dump(Context* context, int level) {
265
foreach(AbstractAtom* atom, m_children)
266
atom->dump(context, level + 1);
268
virtual void readElement(Context* context, MsooXmlDiagramReader* reader);
269
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
270
while (!reader->atEnd()) {
271
QXmlStreamReader::TokenType tokenType = reader->readNext();
272
if(tokenType == QXmlStreamReader::Invalid || tokenType == QXmlStreamReader::EndDocument) break;
273
if (!reader->isStartElement() && reader->qualifiedName() == m_tagName) break;
274
readElement(context, reader);
277
virtual void readDone(Context* context) {
278
foreach(AbstractAtom* atom, m_children)
279
atom->readDone(context);
281
virtual void layoutAtom(Context* context) {
282
foreach(AbstractAtom* atom, m_children)
283
atom->layoutAtom(context);
285
virtual void writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles) {
286
foreach(AbstractAtom* atom, m_children)
287
atom->writeAtom(context, xmlWriter, styles);
289
AbstractAtom* parent() const { return m_parent; }
290
QList<AbstractAtom*> children() const { return m_children; }
291
template<class U, class T> QList<U*> filterItems(Context* context, const QList<T*> &items) const;
292
void addChild(AbstractAtom* node) {
293
Q_ASSERT(!node->m_parent);
294
node->m_parent = this;
295
m_children.append(node);
297
void removeChild(AbstractAtom* node) {
298
Q_ASSERT(node->m_parent == this);
300
m_children.removeAll(node);
304
AbstractAtom* m_parent;
305
QList<AbstractAtom*> m_children;
307
QList<AbstractNode*> fetchAxis(Context* context, const QString& _axis, const QString &_ptType, const QString& _start, const QString& _count, const QString& _step) const {
308
const QStringList axisList = _axis.split(' ', QString::SkipEmptyParts);
310
const QStringList typeList = _ptType.split(' ', QString::SkipEmptyParts);
311
Q_ASSERT(axisList.count() <= 1 || axisList.count() == typeList.count());
313
const QStringList startList = _start.split(' ', QString::SkipEmptyParts);
314
const QStringList countList = _count.split(' ', QString::SkipEmptyParts);
315
const QStringList stepList = _step.split(' ', QString::SkipEmptyParts);
316
Q_ASSERT(startList.count() == countList.count() || startList.isEmpty() || countList.isEmpty());
317
Q_ASSERT(countList.count() == stepList.count() || countList.isEmpty() || stepList.isEmpty());
318
Q_ASSERT(startList.count() == stepList.count() || startList.isEmpty() || stepList.isEmpty());
320
QList<AbstractNode*> result;
321
for(int i = 0; i < axisList.count(); ++i) {
322
const QString axis = axisList[i];
323
QList<AbstractNode*> list;
324
if(axis == QLatin1String("ancst")) { // Ancestor
325
for(AbstractNode* n = context->currentNode(); n; n = n->parent())
327
} else if(axis == QLatin1String("ancstOrSelf")) { // Ancestor Or Self
328
for(AbstractNode* n = context->currentNode(); n; n = n->parent())
330
list.append(context->currentNode());
331
} else if(axis == QLatin1String("ch")) { // Child
332
foreach(AbstractNode* n, context->currentNode()->children())
334
} else if(axis == QLatin1String("des")) { // Descendant
335
foreach(AbstractNode* n, context->currentNode()->descendant())
337
} else if(axis == QLatin1String("desOrSelf")) { // Descendant Or Self
338
foreach(AbstractNode* n, context->currentNode()->descendant())
340
list.append(context->currentNode());
341
} else if(axis == QLatin1String("follow")) { // Follow
342
foreach(AbstractNode* peer, context->currentNode()->peers()) {
344
foreach(AbstractNode* n, peer->descendant())
347
} else if(axis == QLatin1String("followSib")) { // Follow Sibling
348
foreach(AbstractNode* n, context->currentNode()->peers())
350
} else if(axis == QLatin1String("par")) { // Parent
351
if (context->currentNode()->parent())
352
list.append(context->currentNode()->parent());
353
} else if(axis == QLatin1String("preced")) { // Preceding
355
} else if(axis == QLatin1String("precedSib")) { // Preceding Sibling
357
} else if(axis == QLatin1String("root")) { // Root
358
list.append(context->m_rootPoint);
359
} else if(axis == QLatin1String("self")) { // Self
360
list.append(context->currentNode());
363
// optionally filter the list
364
if(i < typeList.count()) {
365
QList<AbstractNode*> _list = list;
367
const QString ptType = typeList[i];
368
foreach(AbstractNode* node, _list) {
369
if(PointNode* pt = dynamic_cast<PointNode*>(node)) {
370
if(ptType == pt->m_type || ptType == "all" || (ptType == "nonAsst" && pt->m_type != "asst" ) || (ptType == "nonNorm" && pt->m_type != "norm")) {
377
// evaluate optional forEach-conditions
378
if(i < startList.count() || i < countList.count() || i < stepList.count()) {
379
const int start = i < startList.count() ? startList[i].toInt() : 1;
380
const int count = i < countList.count() ? countList[i].toInt() : 0;
381
const int step = i < stepList.count() ? stepList[i].toInt() : 1;
382
list = foreachAxis(context, list, start, count, step);
385
// transfer the resulting list to the result-list.
386
foreach(AbstractNode* node, list) {
395
QList<AbstractNode*> foreachAxis(Context*, const QList<AbstractNode*> &list, int start, int count, int step) const {
396
QList<AbstractNode*> result;
397
const int _start = qMax(0, start - 1);
398
const int _step = qMax(1, step);
399
for(int i = _start; i < list.count(); i += _step) {
400
result.append(list[i]);
401
if(/*count > 0 &&*/ result.count() == count) break;
407
/// The layout node is the basic building block of diagrams. The layout node is responsible for defining how shapes are arranged in a diagram and how the data maps to a particular shape in a diagram.
408
class LayoutNodeAtom : public AbstractAtom
412
int m_x, m_y, m_width, m_height, m_cx, m_cy;
413
qreal m_factX, m_factY, m_factWidth, m_factHeight;
414
qreal m_ctrX, m_ctrY;
415
explicit LayoutNodeAtom() : AbstractAtom("dgm:layoutNode"), m_x(-1), m_y(-1), m_width(-1), m_height(-1), m_cx(-1), m_cy(-1), m_factX(1.0), m_factY(1.0), m_factWidth(1.0), m_factHeight(1.0), m_ctrX(1.0), m_ctrY(1.0), m_algorithm(0), m_needsRelayout(true), m_childNeedsRelayout(true) {}
416
virtual ~LayoutNodeAtom() {}
417
virtual void dump(Context* context, int level) {
418
DEBUG_DUMP << "name=" << m_name << "constraintsCount=" << m_constraints.count();
419
AbstractAtom::dump(context, level);
421
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
422
const QXmlStreamAttributes attrs(reader->attributes());
423
TRY_READ_ATTR_WITHOUT_NS_INTO(name, m_name)
424
//TRY_READ_ATTR_WITHOUT_NS_INTO(styleLbl, m_styleLbl)
425
context->m_layoutMap[m_name] = this;
426
LayoutNodeAtom* oldLayout = context->m_parentLayout;
427
context->m_parentLayout = this;
428
AbstractAtom::readAll(context, reader);
429
context->m_parentLayout = oldLayout;
431
virtual void layoutAtom(Context* context);
432
virtual void writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles);
433
QList<ConstraintAtom*> constraints() const { return m_constraints; }
434
void addConstraint(ConstraintAtom* constraint) { m_constraints.append(constraint); setNeedsRelayout(true); }
435
void setAlgorithm(AlgorithmAtom* algorithm) { m_algorithm = algorithm; setNeedsRelayout(true); }
436
QList<AbstractNode*> axis() const { return m_axis; }
437
void setAxis(const QList<AbstractNode*> &axis) { m_axis = axis; setNeedsRelayout(true); }
438
void setNeedsRelayout(bool needsRelayout) {
439
if(needsRelayout == m_needsRelayout) return;
440
m_needsRelayout = needsRelayout;
441
if(m_needsRelayout) // let parent-layouts know that we need a relayout
442
for(AbstractAtom* parent = m_parent; parent; parent = parent->parent())
443
if(LayoutNodeAtom* parentLayoutAtom = dynamic_cast<LayoutNodeAtom*>(parent))
444
parentLayoutAtom->m_childNeedsRelayout = true;
447
QList<ConstraintAtom*> m_constraints;
448
AlgorithmAtom* m_algorithm;
449
QList<AbstractNode*> m_axis;
450
bool m_needsRelayout, m_childNeedsRelayout;
453
/// Specify size and position of nodes, text values, and layout dependencies between nodes in a layout definition.
454
class ConstraintAtom : public AbstractAtom
457
/// Factor used in a reference constraint or a rule in order to modify a referenced value by the factor defined.
459
/// Specifies the axis of layout nodes to apply a constraint or rule to.
461
/// Specifies the name of the layout node to apply a constraint or rule to.
463
/// The operator constraint used to evaluate the condition.
465
/// Specifies the type of data point to select.
467
/// The point type used int he referenced constraint.
469
/// Specifies the type of a reference constraint.
471
/// The for value of the referenced constraint.
473
/// The name of the layout node referenced by a reference constraint.
474
QString m_refForName;
475
/// Specifies the constraint to apply to this layout node.
477
/// Specifies an absolute value instead of reference another constraint.
479
explicit ConstraintAtom() : AbstractAtom("dgm:constr") {}
480
virtual ~ConstraintAtom() {}
481
virtual void dump(Context*, int level) {
482
QString s = QString("fact=%1 ").arg(m_fact);
483
if(!m_for.isEmpty()) s += QString("for=%1 ").arg(m_for);
484
if(!m_forName.isEmpty()) s += QString("forName=%1 ").arg(m_forName);
485
if(!m_op.isEmpty()) s += QString("op=%1 ").arg(m_op);
486
if(!m_ptType.isEmpty()) s += QString("ptType=%1 ").arg(m_ptType);
487
if(!m_refPtType.isEmpty()) s += QString("refPtType=%1 ").arg(m_refPtType);
488
if(!m_refType.isEmpty()) s += QString("refType=%1 ").arg(m_refType);
489
if(!m_refFor.isEmpty()) s += QString("refFor=%1 ").arg(m_refFor);
490
if(!m_refForName.isEmpty()) s += QString("refForName=%1 ").arg(m_refForName);
491
if(!m_type.isEmpty()) s += QString("type=%1 ").arg(m_type);
492
if(!m_value.isEmpty()) s += QString("val=%1 ").arg(m_value);
495
virtual void readAll(Context*, MsooXmlDiagramReader* reader) {
496
const QXmlStreamAttributes attrs(reader->attributes());
497
TRY_READ_ATTR_WITHOUT_NS(fact)
498
m_fact = fact.isEmpty() ? 1.0 : fact.toDouble();
499
TRY_READ_ATTR_WITHOUT_NS_INTO(for, m_for)
500
TRY_READ_ATTR_WITHOUT_NS_INTO(forName, m_forName)
501
TRY_READ_ATTR_WITHOUT_NS_INTO(op, m_op)
502
TRY_READ_ATTR_WITHOUT_NS_INTO(ptType, m_ptType)
503
TRY_READ_ATTR_WITHOUT_NS_INTO(refPtType, m_refPtType)
504
TRY_READ_ATTR_WITHOUT_NS_INTO(refType, m_refType)
505
TRY_READ_ATTR_WITHOUT_NS_INTO(refFor, m_refFor)
506
TRY_READ_ATTR_WITHOUT_NS_INTO(refForName, m_refForName)
507
TRY_READ_ATTR_WITHOUT_NS_INTO(type, m_type)
508
TRY_READ_ATTR_WITHOUT_NS_INTO(val, m_value)
509
//AbstractAtom::readAll(context, reader);
511
virtual void readDone(Context* context) {
512
LayoutNodeAtom* layout = m_forName.isEmpty() ? context->m_parentLayout : context->m_layoutMap.value(m_forName);
513
if(layout) layout->addConstraint(this);
514
AbstractAtom::readDone(context);
518
/// List of constraints.
519
class ConstraintListAtom : public AbstractAtom
522
explicit ConstraintListAtom() : AbstractAtom("dgm:constrLst") {}
523
virtual ~ConstraintListAtom() {}
524
virtual void dump(Context* context, int level) {
525
AbstractAtom::dump(context, level);
527
virtual void readElement(Context* context, MsooXmlDiagramReader* reader) {
528
if (reader->isStartElement()) {
529
if (reader->qualifiedName() == QLatin1String("dgm:constr")) {
530
ConstraintAtom* node = new ConstraintAtom;
532
node->readAll(context, reader);
538
/// The shape displayed by the containing layout node. Not all layout nodes display shapes.
539
class ShapeAtom : public AbstractAtom
545
int m_x, m_y, m_width, m_height, m_cx, m_cy;
546
qreal m_factX, m_factY, m_factWidth, m_factHeight;
547
qreal m_ctrX, m_ctrY;
548
explicit ShapeAtom() : AbstractAtom("dgm:shape"), m_hideGeom(false), m_x(-1), m_y(-1), m_width(-1), m_height(-1), m_cx(-1), m_cy(-1), m_factX(1.0), m_factY(1.0), m_factWidth(1.0), m_factHeight(1.0), m_ctrX(1.0), m_ctrY(1.0) {}
549
virtual ~ShapeAtom() {}
550
virtual void dump(Context* context, int level) {
551
DEBUG_DUMP << "type=" << m_type << "blip=" << m_blip << "x=" << m_x << "y=" << m_y << "width=" << m_width << "height=" << m_height;
552
AbstractAtom::dump(context, level);
554
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
555
const QXmlStreamAttributes attrs(reader->attributes());
556
TRY_READ_ATTR_WITHOUT_NS_INTO(type, m_type)
557
//if (m_type.isEmpty()) m_type = "obj";
558
TRY_READ_ATTR_WITHOUT_NS_INTO(blip, m_blip)
559
TRY_READ_ATTR_WITHOUT_NS(hideGeom)
560
m_hideGeom = hideGeom.toInt();
561
AbstractAtom::readAll(context, reader);
564
//TODO use filters/libmso/ODrawToOdf.h
565
virtual void writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles) {
566
Q_ASSERT(context->m_parentLayout);
567
if(m_type.isEmpty()) return;
568
//if(m_hideGeom) return;
570
int x = m_x * m_factX;
571
int y = m_y * m_factY;
572
int w = m_width * m_factWidth;
573
int h = m_height * m_factHeight;
574
int cx = m_cx * m_ctrX;
575
int cy = m_cy * m_ctrY;
576
DEBUG_WRITE << "type=" << m_type << "blip=" << m_blip << "hideGeom=" << m_hideGeom << "geometry=" << x+cx << y+cy << w << h << m_cx << m_ctrX << m_cy << m_ctrY;
578
xmlWriter->startElement("draw:custom-shape");
579
xmlWriter->addAttribute("draw:layer", "layout");
580
if (!context->m_parentLayout->m_name.isEmpty())
581
xmlWriter->addAttribute("draw:name", context->m_parentLayout->m_name);
583
KoGenStyle style = KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic");
584
style.addProperty("draw:fill", "solid" /*none*/, KoGenStyle::GraphicType);
585
style.addProperty("draw:fill-color", "#6666ff"); //TODO needs to handle colors1.xml ...
586
style.addProperty("draw:opacity", "50%");
587
const QString styleName = styles->insert(style);
588
xmlWriter->addAttribute("draw:style-name", styleName);
589
//xmlWriter->addAttribute("draw:text-style-name", "P2");
594
if(x+cx<0) { x=iii*30; cx=0; }
595
if(y+cy<0) { y=iii*30; cy=0; }
601
xmlWriter->addAttribute("svg:x", QString("%1px").arg(x+cx));
602
xmlWriter->addAttribute("svg:y", QString("%1px").arg(y+cy));
603
xmlWriter->addAttribute("svg:width", QString("%1px").arg(w));
604
xmlWriter->addAttribute("svg:height", QString("%1px").arg(h));
606
xmlWriter->startElement("text:p");
607
xmlWriter->endElement();
609
if (m_type == QLatin1String("ellipse")) {
610
xmlWriter->startElement("draw:enhanced-geometry");
611
xmlWriter->addAttribute("draw:enhanced-path", "U 10800 10800 10800 10800 0 360 Z N");
612
xmlWriter->addAttribute("draw:glue-points", "10800 0 3163 3163 0 10800 3163 18437 10800 21600 18437 18437 21600 10800 18437 3163");
613
xmlWriter->addAttribute("draw:type", "ellipse");
614
xmlWriter->addAttribute("svg:viewBox", "0 0 21600 21600");
615
xmlWriter->endElement();
616
} else if (m_type == QLatin1String("cycle")) {
617
xmlWriter->startElement("draw:enhanced-geometry");
618
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");
619
xmlWriter->addAttribute("draw:glue-point-leaving-directions", "-90, -90, -90, -90, -90, -90, -90, -90, -90, -90");
620
xmlWriter->addAttribute("draw:glue-points", "-90, -90, -90, -90, -90, -90, -90, -90, -90, -90");
621
xmlWriter->addAttribute("draw:type", "?f21 ?f22 ?f23 ?f24 ?f25 ?f26 ?f27 ?f28 ?f29 ?f30 ?f27 ?f31 ?f25 ?f32 ?f23 ?f31 ?f33 ?f30 ?f21 ?f22");
622
xmlWriter->addAttribute("draw:text-areas", "?f34 ?f36 ?f35 ?f37");
623
xmlWriter->addAttribute("draw:type", "circle");
624
xmlWriter->addAttribute("svg:viewBox", "0 0 828228 828228");
625
xmlWriter->endElement();
626
} else /*if (m_type == QLatin1String("rect"))*/ {
628
kWarning() << "TODO shape type=" << m_type;
631
xmlWriter->endElement(); // draw:custom-shape
635
/// The algorithm used by the containing layout node. The algorithm defines the behavior of the layout node along with the behavior and layout of the nested layout nodes.
636
class AlgorithmAtom : public AbstractAtom
641
// The composite algorithm specifies the size and position for all child layout nodes. You can use it to create
642
// graphics with a predetermined layout or in combination with other algorithms to create more complex shapes.
644
// The connector algorithm lays out and routes connecting lines, arrows, and shapes between layout nodes.
646
// The cycle algorithm lays out child layout nodes around a circle or portion of a circle using equal angle spacing.
648
// The hierarchy child algorithm works with the hierRoot algorithm to create hierarchical tree layouts. This
649
// algorithm aligns and positions its child layout nodes in a linear path under the hierRoot layout node.
651
// The hierarchy root algorithm works with the hierChild algorithm to create hierarchical tree layouts. The
652
// hierRoot algorithm aligns and positions the hierRoot layout node in relation to the hierChild layout nodes.
654
// The linear algorithm lays out child layout nodes along a linear path.
656
// The pyramid algorithm lays out child layout nodes along a vertical path and works with the trapezoid
657
// shape to create a pyramid.
659
// The snake algorithm lays out child layout nodes along a linear path in two dimensions, allowing the linear
660
// flow to continue across multiple rows or columns.
662
// The space algorithm is used to specify a minimum space between other layout nodes or as an indication
663
// to do nothing with the layout node’s size and position.
665
// The text algorithm sizes text to fit inside a shape and controls its margins and alignment.
669
QList< QPair<QString,QString> > m_params; // list of type=value parameters that modify the default behavior of the algorithm.
670
explicit AlgorithmAtom() : AbstractAtom("dgm:alg"), m_type(UnknownAlg) {}
671
virtual ~AlgorithmAtom() {}
672
virtual void dump(Context* context, int level) {
673
DEBUG_DUMP << "type=" << m_type;
674
AbstractAtom::dump(context, level);
676
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
677
const QXmlStreamAttributes attrs(reader->attributes());
678
TRY_READ_ATTR_WITHOUT_NS(type)
679
if(type == QLatin1String("composite")) m_type = CompositeAlg;
680
else if(type == QLatin1String("conn")) m_type = ConnectorAlg;
681
else if(type == QLatin1String("cycle")) m_type = CycleAlg;
682
else if(type == QLatin1String("hierChild")) m_type = HierChildAlg;
683
else if(type == QLatin1String("hierRoot")) m_type = HierRootAlg;
684
else if(type == QLatin1String("lin")) m_type = LinearAlg;
685
else if(type == QLatin1String("pyra")) m_type = PyramidAlg;
686
else if(type == QLatin1String("snake")) m_type = SnakeAlg;
687
else if(type == QLatin1String("sp")) m_type = SpaceAlg;
688
else if(type == QLatin1String("tx")) m_type = TextAlg;
689
else m_type = UnknownAlg;
690
context->m_parentLayout->setAlgorithm(this);
691
AbstractAtom::readAll(context, reader);
693
virtual void readElement(Context*, MsooXmlDiagramReader* reader) {
694
if (reader->isStartElement()) {
695
if (reader->qualifiedName() == QLatin1String("dgm:param")) {
696
const QXmlStreamAttributes attrs(reader->attributes());
697
TRY_READ_ATTR_WITHOUT_NS(type)
698
TRY_READ_ATTR_WITHOUT_NS(val)
699
m_params << QPair<QString,QString>(type, val);
705
/// This element specifies a particular data model point which is to be mapped to the containing layout node.
706
class PresentationOfAtom : public AbstractAtom
709
QString m_axis; // This determines how to navigate through the data model, setting the context node as it moves.
710
QString m_ptType; // dataPointType
712
QString m_hideLastTrans;
715
explicit PresentationOfAtom() : AbstractAtom("dgm:presOf") {}
716
virtual ~PresentationOfAtom() {}
717
virtual void dump(Context* context, int level) {
718
DEBUG_DUMP << "axis=" << m_axis << "ptType=" << m_ptType << "count=" << m_count << "start=" << m_start << "step=" << m_step << "hideLastTrans=" << m_hideLastTrans;
719
AbstractAtom::dump(context, level);
721
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
722
const QXmlStreamAttributes attrs(reader->attributes());
723
TRY_READ_ATTR_WITHOUT_NS_INTO(axis, m_axis)
724
TRY_READ_ATTR_WITHOUT_NS_INTO(ptType, m_ptType)
725
TRY_READ_ATTR_WITHOUT_NS_INTO(cnt, m_count)
726
TRY_READ_ATTR_WITHOUT_NS_INTO(hideLastTrans, m_hideLastTrans)
727
TRY_READ_ATTR_WITHOUT_NS_INTO(st, m_start)
728
TRY_READ_ATTR_WITHOUT_NS_INTO(step, m_step)
729
AbstractAtom::readAll(context, reader);
731
virtual void layoutAtom(Context* context) {
732
QList<AbstractNode*> axis = fetchAxis(context, m_axis, m_ptType, m_start, m_count, m_step);
733
context->m_parentLayout->setAxis(axis);
734
//AbstractAtom::layoutAtom(context);
738
/// The if element represents a condition that applies to all it's children.
739
class IfAtom : public AbstractAtom
745
QString m_hideLastTrans;
753
explicit IfAtom(bool isTrue) : AbstractAtom(isTrue ? "dgm:if" : "dgm:else"), m_isTrue(isTrue) {}
755
virtual void dump(Context* context, int level) {
756
DEBUG_DUMP<<"name="<<m_name;
757
//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;
758
AbstractAtom::dump(context, level);
760
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
761
const QXmlStreamAttributes attrs(reader->attributes());
762
TRY_READ_ATTR_WITHOUT_NS_INTO(arg, m_argument)
763
TRY_READ_ATTR_WITHOUT_NS_INTO(axis, m_axis)
764
TRY_READ_ATTR_WITHOUT_NS_INTO(cnt, m_count)
765
TRY_READ_ATTR_WITHOUT_NS_INTO(func, m_function)
766
TRY_READ_ATTR_WITHOUT_NS_INTO(hideLastTrans, m_hideLastTrans)
767
TRY_READ_ATTR_WITHOUT_NS_INTO(name, m_name)
768
TRY_READ_ATTR_WITHOUT_NS_INTO(op, m_operator)
769
TRY_READ_ATTR_WITHOUT_NS_INTO(ptType, m_ptType)
770
TRY_READ_ATTR_WITHOUT_NS_INTO(st, m_start)
771
TRY_READ_ATTR_WITHOUT_NS_INTO(step, m_step)
772
TRY_READ_ATTR_WITHOUT_NS_INTO(val, m_value)
773
AbstractAtom::readAll(context, reader);
775
bool isTrue() const { return m_isTrue; } // is true or false?
776
bool testAtom(Context* context) {
777
//TODO handle m_argument=="var"
778
QList<AbstractNode*> axis = fetchAxis(context, m_axis, m_ptType, m_start, m_count, m_step);
780
if(m_function == "cnt") { // Specifies a count.
781
funcValue = QString::number(axis.count());
782
} else if(m_function == "depth") { // Specifies the depth.
784
//for(AbstractNode* n = context->m_currentNode; n; n = n->parent(), ++depth);
785
//istrue = depth == m_value.toInt();
787
kWarning()<<"TODO func=depth";
788
} else if(m_function == "maxDepth") { // Defines the maximum depth.
790
//for(AbstractNode* n = context->m_currentNode; n; n = n->parent(), ++depth);
791
//istrue = depth <= m_value.toInt();
793
kWarning()<<"TODO func=maxDepth";
794
} else if(m_function == "pos") { // Retrieves the position of the node in the specified set of nodes.
795
//int index = axis.indexOf(context->m_currentNode)+1;
796
//istrue = index == m_value.toInt();
798
kWarning()<<"TODO func=pos";
799
} else if(m_function == "posEven") { // Returns 1 if the specified node is at an even numbered position in the data model.
800
//int index = axis.indexOf(context->m_currentNode)+1;
801
//istrue = index>=1 ? index % 2 == 0 : false;
803
kWarning()<<"TODO func=posEven";
804
} else if(m_function == "posOdd") { // Returns 1 if the specified node is in an odd position in the data model.
805
//int index = axis.indexOf(context->m_currentNode)+1;
806
//istrue = index>=1 ? index % 2 != 0 : false;
808
kWarning()<<"TODO func=posOdd";
809
} else if(m_function == "revPos") { // Reverse position function.
810
//int index = axis.indexOf(context->m_currentNode)+1;
811
//istrue = axis.count()-index == m_value.toInt();
813
kWarning()<<"TODO func=revPos";
814
} else if(m_function == "var") { // Used to reference a variable.
815
if(m_argument == QLatin1String("animLvl")) { // Specifies the animation level
817
} else if(m_argument == QLatin1String("animOne")) { // Specifies animate as one.
819
} else if(m_argument == QLatin1String("bulEnabled")) { // Specifies bullets enabled.
821
} else if(m_argument == QLatin1String("chMax")) { // The maximum number of children.
823
} else if(m_argument == QLatin1String("chPref")) { // The preferred number of children.
825
} else if(m_argument == QLatin1String("dir")) { // Specifies the direction of the diagram.
826
//TODO another case missing in the specs: What are the possible directions and where are they defined?
828
} else if(m_argument == QLatin1String("hierBranch")) { // The hierarchy branch.
830
} else if(m_argument == QLatin1String("none")) { // Unknown variable type.
832
} else if(m_argument == QLatin1String("orgChart")) { // Algorithm that lays out an org chart.
834
} else if(m_argument == QLatin1String("resizeHandles")) { // Specifies the resize handles.
837
kWarning()<<"Unexpected argument="<<m_argument<<"name="<<m_name;
842
if(m_isTrue && !funcValue.isNull()) {
843
if(m_operator == "equ") {
844
istrue = funcValue == m_value;
847
const int funcValueInt = funcValue.toInt(&isInt);
848
const int valueInt = isInt ? m_value.toInt(&isInt) : 0;
850
// right, that's untested atm since I didn't found a single document that does it and the specs don't cover
851
// such "details" anyways so it seems. So, if you run into this then it's up to you to fix it :)
852
kWarning()<<"TODO figure out how non-integer comparision is expected to work";
855
if(m_operator == QLatin1String("gt")) {
856
istrue = isInt ? funcValueInt > valueInt : funcValue > m_value;
857
} else if(m_operator == QLatin1String("gte")) {
858
istrue = isInt ? funcValueInt >= valueInt : funcValue >= m_value;
859
} else if(m_operator == QLatin1String("lt")) {
860
istrue = isInt ? funcValueInt < valueInt : funcValue < m_value;
861
} else if(m_operator == QLatin1String("lte")) {
862
istrue = isInt ? funcValueInt <= valueInt : funcValue <= m_value;
863
} else if(m_operator == QLatin1String("neq")) {
864
istrue = isInt ? funcValueInt != valueInt : funcValue != m_value;
866
kWarning()<<"Unexpected operator="<<m_operator<<"name="<<m_name;
869
//kDebug()<<"name="<<m_name<<"value1="<<funcValue<<"value2="<<m_value<<"operator="<<m_operator<<"istrue="<<istrue;
878
/// The choose element wraps if/else blocks into a choose block.
879
class ChooseAtom : public AbstractAtom
883
explicit ChooseAtom() : AbstractAtom("dgm:choose") {}
884
virtual ~ChooseAtom() {}
885
virtual void dump(Context* context, int level) {
886
//DEBUG_DUMP << "name=" << m_name;
887
foreach(AbstractAtom* atom, atomsMatchingToCondition(context))
888
atom->dump(context, level);
890
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
891
const QXmlStreamAttributes attrs(reader->attributes());
892
TRY_READ_ATTR_WITHOUT_NS_INTO(name, m_name)
893
AbstractAtom::readAll(context, reader);
895
virtual void readElement(Context* context, MsooXmlDiagramReader* reader) {
896
if (reader->isStartElement()) {
897
if (reader->qualifiedName() == QLatin1String("dgm:if")) {
898
IfAtom *n = new IfAtom(true);
900
n->readAll(context, reader);
901
} else if (reader->qualifiedName() == QLatin1String("dgm:else")) {
902
IfAtom *n = new IfAtom(false);
904
n->readAll(context, reader);
908
virtual void layoutAtom(Context* context) {
909
foreach(AbstractAtom* atom, atomsMatchingToCondition(context))
910
atom->layoutAtom(context);
912
virtual void writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles) {
914
foreach(AbstractAtom* atom, atomsMatchingToCondition(context))
915
atom->writeAtom(context, xmlWriter, styles);
917
QList<AbstractAtom*> atomsMatchingToCondition(Context* context) const {
918
QList<AbstractAtom*> ifResult;
919
QList<AbstractAtom*> elseResult;
920
foreach(AbstractAtom* atom, m_children) {
921
if(IfAtom* ifatom = dynamic_cast<IfAtom*>(atom)) {
922
if(ifatom->isTrue()) {
923
if(ifatom->testAtom(context))
924
ifResult.append(ifatom);
926
elseResult.append(ifatom);
930
return ifResult.isEmpty() ? elseResult : ifResult;
934
/// A looping structure, similar to a for loop in a programming language, which defines what data model points will use this layout node.
935
class ForEachAtom : public AbstractAtom
939
QString m_hideLastTrans;
946
explicit ForEachAtom() : AbstractAtom("dgm:forEach") {}
947
virtual ~ForEachAtom() {}
948
virtual void dump(Context* context, int level) {
949
DEBUG_DUMP << "axis=" << m_axis << "count=" << m_count << "hideLastTrans=" << m_hideLastTrans << "name=" << m_name << "ptType=" << m_ptType << "reference=" << m_reference << "start=" << m_start << "step=" << m_step;
950
foreach(AbstractAtom* atom, m_children)
951
atom->dump(context, level + 1);
953
virtual void readAll(Context* context, MsooXmlDiagramReader* reader) {
954
const QXmlStreamAttributes attrs(reader->attributes());
955
TRY_READ_ATTR_WITHOUT_NS_INTO(axis, m_axis)
956
TRY_READ_ATTR_WITHOUT_NS_INTO(cnt, m_count)
957
TRY_READ_ATTR_WITHOUT_NS_INTO(hideLastTrans, m_hideLastTrans)
958
TRY_READ_ATTR_WITHOUT_NS_INTO(name, m_name)
959
TRY_READ_ATTR_WITHOUT_NS_INTO(ptType, m_ptType)
960
TRY_READ_ATTR_WITHOUT_NS_INTO(ref, m_reference)
961
TRY_READ_ATTR_WITHOUT_NS_INTO(st, m_start)
962
TRY_READ_ATTR_WITHOUT_NS_INTO(step, m_step)
963
AbstractAtom::readAll(context, reader);
965
virtual void layoutAtom(Context* context) {
966
QList<AbstractNode*> axis = fetchAxis(context, m_axis, m_ptType, m_start, m_count, m_step);
967
foreach(AbstractNode* node, axis) {
968
Q_ASSERT(dynamic_cast<PointNode*>(node));
969
foreach(AbstractAtom* atom, m_children)
970
atom->layoutAtom(context);
973
virtual void writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles) {
975
QList<AbstractNode*> axis = fetchAxis(context, m_axis, m_ptType, m_start, m_count, m_step);
976
foreach(AbstractNode* node, axis) {
977
Q_ASSERT(dynamic_cast<PointNode*>(node));
978
foreach(AbstractAtom* atom, m_children)
979
atom->writeAtom(context, xmlWriter, styles);
986
, m_connections(new ConnectionListNode)
987
, m_rootLayout(new Diagram::LayoutNodeAtom)
988
, m_parentLayout(m_rootLayout)
996
delete m_connections;
1000
void Context::setCurrentNode(AbstractNode* node)
1002
Q_ASSERT(dynamic_cast<PointNode*>(node));
1003
m_currentNode = node;
1006
void AbstractAtom::readElement(Context* context, MsooXmlDiagramReader* reader)
1008
if (reader->isStartElement()) {
1009
AbstractAtom *node = 0;
1011
if (reader->qualifiedName() == QLatin1String("dgm:layoutNode")) {
1012
node = new LayoutNodeAtom;
1014
else if (reader->qualifiedName() == QLatin1String("dgm:shape")) {
1015
node = new ShapeAtom;
1017
else if (reader->qualifiedName() == QLatin1String("dgm:alg")) {
1018
node = new AlgorithmAtom;
1020
else if (reader->qualifiedName() == QLatin1String("dgm:presOf")) {
1021
node = new PresentationOfAtom;
1023
else if (reader->qualifiedName() == QLatin1String("dgm:choose")) {
1024
node = new ChooseAtom;
1026
else if (reader->qualifiedName() == QLatin1String("dgm:forEach")) {
1027
node = new ForEachAtom;
1029
else if (reader->qualifiedName() == QLatin1String("dgm:constrLst")) {
1030
node = new ConstraintListAtom;
1035
node->readAll(context, reader);
1040
template<class U, class T> QList<U*> AbstractAtom::filterItems(Context* context, const QList<T*> &items) const
1043
foreach(T* atom, items) {
1044
if(ChooseAtom* chooseatom = dynamic_cast<ChooseAtom*>(atom)) {
1045
QList<U*> children = filterItems<U, AbstractAtom>(context, chooseatom->atomsMatchingToCondition(context));
1046
foreach(U* a, children)
1048
} else if(ForEachAtom* foreachatom = dynamic_cast<ForEachAtom*>(atom)) {
1049
QList<U*> children = filterItems<U, AbstractAtom>(context, foreachatom->children());
1050
foreach(U* a, children)
1052
} else if(U* a = dynamic_cast<U*>(atom)) {
1059
void LayoutNodeAtom::layoutAtom(Context* context)
1061
LayoutNodeAtom* oldLayout = context->m_parentLayout;
1062
context->m_parentLayout = this;
1064
// initially inherit the layout from the parent.
1065
m_x = oldLayout->m_x;
1066
m_y = oldLayout->m_y;
1067
m_width = oldLayout->m_width;
1068
m_height = oldLayout->m_height;
1069
m_cx = oldLayout->m_cx;
1070
m_cy = oldLayout->m_cy;
1071
m_factX = oldLayout->m_factX;
1072
m_factY = oldLayout->m_factY;
1073
m_factWidth = oldLayout->m_factWidth;
1074
m_factHeight = oldLayout->m_factHeight;
1075
m_ctrX = oldLayout->m_ctrX;
1076
m_ctrY = oldLayout->m_ctrY;
1079
if(m_childNeedsRelayout) {
1080
m_childNeedsRelayout = false;
1081
foreach(AbstractAtom* atom, m_children) {
1082
atom->layoutAtom(context);
1087
AlgorithmAtom::Algorithm algorithm = AlgorithmAtom::UnknownAlg;
1088
QList< QPair<QString,QString> > params;
1090
algorithm = m_algorithm->m_type;
1091
params = m_algorithm->m_params;
1094
// layout ourself if requested
1095
if(m_needsRelayout) {
1096
m_needsRelayout = false;
1098
//QStringList axisnames;
1099
//foreach(AbstractNode* n, axis()) axisnames.append(n->m_tagName);
1100
//kDebug() << "################# name=" << m_name << "algorithm=" << algorithm << "constraintCount=" << m_constraints.count() << "axis=" << axisnames;
1101
//this->dump(context, 2);
1103
// evaluate the constraints responsible for positioning and sizing.
1104
if(!m_constraints.isEmpty()) kDebug() << "Constraints for LayoutNodeAtom="<<m_name;
1105
foreach(ConstraintAtom* c, m_constraints) {
1106
c->dump(context, 2);
1109
if(!c->m_value.isEmpty()) {
1111
value = c->m_value.toInt(&ok);
1114
LayoutNodeAtom* ref = c->m_refForName.isEmpty() ? this : context->m_layoutMap.value(c->m_refForName);
1116
//Q_ASSERT(!ref->m_needsRelayout);
1117
//Q_ASSERT(!ref->m_childNeedsRelayout);
1118
if(ref->m_needsRelayout || ref->m_childNeedsRelayout) {
1119
ref->layoutAtom(context);
1120
m_needsRelayout = true;
1121
layoutAtom(context); // restart from the beginning since things may have completly changed now
1122
context->m_parentLayout = oldLayout;
1126
if(!c->m_refType.isEmpty()) {
1127
if(c->m_refType == "l") {
1129
} else if(c->m_refType == "t") {
1131
} else if(c->m_refType == "w") {
1132
value = ref->m_width;
1133
} else if(c->m_refType == "h") {
1134
value = ref->m_height;
1135
} else if(c->m_refType == "primFontSz") {
1138
kWarning() << "Unhandled constraint reference-type=" << c->m_refType;
1142
kDebug()<<"TODO c->m_refType.isEmpty()";
1146
//Q_ASSERT(c->m_for.isEmpty() == c->m_forName.isEmpty() || c->m_type=="primFontSz");
1148
if(c->m_type == QLatin1String("l")) {
1149
if(value >= 0) m_x = value;
1150
m_factX = (m_factX + c->m_fact) / 2.0;
1151
} else if(c->m_type == QLatin1String("t")) {
1152
if(value >= 0) m_y = value;
1153
m_factY = (m_factY + c->m_fact) / 2.0;
1154
} else if(c->m_type == QLatin1String("w")) {
1155
if(value >= 0) m_width = value;
1156
m_factWidth = (m_factWidth + c->m_fact) / 2.0;
1157
} else if(c->m_type == QLatin1String("h")) {
1158
if(value >= 0) m_height = value;
1159
m_factHeight = (m_factHeight + c->m_fact) / 2.0;
1160
} else if(c->m_type == QLatin1String("ctrX")) {
1161
if(value >= 0) m_cx = value;
1162
m_ctrX = (m_ctrX + c->m_fact) / 2.0;
1163
} else if(c->m_type == QLatin1String("ctrY")) {
1164
if(value >= 0) m_cy = value;
1165
m_ctrY = (m_ctrY + c->m_fact) / 2.0;
1166
} else if(c->m_type == QLatin1String("lMarg")) {
1168
} else if(c->m_type == QLatin1String("tMarg")) {
1170
} else if(c->m_type == QLatin1String("rMarg")) {
1172
} else if(c->m_type == QLatin1String("bMarg")) {
1174
} else if(c->m_type == QLatin1String("primFontSz")) {
1177
kWarning() << "Unhandled constraint type=" << c->m_type;
1181
if(c->m_for == QLatin1String("ch")) {
1182
QList<ShapeAtom*> shapes = filterItems<ShapeAtom,AbstractAtom>(context, m_children);
1183
foreach(ShapeAtom* shape, shapes) {
1184
if(m_x >= 0) shape->m_x = m_x;
1185
if(m_y >= 0) shape->m_y = m_y;
1186
if(m_width >= 0) shape->m_width = m_width;
1187
if(m_height >= 0) shape->m_height = m_height;
1188
if(m_cx >= 0) shape->m_cx = m_cx;
1189
if(m_cy >= 0) shape->m_cy = m_cy;
1190
shape->m_factX = m_factX;
1191
shape->m_factY = m_factY;
1192
shape->m_factWidth = m_factWidth;
1193
shape->m_factHeight = m_factHeight;
1194
shape->m_ctrX = m_ctrX;
1195
shape->m_ctrY = m_ctrY;
1196
//shape->dump(context,10);
1198
//if(m_x >= 0 || m_y >= 0 || m_width >= 0 || m_height >= 0) kDebug()<<m_x<<m_y<<m_width<<m_height;
1199
//Q_ASSERT(m_x < 0 && m_y < 0 && m_width < 0 && m_height < 0);
1202
//kDebug() << "####/CONSTRAINTS-END";
1207
// layout the children again if still requested
1208
if(m_childNeedsRelayout) {
1209
m_childNeedsRelayout = false;
1210
foreach(AbstractAtom* atom, m_children) {
1211
atom->layoutAtom(context);
1215
//TODO evaluate rules too
1217
context->m_parentLayout = oldLayout;
1220
void LayoutNodeAtom::writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles)
1222
AlgorithmAtom::Algorithm algorithm = AlgorithmAtom::UnknownAlg;
1223
QList< QPair<QString,QString> > params;
1225
algorithm = m_algorithm->m_type;
1226
params = m_algorithm->m_params;
1228
DEBUG_WRITE << "name=" << m_name << "algorithm=" << algorithm << "params=" << params;
1230
LayoutNodeAtom* oldLayout = context->m_parentLayout;
1231
context->m_parentLayout = this;
1233
AbstractAtom::writeAtom(context, xmlWriter, styles);
1234
context->m_parentLayout = oldLayout;
1237
}} // namespace MSOOXML::Diagram
1239
/****************************************************************************************************
1240
* The reader-context and the reader itself. Note that there will be one reader-instance per xml-file
1241
* in a diagram. The reader-context is shared between the reader-instances for one diagram.
1244
using namespace MSOOXML;
1246
MsooXmlDiagramReaderContext::MsooXmlDiagramReaderContext(KoGenStyles* styles)
1247
: MSOOXML::MsooXmlReaderContext()
1249
, m_context(new Diagram::Context)
1253
MsooXmlDiagramReaderContext::~MsooXmlDiagramReaderContext()
1258
void MsooXmlDiagramReaderContext::saveIndex(KoXmlWriter* xmlWriter, const QRect &rect)
1260
// The root layout node always inherits the canvas dimensions by default
1261
m_context->m_rootLayout->m_x = rect.x();
1262
m_context->m_rootLayout->m_y = rect.y();
1263
m_context->m_rootLayout->m_width = rect.width();
1264
m_context->m_rootLayout->m_height = rect.height();
1265
// Do the (re-)layout.
1266
m_context->m_rootLayout->layoutAtom(m_context);
1267
// Write the content.
1268
m_context->m_rootLayout->writeAtom(m_context, xmlWriter, m_styles);
1271
MsooXmlDiagramReader::MsooXmlDiagramReader(KoOdfWriters *writers)
1272
: MSOOXML::MsooXmlCommonReader(writers)
1273
, m_type(InvalidType)
1277
MsooXmlDiagramReader::~MsooXmlDiagramReader()
1281
KoFilter::ConversionStatus MsooXmlDiagramReader::read(MSOOXML::MsooXmlReaderContext* context)
1283
m_context = dynamic_cast<MsooXmlDiagramReaderContext*>(context);
1284
Q_ASSERT(m_context);
1287
if (!isStartDocument()) {
1288
return KoFilter::WrongFormat;
1292
if (qualifiedName() == QLatin1String("dgm:dataModel")) {
1293
m_type = DataModelType;
1295
Diagram::PointListNode rootList;
1297
QXmlStreamReader::TokenType tokenType = readNext();
1298
if(tokenType == QXmlStreamReader::Invalid || tokenType == QXmlStreamReader::EndDocument) break;
1299
if (isStartElement()) {
1300
if (qualifiedName() == QLatin1String("dgm:ptLst")) { // list of points
1301
rootList.readAll(m_context->m_context, this);
1302
} else if (qualifiedName() == QLatin1String("dgm:cxnLst")) { // list of connections
1303
m_context->m_context->m_connections->readAll(m_context->m_context, this);
1308
QMap<QString, Diagram::PointNode*> pointMap;
1309
foreach(Diagram::AbstractNode* node, rootList.children()) {
1310
if(Diagram::PointNode* point = dynamic_cast<Diagram::PointNode*>(node))
1311
if (!point->m_modelId.isEmpty())
1312
pointMap[point->m_modelId] = point;
1315
QMap<QString, Diagram::PointNode*> pointTree;
1316
foreach(Diagram::AbstractNode* node, m_context->m_context->m_connections->children()) {
1317
if(Diagram::ConnectionNode* connection = dynamic_cast<Diagram::ConnectionNode*>(node)) {
1318
if (connection->m_type != "parOf") continue;
1320
Diagram::PointNode* source = 0;
1321
if (pointTree.contains(connection->m_srcId)) {
1322
source = pointTree[connection->m_srcId];
1325
if (!pointMap.contains(connection->m_srcId)) continue;
1326
source = pointMap[connection->m_srcId];
1327
pointTree[connection->m_srcId] = source;
1330
if (!pointMap.contains(connection->m_destId)) continue;
1332
Diagram::PointNode* destination = pointMap[connection->m_destId];
1333
rootList.removeChild(destination);
1334
source->addChild(destination);
1335
pointTree[connection->m_destId] = destination;
1339
Q_ASSERT(!m_context->m_context->m_rootPoint);
1340
foreach(Diagram::AbstractNode* node, rootList.children()) {
1341
if(Diagram::PointNode* pt = dynamic_cast<Diagram::PointNode*>(node)) {
1342
if(pt->m_type == QLatin1String("doc")) {
1343
m_context->m_context->m_rootPoint = pt;
1348
Q_ASSERT(m_context->m_context->m_rootPoint);
1349
rootList.removeChild(m_context->m_context->m_rootPoint);
1350
m_context->m_context->setCurrentNode(m_context->m_context->m_rootPoint);
1352
//for(QMap<QString, Diagram::PointNode*>::Iterator it = pointTree.begin(); it != pointTree.end(); ++it) (*it)->dump(m_context->m_context, 0);
1353
//m_context->m_context->m_rootPoint->dump(0);
1355
else if (qualifiedName() == QLatin1String("dgm:layoutDef")) {
1356
m_type = LayoutDefType;
1359
QXmlStreamReader::TokenType tokenType = readNext();
1360
if(tokenType == QXmlStreamReader::Invalid || tokenType == QXmlStreamReader::EndDocument) break;
1361
if (isStartElement()) {
1362
if (qualifiedName() == QLatin1String("dgm:layoutNode")) {
1363
m_context->m_context->m_rootLayout->readAll(m_context->m_context, this);
1365
//ELSE_TRY_READ_IF(title)
1366
//ELSE_TRY_READ_IF(sampData)
1367
//ELSE_TRY_READ_IF(styleData)
1370
Q_ASSERT(m_context->m_context->m_rootPoint);
1372
//m_context->m_context->m_rootPoint->dump(m_context->m_context,0);
1373
m_context->m_context->m_rootLayout->readDone(m_context->m_context);
1377
const QString xml = QString::fromUtf8(device()->readAll());
1379
QXmlNamePool namepool;
1380
//QXmlName name1(namepool, "layoutDef", "http://schemas.openxmlformats.org/drawingml/2006/diagram", "dgm");
1381
QXmlQuery query(QXmlQuery::XSLT20, namepool);
1382
if (!query.setFocus(xml)) {
1383
return KoFilter::WrongFormat;
1386
//query.bindVariable("inputDocument", ba);
1388
class UriResolver : public QAbstractUriResolver {
1390
UriResolver() : QAbstractUriResolver() {}
1391
virtual ~UriResolver() {}
1392
virtual QUrl resolve(const QUrl &relative, const QUrl &baseURI) const { return QString(); }
1394
UriResolver resolver;
1395
query.setUriResolver(&resolver);
1398
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1400
"xmlns:dgm=\"http://schemas.openxmlformats.org/drawingml/2006/diagram\"\n"
1401
"xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n"
1402
"version=\"2.0\">\n"
1403
"<xsl:template match=\"/dgm:layoutDef\">\n"
1406
"</xsl:stylesheet>\n"
1408
Q_ASSERT(query.isValid());
1411
QBuffer buffer(&result);
1412
buffer.open(QBuffer::ReadWrite);
1413
query.evaluateTo(&buffer);
1415
kDebug()<<"3>>>>>>"<<result;
1418
else if (qualifiedName() == QLatin1String("dgm:styleDef")) {
1419
m_type = StyleDefType;
1422
else if (qualifiedName() == QLatin1String("dgm:colorsDef")) {
1423
m_type = ColorsDefType;
1427
return KoFilter::WrongFormat;
1431
m_type = InvalidType;
1432
return KoFilter::OK;