~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to filters/libmsooxml/MsooXmlDiagramReader.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2010-10-27 17:52:57 UTC
  • mfrom: (0.12.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20101027175257-s04zqqk5bs8ckm9o
Tags: 1:2.2.83-0ubuntu1
* Merge with Debian git remaining changes:
 - Add build-deps on librcps-dev, opengtl-dev, libqtgtl-dev, freetds-dev,
   create-resources, libspnav-dev
 - Remove needless build-dep on libwv2-dev
 - koffice-libs recommends create-resources
 - krita recommends pstoedit
 - Keep our patches
* New upstream release 2.3 beta 3
  - Remove debian/patches fixed by upstream
  - Update install files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of Office 2007 Filters for KOffice
 
3
 *
 
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).
 
7
 *
 
8
 * Contact: Suresh Chande suresh.chande@nokia.com
 
9
 *
 
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.
 
13
 *
 
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.
 
18
 *
 
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
 
22
 * 02110-1301 USA
 
23
 *
 
24
 */
 
25
 
 
26
#include "MsooXmlDiagramReader.h"
 
27
 
 
28
#define MSOOXML_CURRENT_NS "dgm"
 
29
#define MSOOXML_CURRENT_CLASS MsooXmlDiagramReader
 
30
#define BIND_READ_CLASS MSOOXML_CURRENT_CLASS
 
31
 
 
32
#include <MsooXmlReader_p.h>
 
33
#include <MsooXmlUtils.h>
 
34
#include <KoXmlWriter.h>
 
35
#include <KoGenStyles.h>
 
36
//#include <QXmlQuery>
 
37
//#include <QAbstractUriResolver>
 
38
#include <typeinfo>
 
39
 
 
40
namespace MSOOXML { namespace Diagram {
 
41
 
 
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.
 
45
 *
 
46
 * See also;
 
47
 * - http://wiki.services.openoffice.org/wiki/SmartArt
 
48
 * - http://msdn.microsoft.com/en-us/magazine/cc163470.aspx
 
49
 */
 
50
 
 
51
#define DEBUG_DUMP \
 
52
    qDebug() << QString("%1Dgm::%2::%3").arg(QString(' ').repeated(level)).arg(typeid(this).name()).arg(__FUNCTION__) << this << "atom=" << m_tagName
 
53
#define DEBUG_WRITE \
 
54
    qDebug() << QString("Dgm::%1::%2").arg(typeid(this).name()).arg(__FUNCTION__) << "atom=" << m_tagName
 
55
 
 
56
class AbstractNode;
 
57
class PointNode;
 
58
class PointListNode;
 
59
class ConnectionListNode;
 
60
class AbstractAtom;
 
61
class LayoutNodeAtom;
 
62
class ConstraintAtom;
 
63
class AlgorithmAtom;
 
64
 
 
65
/// The evaluation context that is passed around and contains all kind of state-informations.
 
66
class Context
 
67
{
 
68
    public:
 
69
        AbstractNode* m_rootPoint;
 
70
        ConnectionListNode* m_connections;
 
71
        LayoutNodeAtom* m_rootLayout;
 
72
        LayoutNodeAtom* m_parentLayout;
 
73
        QMap<QString, LayoutNodeAtom*> m_layoutMap;
 
74
        explicit Context();
 
75
        ~Context();
 
76
        AbstractNode* currentNode() const { return m_currentNode; }
 
77
        void setCurrentNode(AbstractNode* node);
 
78
    private:
 
79
        AbstractNode* m_currentNode; // the moving context node
 
80
};
 
81
 
 
82
/****************************************************************************************************
 
83
 * It follws the classes used within the data-model to build up a tree of data-nodes.
 
84
 */
 
85
 
 
86
/// The AbstractNode is the base class to handle the diagram data-model (content of data1.xml).
 
87
class AbstractNode
 
88
{
 
89
    public:
 
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);
 
96
        }
 
97
        virtual void readElement(Context*, MsooXmlDiagramReader*) {
 
98
        }
 
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);
 
105
            }
 
106
        }
 
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);
 
113
        }
 
114
        void removeChild(AbstractNode* node) {
 
115
            Q_ASSERT(node->m_parent == this);
 
116
            node->m_parent = 0;
 
117
            m_children.removeAll(node);
 
118
        }
 
119
        QList<AbstractNode*> descendant() const {
 
120
            QList<AbstractNode*> list = m_children;
 
121
            foreach(AbstractNode* node, m_children)
 
122
                foreach(AbstractNode* n, node->descendant())
 
123
                    list.append(n);
 
124
            return list;
 
125
        }
 
126
        QList<AbstractNode*> peers() const {
 
127
            QList<AbstractNode*> list;
 
128
            if (m_parent)
 
129
                foreach(AbstractNode* node, m_parent->m_children)
 
130
                    if(node != this)
 
131
                        list.append(node);
 
132
            return list;
 
133
        }                
 
134
    protected:
 
135
        AbstractNode* m_parent;
 
136
        QList<AbstractNode*> m_children;
 
137
};
 
138
 
 
139
/// A point in the data-model.
 
140
class PointNode : public AbstractNode
 
141
{
 
142
    public:
 
143
        QString m_modelId;
 
144
        QString m_type;
 
145
        QString m_cxnId;
 
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);
 
151
        }
 
152
        virtual void readElement(Context*, MsooXmlDiagramReader* reader) {
 
153
            if (reader->isStartElement()) {
 
154
                if (reader->qualifiedName() == QLatin1String("dgm:prSet")) {
 
155
                    //TODO
 
156
                } else if (reader->qualifiedName() == QLatin1String("dgm:spPr")) {
 
157
                    //TODO
 
158
                } else if (reader->qualifiedName() == QLatin1String("dgm:t")) {
 
159
                    //TODO
 
160
                }
 
161
            }
 
162
        }
 
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)
 
170
            else
 
171
                m_cxnId.clear();
 
172
            AbstractNode::readAll(context, reader);
 
173
        }
 
174
};
 
175
 
 
176
/// A list of points in the data-model.
 
177
class PointListNode : public AbstractNode
 
178
{
 
179
    public:
 
180
        explicit PointListNode() : AbstractNode("dgm:ptLst") {}
 
181
        virtual ~PointListNode() {}
 
182
        virtual void dump(Context* context, int level) {
 
183
            //DEBUG_DUMP;
 
184
            AbstractNode::dump(context, level);
 
185
        }
 
186
        virtual void readElement(Context* context, MsooXmlDiagramReader* reader) {
 
187
            if (reader->isStartElement()) {
 
188
                if (reader->qualifiedName() == QLatin1String("dgm:pt")) {
 
189
                    PointNode *n = new PointNode;
 
190
                    addChild(n);
 
191
                    n->readAll(context, reader);
 
192
                }
 
193
            }
 
194
        }
 
195
};
 
196
 
 
197
/// A connection between two nodes in the data-model.
 
198
class ConnectionNode : public AbstractNode
 
199
{
 
200
    public:
 
201
        QString m_modelId;
 
202
        QString m_type;
 
203
        QString m_srcId;
 
204
        QString m_destId;
 
205
        QString m_presId;
 
206
        QString m_sibTransId;
 
207
        int m_srcOrd;
 
208
        int m_destOrd;
 
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;
 
213
        }
 
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);
 
228
        }
 
229
};
 
230
 
 
231
/// A list of connections in the data-model.
 
232
class ConnectionListNode : public AbstractNode
 
233
{
 
234
    public:
 
235
        explicit ConnectionListNode() : AbstractNode("dgm:cxnLst") {}
 
236
        virtual ~ConnectionListNode() {}
 
237
        virtual void dump(Context* context, int level) {
 
238
            //DEBUG_DUMP;
 
239
            AbstractNode::dump(context, level);
 
240
        }
 
241
        virtual void readElement(Context* context, MsooXmlDiagramReader* reader) {
 
242
            if (reader->isStartElement()) {
 
243
                if (reader->qualifiedName() == QLatin1String("dgm:cxn")) {
 
244
                    ConnectionNode *n = new ConnectionNode;
 
245
                    addChild(n);
 
246
                    n->readAll(context, reader);
 
247
                }
 
248
            }
 
249
        }
 
250
};
 
251
 
 
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.
 
255
 */
 
256
 
 
257
/// Base class for layout-operations (content of layout1.xml)
 
258
class AbstractAtom
 
259
{
 
260
    public:
 
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);
 
267
        }
 
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);
 
275
            }
 
276
        }
 
277
        virtual void readDone(Context* context) {
 
278
            foreach(AbstractAtom* atom, m_children)
 
279
                atom->readDone(context);
 
280
        }
 
281
        virtual void layoutAtom(Context* context) {
 
282
            foreach(AbstractAtom* atom, m_children)
 
283
                atom->layoutAtom(context);
 
284
        }
 
285
        virtual void writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles) {
 
286
            foreach(AbstractAtom* atom, m_children)
 
287
                atom->writeAtom(context, xmlWriter, styles);
 
288
        }
 
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);
 
296
        }
 
297
        void removeChild(AbstractAtom* node) {
 
298
            Q_ASSERT(node->m_parent == this);
 
299
            node->m_parent = 0;
 
300
            m_children.removeAll(node);
 
301
        }
 
302
 
 
303
    protected:
 
304
        AbstractAtom* m_parent;
 
305
        QList<AbstractAtom*> m_children;
 
306
 
 
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);
 
309
 
 
310
            const QStringList typeList = _ptType.split(' ', QString::SkipEmptyParts);
 
311
            Q_ASSERT(axisList.count() <= 1 || axisList.count() == typeList.count());
 
312
            
 
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());
 
319
 
 
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())
 
326
                        list.append(n);
 
327
                } else if(axis == QLatin1String("ancstOrSelf")) { // Ancestor Or Self
 
328
                    for(AbstractNode* n = context->currentNode(); n; n = n->parent())
 
329
                        list.append(n);
 
330
                    list.append(context->currentNode());
 
331
                } else if(axis == QLatin1String("ch")) { // Child
 
332
                    foreach(AbstractNode* n, context->currentNode()->children())
 
333
                        list.append(n);
 
334
                } else if(axis == QLatin1String("des")) { // Descendant
 
335
                    foreach(AbstractNode* n, context->currentNode()->descendant())
 
336
                        list.append(n);
 
337
                } else if(axis == QLatin1String("desOrSelf")) { // Descendant Or Self
 
338
                    foreach(AbstractNode* n, context->currentNode()->descendant())
 
339
                        list.append(n);
 
340
                    list.append(context->currentNode());
 
341
                } else if(axis == QLatin1String("follow")) { // Follow
 
342
                    foreach(AbstractNode* peer, context->currentNode()->peers()) {
 
343
                        list.append(peer);
 
344
                        foreach(AbstractNode* n, peer->descendant())
 
345
                            list.append(n);
 
346
                    }
 
347
                } else if(axis == QLatin1String("followSib")) { // Follow Sibling
 
348
                    foreach(AbstractNode* n, context->currentNode()->peers())
 
349
                        list.append(n);
 
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
 
354
                    //TODO
 
355
                } else if(axis == QLatin1String("precedSib")) { // Preceding Sibling
 
356
                    //TODO
 
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());
 
361
                }
 
362
 
 
363
                // optionally filter the list
 
364
                if(i < typeList.count()) {
 
365
                    QList<AbstractNode*> _list = list;
 
366
                    list.clear();
 
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")) {
 
371
                                list.append(pt);
 
372
                            }
 
373
                        }
 
374
                    }
 
375
                }
 
376
 
 
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);
 
383
                }
 
384
 
 
385
                // transfer the resulting list to the result-list.
 
386
                foreach(AbstractNode* node, list) {
 
387
                    result.append(node);
 
388
                }
 
389
            }
 
390
 
 
391
            return result;
 
392
        }
 
393
 
 
394
    private:
 
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;
 
402
            }
 
403
            return result;
 
404
        }
 
405
};
 
406
 
 
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
 
409
{
 
410
    public:
 
411
        QString m_name;
 
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);
 
420
        }
 
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;
 
430
        }
 
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;
 
445
        }
 
446
    private:
 
447
        QList<ConstraintAtom*> m_constraints;
 
448
        AlgorithmAtom* m_algorithm;
 
449
        QList<AbstractNode*> m_axis;
 
450
        bool m_needsRelayout, m_childNeedsRelayout;
 
451
};
 
452
 
 
453
/// Specify size and position of nodes, text values, and layout dependencies between nodes in a layout definition.
 
454
class ConstraintAtom : public AbstractAtom
 
455
{
 
456
    public:
 
457
        /// Factor used in a reference constraint or a rule in order to modify a referenced value by the factor defined.
 
458
        double m_fact;
 
459
        /// Specifies the axis of layout nodes to apply a constraint or rule to.
 
460
        QString m_for;
 
461
        /// Specifies the name of the layout node to apply a constraint or rule to.
 
462
        QString m_forName;
 
463
        /// The operator constraint used to evaluate the condition.
 
464
        QString m_op;
 
465
        /// Specifies the type of data point to select.
 
466
        QString m_ptType;
 
467
        /// The point type used int he referenced constraint.
 
468
        QString m_refPtType;
 
469
        /// Specifies the type of a reference constraint.
 
470
        QString m_refType;
 
471
        /// The for value of the referenced constraint.
 
472
        QString m_refFor;
 
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.
 
476
        QString m_type;
 
477
        /// Specifies an absolute value instead of reference another constraint.
 
478
        QString m_value;
 
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);
 
493
            DEBUG_DUMP << s;
 
494
        }
 
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);
 
510
        }
 
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);
 
515
        }
 
516
};
 
517
 
 
518
/// List of constraints.
 
519
class ConstraintListAtom : public AbstractAtom
 
520
{
 
521
    public:
 
522
        explicit ConstraintListAtom() : AbstractAtom("dgm:constrLst") {}
 
523
        virtual ~ConstraintListAtom() {}
 
524
        virtual void dump(Context* context, int level) {
 
525
            AbstractAtom::dump(context, level);
 
526
        }
 
527
        virtual void readElement(Context* context, MsooXmlDiagramReader* reader) {
 
528
            if (reader->isStartElement()) {
 
529
                if (reader->qualifiedName() == QLatin1String("dgm:constr")) {
 
530
                    ConstraintAtom* node = new ConstraintAtom;
 
531
                    addChild(node);
 
532
                    node->readAll(context, reader);
 
533
                }
 
534
            }
 
535
        }
 
536
};
 
537
 
 
538
/// The shape displayed by the containing layout node. Not all layout nodes display shapes.
 
539
class ShapeAtom : public AbstractAtom
 
540
{
 
541
    public:
 
542
        QString m_type;
 
543
        QString m_blip;
 
544
        bool m_hideGeom;
 
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);
 
553
        }
 
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);
 
562
        }
 
563
 
 
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;
 
569
            
 
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;
 
577
 
 
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);
 
582
 
 
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");
 
590
 
 
591
/*
 
592
static int iii=0;
 
593
iii++;
 
594
if(x+cx<0) { x=iii*30; cx=0; }
 
595
if(y+cy<0) { y=iii*30; cy=0; }
 
596
if(w<0) { w=50; }
 
597
if(h<0) { h=50; }
 
598
//Q_ASSERT(false);
 
599
*/
 
600
 
 
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));
 
605
 
 
606
            xmlWriter->startElement("text:p");
 
607
            xmlWriter->endElement();
 
608
 
 
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"))*/ {
 
627
                //TODO
 
628
                kWarning() << "TODO shape type=" << m_type;
 
629
            }
 
630
 
 
631
            xmlWriter->endElement(); // draw:custom-shape
 
632
        }
 
633
};
 
634
 
 
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
 
637
{
 
638
    public:
 
639
        enum Algorithm {
 
640
            UnknownAlg,
 
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.
 
643
            CompositeAlg,
 
644
            // The connector algorithm lays out and routes connecting lines, arrows, and shapes between layout nodes.
 
645
            ConnectorAlg,
 
646
            // The cycle algorithm lays out child layout nodes around a circle or portion of a circle using equal angle spacing.
 
647
            CycleAlg,
 
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.
 
650
            HierChildAlg,
 
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.
 
653
            HierRootAlg,
 
654
            // The linear algorithm lays out child layout nodes along a linear path.
 
655
            LinearAlg,
 
656
            // The pyramid algorithm lays out child layout nodes along a vertical path and works with the trapezoid
 
657
            // shape to create a pyramid.
 
658
            PyramidAlg,
 
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.
 
661
            SnakeAlg,
 
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.
 
664
            SpaceAlg,
 
665
            // The text algorithm sizes text to fit inside a shape and controls its margins and alignment.
 
666
            TextAlg
 
667
        };
 
668
        Algorithm m_type;
 
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);
 
675
        }
 
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);
 
692
        }
 
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);
 
700
                }
 
701
            }
 
702
        }
 
703
};
 
704
 
 
705
/// This element specifies a particular data model point which is to be mapped to the containing layout node.
 
706
class PresentationOfAtom : public AbstractAtom
 
707
{
 
708
    public:
 
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
 
711
        QString m_count;
 
712
        QString m_hideLastTrans;
 
713
        QString m_start;
 
714
        QString m_step;
 
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);
 
720
        }
 
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);
 
730
        }
 
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);
 
735
        }
 
736
};
 
737
 
 
738
/// The if element represents a condition that applies to all it's children.
 
739
class IfAtom : public AbstractAtom
 
740
{
 
741
    public:
 
742
        QString m_argument;
 
743
        QString m_axis;
 
744
        QString m_function;
 
745
        QString m_hideLastTrans;
 
746
        QString m_name;
 
747
        QString m_operator;
 
748
        QString m_ptType;
 
749
        QString m_start;
 
750
        QString m_step;
 
751
        QString m_count;
 
752
        QString m_value;
 
753
        explicit IfAtom(bool isTrue) : AbstractAtom(isTrue ? "dgm:if" : "dgm:else"), m_isTrue(isTrue) {}
 
754
        virtual ~IfAtom() {}
 
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);
 
759
        }
 
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);
 
774
        }
 
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);
 
779
            QString funcValue;
 
780
            if(m_function == "cnt") { // Specifies a count.
 
781
                funcValue = QString::number(axis.count());
 
782
            } else if(m_function == "depth") { // Specifies the depth.
 
783
                //int depth = 0;
 
784
                //for(AbstractNode* n = context->m_currentNode; n; n = n->parent(), ++depth);
 
785
                //istrue = depth == m_value.toInt();
 
786
                //TODO
 
787
                kWarning()<<"TODO func=depth";
 
788
            } else if(m_function == "maxDepth") { // Defines the maximum depth.
 
789
                //int depth = 0;
 
790
                //for(AbstractNode* n = context->m_currentNode; n; n = n->parent(), ++depth);
 
791
                //istrue = depth <= m_value.toInt();
 
792
                //TODO
 
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();
 
797
                //TODO
 
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;
 
802
                //TODO
 
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;
 
807
                //TODO
 
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();
 
812
                //TODO
 
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
 
816
                    //TODO
 
817
                } else if(m_argument == QLatin1String("animOne")) { // Specifies animate as one.
 
818
                    //TODO
 
819
                } else if(m_argument == QLatin1String("bulEnabled")) { // Specifies bullets enabled.
 
820
                    //TODO
 
821
                } else if(m_argument == QLatin1String("chMax")) { // The maximum number of children.
 
822
                    //TODO
 
823
                } else if(m_argument == QLatin1String("chPref")) { // The preferred number of children.
 
824
                    //TODO
 
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?
 
827
                    funcValue = "norm";
 
828
                } else if(m_argument == QLatin1String("hierBranch")) { // The hierarchy branch.
 
829
                    //TODO
 
830
                } else if(m_argument == QLatin1String("none")) { // Unknown variable type.
 
831
                    //TODO
 
832
                } else if(m_argument == QLatin1String("orgChart")) { // Algorithm that lays out an org chart.
 
833
                    //TODO
 
834
                } else if(m_argument == QLatin1String("resizeHandles")) { // Specifies the resize handles.
 
835
                    //TODO
 
836
                } else {
 
837
                    kWarning()<<"Unexpected argument="<<m_argument<<"name="<<m_name;
 
838
                }
 
839
            }
 
840
 
 
841
            bool istrue = false;
 
842
            if(m_isTrue && !funcValue.isNull()) {
 
843
                if(m_operator == "equ") {
 
844
                    istrue = funcValue == m_value;
 
845
                } else {
 
846
                    bool isInt;
 
847
                    const int funcValueInt = funcValue.toInt(&isInt);
 
848
                    const int valueInt = isInt ? m_value.toInt(&isInt) : 0;
 
849
                    if(!isInt) {
 
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";
 
853
                    }
 
854
 
 
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;
 
865
                    } else {
 
866
                        kWarning()<<"Unexpected operator="<<m_operator<<"name="<<m_name;
 
867
                    }
 
868
                }
 
869
                //kDebug()<<"name="<<m_name<<"value1="<<funcValue<<"value2="<<m_value<<"operator="<<m_operator<<"istrue="<<istrue;
 
870
            }
 
871
 
 
872
            return istrue;
 
873
        }
 
874
    private:
 
875
        bool m_isTrue;
 
876
};
 
877
 
 
878
/// The choose element wraps if/else blocks into a choose block.
 
879
class ChooseAtom : public AbstractAtom
 
880
{
 
881
    public:
 
882
        QString m_name;
 
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);
 
889
        }
 
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);
 
894
        }
 
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);
 
899
                    addChild(n);
 
900
                    n->readAll(context, reader);
 
901
                } else if (reader->qualifiedName() == QLatin1String("dgm:else")) {
 
902
                    IfAtom *n = new IfAtom(false);
 
903
                    addChild(n);
 
904
                    n->readAll(context, reader);
 
905
                }
 
906
            }
 
907
        }
 
908
        virtual void layoutAtom(Context* context) {
 
909
            foreach(AbstractAtom* atom, atomsMatchingToCondition(context))
 
910
                atom->layoutAtom(context);
 
911
        }
 
912
        virtual void writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles) {
 
913
            DEBUG_WRITE;
 
914
            foreach(AbstractAtom* atom, atomsMatchingToCondition(context))
 
915
                atom->writeAtom(context, xmlWriter, styles);
 
916
        }
 
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);
 
925
                    } else {
 
926
                        elseResult.append(ifatom);
 
927
                    }
 
928
                }
 
929
            }
 
930
            return ifResult.isEmpty() ? elseResult : ifResult;
 
931
        }
 
932
};
 
933
 
 
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
 
936
{
 
937
    public:
 
938
        QString m_axis;
 
939
        QString m_hideLastTrans;
 
940
        QString m_name;
 
941
        QString m_ptType;
 
942
        QString m_reference;
 
943
        QString m_start;
 
944
        QString m_step;
 
945
        QString m_count;
 
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);
 
952
        }
 
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);
 
964
        }
 
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);
 
971
            }
 
972
        }
 
973
        virtual void writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles) {
 
974
            DEBUG_WRITE;
 
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);
 
980
            }
 
981
        }
 
982
};
 
983
 
 
984
Context::Context()
 
985
    : m_rootPoint(0)
 
986
    , m_connections(new ConnectionListNode)
 
987
    , m_rootLayout(new Diagram::LayoutNodeAtom)
 
988
    , m_parentLayout(m_rootLayout)
 
989
    , m_currentNode(0)
 
990
{
 
991
}
 
992
 
 
993
Context::~Context()
 
994
{
 
995
    delete m_rootPoint;
 
996
    delete m_connections;
 
997
    delete m_rootLayout;
 
998
}
 
999
 
 
1000
void Context::setCurrentNode(AbstractNode* node)
 
1001
{
 
1002
    Q_ASSERT(dynamic_cast<PointNode*>(node));
 
1003
    m_currentNode = node;
 
1004
}
 
1005
 
 
1006
void AbstractAtom::readElement(Context* context, MsooXmlDiagramReader* reader)
 
1007
{
 
1008
    if (reader->isStartElement()) {
 
1009
        AbstractAtom *node = 0;
 
1010
 
 
1011
        if (reader->qualifiedName() == QLatin1String("dgm:layoutNode")) {
 
1012
            node = new LayoutNodeAtom;
 
1013
        }
 
1014
        else if (reader->qualifiedName() == QLatin1String("dgm:shape")) {
 
1015
            node = new ShapeAtom;
 
1016
        }
 
1017
        else if (reader->qualifiedName() == QLatin1String("dgm:alg")) {
 
1018
            node = new AlgorithmAtom;
 
1019
        }
 
1020
        else if (reader->qualifiedName() == QLatin1String("dgm:presOf")) {
 
1021
            node = new PresentationOfAtom;
 
1022
        }
 
1023
        else if (reader->qualifiedName() == QLatin1String("dgm:choose")) {
 
1024
            node = new ChooseAtom;
 
1025
        }
 
1026
        else if (reader->qualifiedName() == QLatin1String("dgm:forEach")) {
 
1027
            node = new ForEachAtom;
 
1028
        }
 
1029
        else if (reader->qualifiedName() == QLatin1String("dgm:constrLst")) {
 
1030
            node = new ConstraintListAtom;
 
1031
        }
 
1032
        
 
1033
        if (node) {
 
1034
            addChild(node);
 
1035
            node->readAll(context, reader);
 
1036
        }
 
1037
    }
 
1038
}
 
1039
 
 
1040
template<class U, class T> QList<U*> AbstractAtom::filterItems(Context* context, const QList<T*> &items) const
 
1041
{
 
1042
    QList<U*> results;
 
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)
 
1047
                results.append(a);
 
1048
        } else if(ForEachAtom* foreachatom = dynamic_cast<ForEachAtom*>(atom)) {
 
1049
            QList<U*> children = filterItems<U, AbstractAtom>(context, foreachatom->children());
 
1050
            foreach(U* a, children)
 
1051
                results.append(a);
 
1052
        } else if(U* a = dynamic_cast<U*>(atom)) {
 
1053
            results.append(a);
 
1054
        }
 
1055
    }
 
1056
    return results;
 
1057
}
 
1058
 
 
1059
void LayoutNodeAtom::layoutAtom(Context* context)
 
1060
{
 
1061
    LayoutNodeAtom* oldLayout = context->m_parentLayout;
 
1062
    context->m_parentLayout = this;
 
1063
 
 
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;
 
1077
 
 
1078
    /*
 
1079
    if(m_childNeedsRelayout) {
 
1080
        m_childNeedsRelayout = false;
 
1081
        foreach(AbstractAtom* atom, m_children) {
 
1082
            atom->layoutAtom(context);
 
1083
        }
 
1084
    }
 
1085
    */
 
1086
 
 
1087
    AlgorithmAtom::Algorithm algorithm = AlgorithmAtom::UnknownAlg;
 
1088
    QList< QPair<QString,QString> > params;
 
1089
    if(m_algorithm) {
 
1090
        algorithm = m_algorithm->m_type;
 
1091
        params = m_algorithm->m_params;
 
1092
    }
 
1093
 
 
1094
    // layout ourself if requested
 
1095
    if(m_needsRelayout) {
 
1096
        m_needsRelayout = false;
 
1097
 
 
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);
 
1102
 
 
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); 
 
1107
 
 
1108
            int value = -1;
 
1109
            if(!c->m_value.isEmpty()) {
 
1110
                bool ok;
 
1111
                value = c->m_value.toInt(&ok);
 
1112
                Q_ASSERT(ok);
 
1113
            } else {
 
1114
                LayoutNodeAtom* ref = c->m_refForName.isEmpty() ? this : context->m_layoutMap.value(c->m_refForName);
 
1115
                Q_ASSERT(ref);
 
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;
 
1123
                    return;
 
1124
                }
 
1125
 
 
1126
                if(!c->m_refType.isEmpty()) {
 
1127
                    if(c->m_refType == "l") {
 
1128
                        value = ref->m_x;
 
1129
                    } else if(c->m_refType == "t") {
 
1130
                        value = ref->m_y;
 
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") {
 
1136
                        //TODO
 
1137
                    } else {
 
1138
                        kWarning() << "Unhandled constraint reference-type=" << c->m_refType;
 
1139
                    }
 
1140
                } else {
 
1141
                    //TODO
 
1142
                    kDebug()<<"TODO c->m_refType.isEmpty()";
 
1143
                }
 
1144
            }
 
1145
 
 
1146
            //Q_ASSERT(c->m_for.isEmpty() == c->m_forName.isEmpty() || c->m_type=="primFontSz");
 
1147
 
 
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")) {
 
1167
                //TODO
 
1168
            } else if(c->m_type == QLatin1String("tMarg")) {
 
1169
                //TODO
 
1170
            } else if(c->m_type == QLatin1String("rMarg")) {
 
1171
                //TODO
 
1172
            } else if(c->m_type == QLatin1String("bMarg")) {
 
1173
                //TODO
 
1174
            } else if(c->m_type == QLatin1String("primFontSz")) {
 
1175
                //TODO
 
1176
            } else {
 
1177
                kWarning() << "Unhandled constraint type=" << c->m_type;
 
1178
            }
 
1179
 
 
1180
            //dump(context,10);
 
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);
 
1197
                }
 
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);
 
1200
            }
 
1201
        }
 
1202
        //kDebug() << "####/CONSTRAINTS-END";
 
1203
    }
 
1204
    
 
1205
//dump(context,10);
 
1206
 
 
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);
 
1212
        }
 
1213
    }
 
1214
 
 
1215
    //TODO evaluate rules too
 
1216
 
 
1217
    context->m_parentLayout = oldLayout;
 
1218
}
 
1219
 
 
1220
void LayoutNodeAtom::writeAtom(Context* context, KoXmlWriter* xmlWriter, KoGenStyles* styles)
 
1221
{
 
1222
    AlgorithmAtom::Algorithm algorithm = AlgorithmAtom::UnknownAlg;
 
1223
    QList< QPair<QString,QString> > params;
 
1224
    if(m_algorithm) {
 
1225
        algorithm = m_algorithm->m_type;
 
1226
        params = m_algorithm->m_params;
 
1227
    }
 
1228
    DEBUG_WRITE << "name=" << m_name << "algorithm=" << algorithm << "params=" << params;
 
1229
 
 
1230
    LayoutNodeAtom* oldLayout = context->m_parentLayout;
 
1231
    context->m_parentLayout = this;
 
1232
 
 
1233
    AbstractAtom::writeAtom(context, xmlWriter, styles);
 
1234
    context->m_parentLayout = oldLayout;
 
1235
}
 
1236
 
 
1237
}} // namespace MSOOXML::Diagram
 
1238
 
 
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.
 
1242
 */
 
1243
 
 
1244
using namespace MSOOXML;
 
1245
 
 
1246
MsooXmlDiagramReaderContext::MsooXmlDiagramReaderContext(KoGenStyles* styles)
 
1247
    : MSOOXML::MsooXmlReaderContext()
 
1248
    , m_styles(styles)
 
1249
    , m_context(new Diagram::Context)
 
1250
{
 
1251
}
 
1252
 
 
1253
MsooXmlDiagramReaderContext::~MsooXmlDiagramReaderContext()
 
1254
{
 
1255
    delete m_context;
 
1256
}
 
1257
 
 
1258
void MsooXmlDiagramReaderContext::saveIndex(KoXmlWriter* xmlWriter, const QRect &rect)
 
1259
{
 
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);
 
1269
}
 
1270
 
 
1271
MsooXmlDiagramReader::MsooXmlDiagramReader(KoOdfWriters *writers)
 
1272
    : MSOOXML::MsooXmlCommonReader(writers)
 
1273
    , m_type(InvalidType)
 
1274
{
 
1275
}
 
1276
 
 
1277
MsooXmlDiagramReader::~MsooXmlDiagramReader()
 
1278
{
 
1279
}
 
1280
 
 
1281
KoFilter::ConversionStatus MsooXmlDiagramReader::read(MSOOXML::MsooXmlReaderContext* context)
 
1282
{
 
1283
    m_context = dynamic_cast<MsooXmlDiagramReaderContext*>(context);
 
1284
    Q_ASSERT(m_context);
 
1285
 
 
1286
    readNext();
 
1287
    if (!isStartDocument()) {
 
1288
        return KoFilter::WrongFormat;
 
1289
    }
 
1290
 
 
1291
    readNext();
 
1292
    if (qualifiedName() == QLatin1String("dgm:dataModel")) {
 
1293
        m_type = DataModelType;
 
1294
        
 
1295
        Diagram::PointListNode rootList;
 
1296
        while (!atEnd()) {
 
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);
 
1304
                }
 
1305
            }
 
1306
        }
 
1307
 
 
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;
 
1313
        }
 
1314
 
 
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;
 
1319
 
 
1320
                Diagram::PointNode* source = 0;
 
1321
                if (pointTree.contains(connection->m_srcId)) {
 
1322
                    source = pointTree[connection->m_srcId];
 
1323
                }
 
1324
                else {
 
1325
                    if (!pointMap.contains(connection->m_srcId)) continue;
 
1326
                    source = pointMap[connection->m_srcId];
 
1327
                    pointTree[connection->m_srcId] = source;
 
1328
                }
 
1329
 
 
1330
                if (!pointMap.contains(connection->m_destId)) continue;
 
1331
 
 
1332
                Diagram::PointNode* destination = pointMap[connection->m_destId];
 
1333
                rootList.removeChild(destination);
 
1334
                source->addChild(destination);
 
1335
                pointTree[connection->m_destId] = destination;
 
1336
            }
 
1337
        }
 
1338
 
 
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;
 
1344
                    break;
 
1345
                }
 
1346
            }
 
1347
        }
 
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);
 
1351
 
 
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);
 
1354
    }
 
1355
    else if (qualifiedName() == QLatin1String("dgm:layoutDef")) {
 
1356
        m_type = LayoutDefType;
 
1357
 
 
1358
        while (!atEnd()) {
 
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);
 
1364
                }
 
1365
                //ELSE_TRY_READ_IF(title)
 
1366
                //ELSE_TRY_READ_IF(sampData)
 
1367
                //ELSE_TRY_READ_IF(styleData)
 
1368
            }
 
1369
        }
 
1370
        Q_ASSERT(m_context->m_context->m_rootPoint);
 
1371
        
 
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);
 
1374
        
 
1375
#if 0
 
1376
        device()->seek(0);
 
1377
        const QString xml = QString::fromUtf8(device()->readAll());
 
1378
 
 
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;
 
1384
        }
 
1385
 
 
1386
        //query.bindVariable("inputDocument", ba);
 
1387
        
 
1388
        class UriResolver : public QAbstractUriResolver {
 
1389
            public:
 
1390
                UriResolver() : QAbstractUriResolver() {}
 
1391
                virtual ~UriResolver() {}
 
1392
                virtual QUrl resolve(const QUrl &relative, const QUrl &baseURI) const { return QString(); }
 
1393
        };
 
1394
        UriResolver resolver;
 
1395
        query.setUriResolver(&resolver);
 
1396
 
 
1397
        query.setQuery(
 
1398
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 
1399
            "<xsl:stylesheet\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"
 
1404
                "abc\n"
 
1405
            "</xsl:template>\n"
 
1406
            "</xsl:stylesheet>\n"
 
1407
        );
 
1408
        Q_ASSERT(query.isValid());
 
1409
 
 
1410
        QByteArray result;
 
1411
        QBuffer buffer(&result);
 
1412
        buffer.open(QBuffer::ReadWrite);
 
1413
        query.evaluateTo(&buffer);
 
1414
        buffer.close();
 
1415
        kDebug()<<"3>>>>>>"<<result;
 
1416
#endif
 
1417
    }
 
1418
    else if (qualifiedName() == QLatin1String("dgm:styleDef")) {
 
1419
        m_type = StyleDefType;
 
1420
        //TODO
 
1421
    }
 
1422
    else if (qualifiedName() == QLatin1String("dgm:colorsDef")) {
 
1423
        m_type = ColorsDefType;
 
1424
        //TODO
 
1425
    }
 
1426
    else {
 
1427
        return KoFilter::WrongFormat;
 
1428
    }
 
1429
 
 
1430
    m_context = 0;
 
1431
    m_type = InvalidType;
 
1432
    return KoFilter::OK;
 
1433
}
 
1434