~ubuntu-branches/ubuntu/utopic/psi/utopic

« back to all changes in this revision

Viewing changes to src/wbitems.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-08-28 18:46:52 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080828184652-iiik12dl91nq7cdi
Tags: 0.12-2
Uploading to unstable (Closes: Bug#494352)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * wbitems.cpp - the item classes for the SVG WB
3
 
 * Copyright (C) 2006  Joonas Govenius
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU General Public License
7
 
 * as published by the Free Software Foundation; either version 2
8
 
 * of the License, or (at your option) any later version.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License
16
 
 * along with this library; if not, write to the Free Software
17
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 *
19
 
 */
20
 
 
21
 
#include "wbitems.h"
22
 
#include "wbscene.h"
23
 
#include <QDebug>
24
 
#ifndef M_PI
25
 
#define M_PI 3.14159265358979323846
26
 
#endif
27
 
 
28
 
/*
29
 
 *      Edit
30
 
 */
31
 
 
32
 
Edit::Edit(Type _type, const QDomElement &_xml) {
33
 
        type = _type;
34
 
        xml = _xml.cloneNode().toElement();
35
 
}
36
 
 
37
 
Edit::Edit(Type _type, const QString &_target, const QDomElement &edit, const QString &_oldValue) {
38
 
        type = _type;
39
 
        target = _target;
40
 
        xml = edit.cloneNode().toElement();
41
 
        if(_type == AttributeEdit)
42
 
                oldValue = _oldValue;
43
 
        else if(_type == AttributeEdit)
44
 
                oldParent = _oldValue;
45
 
}
46
 
 
47
 
Edit::Edit(const QString &_target, const QDomElement &edit, QDomNodeList _oldContent) {
48
 
        type = Edit::ContentEdit;
49
 
        target = _target;
50
 
        xml = edit.cloneNode().toElement();
51
 
        oldContent = _oldContent;
52
 
}
53
 
 
54
 
/*
55
 
 *      EditUndo
56
 
 */
57
 
 
58
 
EditUndo::EditUndo(const int &_version, const Edit &edit) {
59
 
        type = edit.type;
60
 
        version = _version;
61
 
        if(type == Edit::AttributeEdit) {
62
 
                attribute = edit.xml.attribute("name");
63
 
                oldValue = edit.oldValue;
64
 
        } else if(type == Edit::ParentEdit) {
65
 
                oldParent = edit.oldParent;
66
 
        } else if(type == Edit::ContentEdit) {
67
 
                oldContent = edit.oldContent;
68
 
        }
69
 
}
70
 
 
71
 
EditUndo::EditUndo(const int &_version, const QString &_attribute, const QString &_oldValue) {
72
 
        type = Edit::AttributeEdit;
73
 
        version = _version;
74
 
        attribute = _attribute;
75
 
        oldValue = _oldValue;
76
 
}
77
 
 
78
 
EditUndo::EditUndo(const int &_version, const QString &_oldParent) {
79
 
        type = Edit::ParentEdit;
80
 
        version = _version;
81
 
        oldParent = _oldParent;
82
 
}
83
 
 
84
 
EditUndo::EditUndo(const int &_version, QDomNodeList _oldContent) {
85
 
        type = Edit::ContentEdit;
86
 
        version = _version;
87
 
        oldContent = _oldContent;
88
 
}
89
 
 
90
 
/*
91
 
 *      WbItemMenu
92
 
 */
93
 
 
94
 
WbItemMenu::WbItemMenu(QWidget* parent) : QMenu(parent) {
95
 
        connect(this, SIGNAL(aboutToHide()), SLOT(destructSelf()));
96
 
}
97
 
 
98
 
WbItemMenu::~WbItemMenu() {
99
 
        foreach(QActionGroup* g, groups_) {
100
 
                foreach(QAction* a, g->actions()) {
101
 
                        a->deleteLater();
102
 
                }
103
 
                g->deleteLater();
104
 
        }
105
 
}
106
 
 
107
 
void WbItemMenu::addActionGroup(QActionGroup* g) {
108
 
        groups_.append(g);
109
 
        addActions(g->actions());
110
 
}
111
 
 
112
 
void WbItemMenu::destructSelf() {
113
 
        deleteLater();
114
 
}
115
 
 
116
 
 
117
 
/*
118
 
 *      WbItem
119
 
 */
120
 
 
121
 
WbItem::WbItem(const QString &id) {
122
 
        id_ = id;
123
 
        parent_ = "root";
124
 
        version = 0;
125
 
}
126
 
 
127
 
QString WbItem::parentWbItem() {
128
 
                return parent_;
129
 
}
130
 
 
131
 
void WbItem::setParentWbItem(const QString &newParent, bool emitChanges) {
132
 
        if(newParent != parent_) {
133
 
                if(newParent.isEmpty()) {
134
 
                        if(parent_ != "root") {
135
 
                                graphicsItem()->setParentItem(0);
136
 
                                if(emitChanges)
137
 
                                        emit parentChanged(id(), "root", parent_);
138
 
                                parent_ = "root";
139
 
                        }
140
 
                } else {
141
 
                        if(graphicsItem()) {
142
 
                                WbScene* wbscene = qobject_cast<WbScene*>(graphicsItem()->scene());
143
 
                                if(wbscene) {
144
 
                                        WbItem* p = wbscene->findWbItem(newParent);
145
 
                                        if(p && p->graphicsItem())
146
 
                                                graphicsItem()->setParentItem(p->graphicsItem());
147
 
                                }
148
 
                        }
149
 
                        if(emitChanges)
150
 
                                emit parentChanged(id(), newParent, parent_);
151
 
                        parent_ = newParent;
152
 
                }
153
 
        }
154
 
}
155
 
 
156
 
QString WbItem::id() {
157
 
        return id_;
158
 
}
159
 
 
160
 
qreal WbItem::index() {
161
 
        return index_;
162
 
}
163
 
 
164
 
void WbItem::setIndex(qreal index, bool emitChanges) {
165
 
        if(index_ != index) {
166
 
                if(emitChanges)
167
 
                        emit indexChanged(id(), index - index_);
168
 
                index_ = index;
169
 
                if(graphicsItem()) {
170
 
                        QString z;
171
 
                        if(index_ - static_cast<int>(index_))
172
 
                                z = QString("%1").arg(index_);
173
 
                        else
174
 
                                z = QString("%1.").arg(index_);
175
 
                        int c;
176
 
                        for(int i=0; i < id_.length(); i++) {
177
 
                                c = id_.at(i).unicode();
178
 
                                //TODO: what should be the minumum width? at least 3 but can a jid contain characters that have a value beyond 999
179
 
                                z.append(QString("%1").arg(QString("%1").arg(c), 4, QLatin1Char('0')));
180
 
                        }
181
 
        //              qDebug() << "z: " << z;
182
 
                        graphicsItem()->setZValue(z.toDouble());
183
 
                }
184
 
        }
185
 
}
186
 
 
187
 
WbItemMenu* WbItem::constructContextMenu() {
188
 
        WbItemMenu* menu = new WbItemMenu(0);
189
 
        WbScene* wbscene = qobject_cast<WbScene*>(graphicsItem()->scene());
190
 
        if(wbscene) {
191
 
                // Add the default actions
192
 
                QActionGroup* group = new QActionGroup(this);
193
 
                QPixmap pixmap(2, 2);
194
 
                pixmap.fill(QColor(Qt::black));
195
 
                QAction* qaction = new QAction(QIcon(pixmap), tr("Thin stroke"), group);
196
 
                qaction->setData(QVariant(1));
197
 
                pixmap = QPixmap(6, 6);
198
 
                pixmap.fill(QColor(Qt::black));
199
 
                qaction = new QAction(QIcon(pixmap), tr("Medium stroke"), group);
200
 
                qaction->setData(QVariant(3));
201
 
                pixmap = QPixmap(12, 12);
202
 
                pixmap.fill(QColor(Qt::black));
203
 
                qaction = new QAction(QIcon(pixmap), tr("Thick stroke"), group);
204
 
                qaction->setData(QVariant(6));
205
 
                connect(group, SIGNAL(triggered(QAction*)), wbscene, SLOT(setStrokeWidth(QAction*)));
206
 
                menu->addActionGroup(group);
207
 
 
208
 
                menu->addSeparator();
209
 
                group = new QActionGroup(this);
210
 
                pixmap = QPixmap(16, 16);
211
 
                pixmap.fill(QColor(Qt::darkCyan));
212
 
                qaction = new QAction(QIcon(pixmap), tr("Change stroke color"), group);
213
 
                connect(qaction, SIGNAL(triggered()), wbscene, SLOT(setStrokeColor()));
214
 
                pixmap.fill(QColor(Qt::darkYellow));
215
 
                qaction = new QAction(QIcon(pixmap), tr("Change fill color"), group);
216
 
                connect(qaction, SIGNAL(triggered()), wbscene, SLOT(setFillColor()));
217
 
                menu->addActionGroup(group);
218
 
 
219
 
                menu->addSeparator();
220
 
                group = new QActionGroup(this);
221
 
                IconAction* action = new IconAction(tr("Bring forward"), "psi/bringForwards", tr("Bring forward"), 0, group);
222
 
                connect(action, SIGNAL(triggered()), wbscene, SLOT(bringForward()));
223
 
                action = new IconAction(tr("Bring to front"), "psi/bringToFront", tr("Bring to front"), 0, group);
224
 
                connect(action, SIGNAL(triggered()), wbscene, SLOT(bringToFront()));
225
 
                action = new IconAction(tr("Send backwards"), "psi/sendBackwards", tr("Send backwards"), 0, group);
226
 
                connect(action, SIGNAL(triggered()), wbscene, SLOT(sendBackwards()));
227
 
                action = new IconAction(tr("Send to back"), "psi/sendToBack", tr("Send to back"), 0, group);
228
 
                connect(action, SIGNAL(triggered()), wbscene, SLOT(sendToBack()));
229
 
                menu->addActionGroup(group);
230
 
 
231
 
                menu->addSeparator();
232
 
                group = new QActionGroup(this);
233
 
                action = new IconAction(tr("Group"), "psi/group", tr("Group"), 0, group);
234
 
                connect(action, SIGNAL(triggered()), wbscene, SLOT(group()));
235
 
                action = new IconAction(tr("Ungroup"), "psi/ungroup", tr("Ungroup"), 0, group);
236
 
                connect(action, SIGNAL(triggered()), wbscene, SLOT(ungroup()));
237
 
                menu->addActionGroup(group);
238
 
        }
239
 
        return menu;
240
 
}
241
 
 
242
 
void WbItem::setStrokeColor(QColor color) {
243
 
        if(graphicsItem()) {
244
 
                QDomElement _svg = svg();
245
 
                _svg.setAttribute("stroke", QString("rgb(%1,%2,%3)").arg(color.red()).arg(color.green()).arg(color.blue()));
246
 
                if(color.alphaF() != 1 || _svg.hasAttribute("stroke-opacity"))
247
 
                        _svg.setAttribute("stroke-opacity", QString("%1").arg(color.alphaF()));
248
 
                parseSvg(_svg, true);
249
 
        }
250
 
}
251
 
 
252
 
void WbItem::setFillColor(QColor color) {
253
 
        if(graphicsItem()) {
254
 
                QDomElement _svg = svg();
255
 
                if(color == Qt::transparent) {
256
 
                        _svg.removeAttribute("fill");
257
 
                        _svg.removeAttribute("fill-opacity");
258
 
                } else {
259
 
                        _svg.setAttribute("fill", QString("rgb(%1,%2,%3)").arg(color.red()).arg(color.green()).arg(color.blue()));
260
 
                        if(color.alphaF() != 1 || _svg.hasAttribute("fill-opacity"))
261
 
                                _svg.setAttribute("fill-opacity", QString("%1").arg(color.alphaF()));
262
 
                }
263
 
                parseSvg(_svg, true);
264
 
        }
265
 
}
266
 
 
267
 
void WbItem::setStrokeWidth(int width) {
268
 
        if(graphicsItem()) {
269
 
                QDomElement _svg = svg();
270
 
                _svg.setAttribute("stroke-width", QString("%1").arg(width));
271
 
                parseSvg(_svg, true);
272
 
        }
273
 
}
274
 
 
275
 
QDomElement WbItem::svg() {
276
 
        QDomDocument doc;
277
 
        QDomElement _svg = doc.createElement("item");
278
 
        foreach(QString a, attributes.keys()) {
279
 
                if(!attributes[a].isNull())
280
 
                        _svg.setAttribute(a, attributes[a]);
281
 
                else
282
 
                        attributes.remove(a);
283
 
        }
284
 
        switch(type()) {
285
 
                case 87654000:
286
 
                        _svg.setTagName("root");
287
 
                        break;
288
 
                case 87654001:
289
 
                        _svg.setTagName("path");
290
 
                        break;
291
 
                case 87654002:
292
 
                        _svg.setTagName("ellipse");
293
 
                        break;
294
 
                case 87654003:
295
 
                        _svg.setTagName("circle");
296
 
                        break;
297
 
                case 87654004:
298
 
                        _svg.setTagName("rect");
299
 
                        break;
300
 
                case 87654005:
301
 
                        _svg.setTagName("line");
302
 
                        break;
303
 
                case 87654006:
304
 
                        _svg.setTagName("polyline");
305
 
                        break;
306
 
                case 87654007:
307
 
                        _svg.setTagName("polygon");
308
 
                        break;
309
 
                case 87654101:
310
 
                        _svg.setTagName("text");
311
 
                        break;
312
 
                case 87654102:
313
 
                        _svg.setTagName("image");
314
 
                        break;
315
 
                case 87654201:
316
 
                        _svg.setTagName("g");
317
 
                        break;
318
 
        }
319
 
        return _svg;
320
 
};
321
 
 
322
 
QList<QString> WbItem::parseSvg(QDomElement &_svg, bool emitChanges) {
323
 
        QList<QString> changed;
324
 
        // First process changes to existing elements
325
 
        foreach(QString a, attributes.keys()) {
326
 
                if(attributes[a] != _svg.attribute(a)) {
327
 
                        if(a.startsWith("stroke") || a == "opacity")
328
 
                                changed.append("pen");
329
 
                        else
330
 
                                changed.append(a);
331
 
                }
332
 
                if(_svg.hasAttribute(a)) {
333
 
                        if(attributes[a] != _svg.attribute(a) && emitChanges)
334
 
                                emit attributeChanged(id(), a, _svg.attribute(a), attributes[a]);
335
 
                        attributes[a] = _svg.attribute(a);
336
 
                        _svg.removeAttribute(a);
337
 
                } else {
338
 
                        if(emitChanges)
339
 
                                emit attributeChanged(id(), a, QString(), attributes[a]);
340
 
                        attributes.remove(a);
341
 
                }
342
 
        }
343
 
        QDomNode a;
344
 
        for(uint i = 0; i < _svg.attributes().length(); i++) {
345
 
                a = _svg.attributes().item(i).cloneNode();
346
 
                if(emitChanges)
347
 
                        emit attributeChanged(id(), a.nodeName(), a.nodeValue(), QString());
348
 
                attributes[a.nodeName()] = a.nodeValue();
349
 
                if(a.nodeName().startsWith("stroke") || a.nodeName() == "opacity")
350
 
                        changed.append("pen");
351
 
                else
352
 
                        changed.append(a.nodeName());
353
 
        }
354
 
 
355
 
        if(graphicsItem()) {
356
 
                // 'x' & 'y' & 'cx' & 'cy'
357
 
                if(changed.contains("x") || changed.contains("y") || changed.contains("cx") || changed.contains("cy")) {
358
 
                        bool xOk, yOk;
359
 
                        qreal xPos, yPos;
360
 
                        if(changed.contains("x") || changed.contains("y")) {
361
 
                                xPos = attributes["x"].toDouble(&xOk);
362
 
                                yPos = attributes["y"].toDouble(&yOk);
363
 
                        } else {
364
 
                                xPos = attributes["cx"].toDouble(&xOk);
365
 
                                yPos = attributes["cy"].toDouble(&yOk);
366
 
                        }
367
 
                        if(xOk && yOk)
368
 
                                graphicsItem()->setPos(QPointF(xPos, yPos));
369
 
//                              graphicsItem()->setPos(graphicsItem()->mapToParent(graphicsItem()->mapFromScene(QPointF(xPos, yPos))));
370
 
                }
371
 
 
372
 
                // 'fill'
373
 
                if(changed.contains("fill")) {
374
 
                        QBrush brush;
375
 
                        if(!attributes["fill"].isEmpty())
376
 
                                brush = QBrush(constructColor(attributes["fill"], attributes["fill-opacity"]));
377
 
                        QAbstractGraphicsShapeItem* s = qgraphicsitem_cast<QAbstractGraphicsShapeItem*>(graphicsItem());
378
 
                        if(s) {
379
 
                                // Only set pens for items that implement it
380
 
                                s->setBrush(brush);
381
 
                        }
382
 
                }
383
 
 
384
 
                // 'stroke' & stroke-dasharray & stroke-dashoffset & stroke-dashoffset & stroke-linecap & stroke-linejoin & stroke-miterlimit & stroke-opacity &
385
 
                if(changed.contains("pen")) {
386
 
                        QPen pen;
387
 
                        pen = parseQPen(attributes["stroke"],
388
 
                                        attributes["stroke-dasharray"],
389
 
                                        attributes["stroke-dashoffset"],
390
 
                                        attributes["stroke-linecap"],
391
 
                                        attributes["stroke-linejoin"],
392
 
                                        attributes["stroke-miterlimit"],
393
 
                                        attributes["stroke-opacity"],
394
 
                                        attributes["opacity"],
395
 
                                        attributes["stroke-width"]);
396
 
                        QAbstractGraphicsShapeItem* s = qgraphicsitem_cast<QAbstractGraphicsShapeItem*>(graphicsItem());
397
 
                        if(s) {
398
 
                                // Only set pens for items that implement it
399
 
                                s->setPen(pen);
400
 
                        }/* else if(typerange == 101) {
401
 
                                QGraphicsTextItem* s = dynamic_cast<QGraphicsTextItem*>(graphicsItem());
402
 
                                s->setPen(pen);
403
 
                        }*/
404
 
                }
405
 
 
406
 
                if(changed.contains("transform"))
407
 
                        graphicsItem()->setMatrix(parseTransformationMatrix(attributes["transform"]));
408
 
 
409
 
                graphicsItem()->update();
410
 
        }
411
 
        return changed;
412
 
}
413
 
 
414
 
void WbItem::regenerateTransform() {
415
 
        if(!graphicsItem())
416
 
                return;
417
 
        QMatrix m = graphicsItem()->matrix();
418
 
        QString old = attributes["transform"];
419
 
        if(m.isIdentity())
420
 
                attributes["transform"] = QString();
421
 
        else
422
 
                attributes["transform"] = QString("matrix(%1 %2 %3 %4 %5 %6)").arg(m.m11()).arg(m.m12()).arg(m.m21()).arg(m.m22()).arg(m.dx()).arg(m.dy());
423
 
        if(attributes["transform"] != old)
424
 
                emit attributeChanged(id(), "transform", attributes["transform"], old);
425
 
}
426
 
 
427
 
QPointF WbItem::center() {
428
 
        if(graphicsItem()) {
429
 
                // Determine the center of the item in item coordinates before transformation
430
 
                QRectF r = graphicsItem()->boundingRect();
431
 
                QPointF c(r.x() + r.width()/2, r.y() + r.height()/2);
432
 
//              qDebug() << QString("center: %1 + %2    %3 + %4").arg(r.x()).arg(r.width()/2).arg(r.y()).arg(r.height()/2);
433
 
                // return the center with transformation applied
434
 
                return graphicsItem()->matrix().map(c);
435
 
        }
436
 
        return QPointF();
437
 
}
438
 
 
439
 
void WbItem::handleMouseMoveEvent(QGraphicsSceneMouseEvent * event) {
440
 
        event->accept();
441
 
        if(graphicsItem() && graphicsItem()->isSelected()) {
442
 
                if(event->modifiers() == Qt::KeyboardModifiers(Qt::ControlModifier)) {
443
 
                        // Ctrl: Translate
444
 
                        // Translate each selected item
445
 
                        WbScene* wbscene = qobject_cast<WbScene*>(graphicsItem()->scene());
446
 
                        if(wbscene) {
447
 
                                foreach(QGraphicsItem* graphicsitem, graphicsItem()->scene()->selectedItems()) {
448
 
                                        if (!graphicsitem->parentItem() || !graphicsitem->parentItem()->isSelected()) {
449
 
                                                QPointF d = graphicsitem->mapFromScene(event->scenePos()) - graphicsitem->mapFromScene(event->lastScenePos());
450
 
                                                graphicsitem->translate(d.x(), d.y());
451
 
                                                // Regenerate the SVG transformation matrix later
452
 
                                                wbscene->queueTransformationChange(wbscene->findWbItem(graphicsitem));
453
 
                                        }
454
 
                                }
455
 
                        }
456
 
                } else if(event->modifiers() == Qt::KeyboardModifiers(Qt::ControlModifier + Qt::AltModifier)) {
457
 
                        // Ctrl + Alt: Rotate
458
 
                        // get center coordinates in item coordinates
459
 
                        QPointF c = center();
460
 
                        QMatrix translation, delta;
461
 
                        // translates the the item's center to the origin of the item coordinates
462
 
                        translation.translate(-c.x(), -c.y());
463
 
                        // Rotate. Determine the direction relative to the center
464
 
                        // Divide the sum by two to reduce the "speed" of rotation
465
 
                        QPointF difference = event->scenePos() - event->lastScenePos();
466
 
        //              qDebug() << QString("d: %1 %2 = %3 %4 + %5 %6").arg(difference.x()).arg(difference.y()).arg(event->scenePos().x()).arg(event->scenePos().y()).arg(event->lastScenePos().x()).arg(event->lastScenePos().y());
467
 
                        QPointF p = event->scenePos();
468
 
                        QPointF sceneCenter = graphicsItem()->mapToScene(c);
469
 
                        if(p.x() >= sceneCenter.x() && p.y() >= sceneCenter.y()) {
470
 
                                delta.rotate((-difference.x() + difference.y()) / 2);
471
 
                        } else if(p.x() < sceneCenter.x() && p.y() >= sceneCenter.y()) {
472
 
                                delta.rotate((-difference.x() - difference.y()) / 2);
473
 
                        } else if(p.x() < sceneCenter.x() && p.y() < sceneCenter.y()) {
474
 
                                delta.rotate((difference.x() - difference.y()) / 2);
475
 
                        } else if(p.x() >= sceneCenter.x() && p.y() < sceneCenter.y()) {
476
 
                                delta.rotate((difference.x() + difference.y()) / 2);
477
 
                        }
478
 
                        // set the matrix
479
 
                        graphicsItem()->setMatrix(graphicsItem()->matrix() * translation * delta * translation.inverted());
480
 
                        // Regenerate the SVG transformation matrix later
481
 
                        WbScene* wbscene = qobject_cast<WbScene*>(graphicsItem()->scene());
482
 
                        if(wbscene)
483
 
                                wbscene->queueTransformationChange(this);
484
 
                } else if(event->modifiers() == Qt::KeyboardModifiers(Qt::ControlModifier + Qt::ShiftModifier)) {
485
 
                        // Ctrl + Shift: Scale
486
 
                        // get center coordinates in item coordinates
487
 
                        QPointF c = center();
488
 
                        QMatrix translation, delta;
489
 
                        // translates the the item's center to the origin of the item coordinates
490
 
                        translation.translate(-c.x(), -c.y());
491
 
                        // Scale.
492
 
                        // Moving mouse up enlarges, down shrinks, y axis.
493
 
                        // Moving mouse right enlarges, left shrinks, x axis.
494
 
                        QPointF difference = event->scenePos() - event->lastScenePos();
495
 
                        // Note: the y axis points downwards in scene coordinates
496
 
                        delta.scale(1 + difference.x()/50, 1 - difference.y()/50);
497
 
                        // set the matrix
498
 
                        graphicsItem()->setMatrix(graphicsItem()->matrix() * translation * delta * translation.inverted());
499
 
                        // Regenerate the SVG transformation matrix later
500
 
                        WbScene* wbscene = qobject_cast<WbScene*>(graphicsItem()->scene());
501
 
                        if(wbscene)
502
 
                                wbscene->queueTransformationChange(this);
503
 
                }
504
 
        }
505
 
}
506
 
 
507
 
void WbItem::handleMouseReleaseEvent(QGraphicsSceneMouseEvent * event) {        
508
 
        WbScene * wbscene = qobject_cast<WbScene*>(graphicsItem()->scene());
509
 
        wbscene->regenerateTransformations();
510
 
        event->ignore();
511
 
}
512
 
 
513
 
/*
514
 
 *      WbUnknown
515
 
 */
516
 
 
517
 
WbUnknown::WbUnknown(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene *) : WbItem(id) {
518
 
        setParentWbItem(parent);
519
 
        setIndex(index);
520
 
        parseSvg(_svg);
521
 
}
522
 
 
523
 
QDomElement WbUnknown::svg() {
524
 
        return svgElement_.cloneNode().toElement();
525
 
}
526
 
 
527
 
QList<QString> WbUnknown::parseSvg(QDomElement &_svg, bool) {
528
 
        svgElement_ = _svg.cloneNode().toElement();
529
 
        return QList<QString>();
530
 
}
531
 
 
532
 
WbItem* WbUnknown::clone() {
533
 
        QDomElement _svg = svg();
534
 
        WbItem* cloned = new WbUnknown(_svg, id(), index(), parentWbItem(), 0);
535
 
        cloned->undos = undos;
536
 
        return cloned;
537
 
}
538
 
 
539
 
/*
540
 
 *      WbRoot
541
 
 */
542
 
 
543
 
WbRoot::WbRoot(QGraphicsScene* scene) : WbItem("root") {
544
 
        scene_ = scene;
545
 
}
546
 
 
547
 
QList<QString> WbRoot::parseSvg(QDomElement &_svg, bool emitChanges) {
548
 
        QList<QString> changed = WbItem::parseSvg(_svg, emitChanges);
549
 
        if(changed.contains("viewBox")) {
550
 
                QString::const_iterator itr = attributes["viewBox"].constBegin();
551
 
                QList<qreal> points = WbItem::parseNumbersList(itr);
552
 
                if(points.size() == 4)
553
 
                        scene_->setSceneRect(points.at(0), points.at(1), points.at(2), points.at(3));
554
 
        }
555
 
        return changed;
556
 
}
557
 
 
558
 
WbItem* WbRoot::clone() {
559
 
        WbItem* cloned = new WbRoot(scene_);
560
 
        QDomElement _svg = svg();
561
 
        cloned->parseSvg(_svg, false);
562
 
        cloned->undos = undos;
563
 
        return cloned;
564
 
}
565
 
 
566
 
/*
567
 
 *      WbPath
568
 
 */
569
 
 
570
 
WbPath::WbPath(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene * scene) : QGraphicsPathItem(0, scene), WbItem(id) {
571
 
        setParentWbItem(parent);
572
 
        setIndex(index);
573
 
        parseSvg(_svg);
574
 
        setFlag(QGraphicsItem::ItemIsSelectable);
575
 
        setFlag(QGraphicsItem::ItemIsMovable);
576
 
        setAcceptDrops(true);
577
 
}
578
 
 
579
 
QPainterPath WbPath::shape() const {
580
 
        QPainterPath qpath = path();
581
 
        qpath.lineTo(qpath.currentPosition() + QPointF(2, 0));
582
 
        qpath.lineTo(qpath.currentPosition() + QPointF(-2, 2));
583
 
        qpath.closeSubpath();
584
 
        qpath.lineTo(qpath.currentPosition() + QPointF(2, 0));
585
 
        qpath.lineTo(qpath.currentPosition() + QPointF(-2, 2));
586
 
        return qpath;
587
 
}
588
 
 
589
 
QList<QString> WbPath::parseSvg(QDomElement &_svg, bool emitChanges) {
590
 
        QList<QString> changed = WbItem::parseSvg(_svg, emitChanges);
591
 
        QPainterPath qpath;
592
 
        // 'd' && 'fill-rule'
593
 
        if(changed.contains("d")) {
594
 
                parsePathDataFast(attributes["d"], qpath);
595
 
        } else
596
 
                qpath = this->path();
597
 
        if(changed.contains("fill-rule")) {
598
 
                if (attributes["fill-rule"] == QLatin1String("nonzero"))
599
 
                        qpath.setFillRule(Qt::WindingFill);
600
 
                else
601
 
                        qpath.setFillRule(Qt::OddEvenFill);
602
 
        } else
603
 
                qpath.setFillRule(this->path().fillRule());
604
 
        setPath(qpath);
605
 
        return changed;
606
 
}
607
 
 
608
 
WbItem* WbPath::clone() {
609
 
        QDomElement _svg = svg();
610
 
        WbItem* cloned = new WbPath(_svg, id(), index(), parentWbItem(), 0);
611
 
        cloned->undos = undos;
612
 
        return cloned;
613
 
}
614
 
 
615
 
void WbPath::lineTo(const QPointF &newPoint) {
616
 
        QPainterPath qpath = path();
617
 
        qpath.lineTo(newPoint);
618
 
        setPath(qpath);
619
 
        QString old = attributes["d"];
620
 
        attributes["d"] += QString("L%1,%2").arg(newPoint.x()).arg(newPoint.y());
621
 
        emit attributeChanged(id(), "d", attributes["d"], old);
622
 
}
623
 
 
624
 
void WbPath::quadTo(const QPointF &controlPoint, const QPointF &newPoint) {
625
 
        QPainterPath qpath = path();
626
 
        qpath.quadTo(controlPoint, newPoint);
627
 
        setPath(qpath);
628
 
        QString old = attributes["d"];
629
 
        attributes["d"] += QString("Q%1,%2 %3,%4").arg(controlPoint.x()).arg(controlPoint.y()).arg(newPoint.x()).arg(newPoint.y());
630
 
        emit attributeChanged(id(), "d", attributes["d"], old);
631
 
}
632
 
 
633
 
void WbPath::contextMenuEvent (QGraphicsSceneContextMenuEvent * event) {
634
 
        constructContextMenu()->exec(event->screenPos());
635
 
        regenerateTransform();
636
 
}
637
 
 
638
 
void WbPath::mouseMoveEvent(QGraphicsSceneMouseEvent * event) {
639
 
        handleMouseMoveEvent(event);
640
 
        if(!event->isAccepted())
641
 
                QGraphicsPathItem::mouseMoveEvent(event);
642
 
}
643
 
 
644
 
void WbPath::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) {
645
 
        handleMouseReleaseEvent(event);
646
 
        if(!event->isAccepted())
647
 
                QGraphicsPathItem::mouseReleaseEvent(event);
648
 
}
649
 
 
650
 
/*
651
 
 *      WbEllipse
652
 
 */
653
 
 
654
 
WbEllipse::WbEllipse(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene * scene) :  QGraphicsEllipseItem(0, scene), WbItem(id) {
655
 
        setParentWbItem(parent);
656
 
        setIndex(index);
657
 
        parseSvg(_svg);
658
 
        setFlag(QGraphicsItem::ItemIsSelectable);
659
 
        setFlag(QGraphicsItem::ItemIsMovable);
660
 
        setAcceptDrops(true);
661
 
}
662
 
 
663
 
QList<QString> WbEllipse::parseSvg(QDomElement &_svg, bool emitChanges) {
664
 
        QList<QString> changed = WbItem::parseSvg(_svg, emitChanges);
665
 
        // 'rx' & 'ry'
666
 
        if(changed.contains("rx") || changed.contains("ry")) {
667
 
                bool okX, okY;
668
 
                qreal rx = attributes["rx"].toDouble(&okX);
669
 
                qreal ry = attributes["ry"].toDouble(&okY);
670
 
                // FIXME: I think it's an issue with Qt, but with very small value I sometime get when setRect()
671
 
                // QPainterPath::lineTo: Adding point where x or y is NaN, results are undefined
672
 
                // QPainterPath::cubicTo: Adding point where x or y is NaN, results are undefined
673
 
                // That's why i'm putting those minumum values in
674
 
                if(okX && okY) {
675
 
                        if(rx <= 1)
676
 
                                rx = 1;
677
 
                        if(ry <= 1)
678
 
                                ry = 1;
679
 
                        setRect(-rx, -ry, 2 * rx, 2 * ry);
680
 
                } else
681
 
                        setRect(0, 0, 2, 2);
682
 
        }
683
 
        return changed;
684
 
}
685
 
 
686
 
WbItem* WbEllipse::clone() {
687
 
        QDomElement _svg = svg();
688
 
        WbItem* cloned = new WbEllipse(_svg, id(), index(), parentWbItem(), 0);
689
 
        cloned->undos = undos;
690
 
        return cloned;
691
 
}
692
 
 
693
 
void WbEllipse::contextMenuEvent (QGraphicsSceneContextMenuEvent * event) {
694
 
        WbItemMenu* menu = constructContextMenu();
695
 
        menu->exec(event->screenPos());
696
 
        event->accept();
697
 
}
698
 
 
699
 
void WbEllipse::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
700
 
        handleMouseMoveEvent(event);
701
 
        if(!event->isAccepted())
702
 
                QGraphicsEllipseItem::mouseMoveEvent(event);
703
 
}
704
 
 
705
 
void WbEllipse::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
706
 
        handleMouseReleaseEvent(event);
707
 
        if(!event->isAccepted())
708
 
                QGraphicsEllipseItem::mouseReleaseEvent(event);
709
 
}
710
 
 
711
 
/*
712
 
 *      WbCircle
713
 
 */
714
 
 
715
 
WbCircle::WbCircle(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene * scene) :  WbEllipse(_svg, id, index, parent, scene) {
716
 
        QDomElement _svg_ = svg();
717
 
        attributes.remove("r");
718
 
        parseSvg(_svg_);
719
 
}
720
 
 
721
 
QList<QString> WbCircle::parseSvg(QDomElement &_svg, bool emitChanges) {
722
 
        QList<QString> changed = WbItem::parseSvg(_svg, emitChanges);
723
 
        // 'r'
724
 
        if(changed.contains("r")) {
725
 
                bool ok;
726
 
                qreal r = attributes["r"].toDouble(&ok);
727
 
                if(ok && r > 0)
728
 
                        setRect(-r, -r, 2 * r, 2 * r);
729
 
                else
730
 
                        setRect(0, 0, 0, 0);
731
 
        }
732
 
        return changed;
733
 
}
734
 
 
735
 
WbItem* WbCircle::clone() {
736
 
        QDomElement _svg = svg();
737
 
        WbItem* cloned = new WbCircle(_svg, id(), index(), parentWbItem(), 0);
738
 
        cloned->undos = undos;
739
 
        return cloned;
740
 
}
741
 
 
742
 
/*
743
 
 *      WbRectangle
744
 
 */
745
 
 
746
 
WbRectangle::WbRectangle(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene * scene) :  QGraphicsRectItem(0, scene), WbItem(id) {
747
 
        setParentWbItem(parent);
748
 
        setIndex(index);
749
 
        parseSvg(_svg);
750
 
        setFlag(QGraphicsItem::ItemIsSelectable);
751
 
        setFlag(QGraphicsItem::ItemIsMovable);
752
 
        setAcceptDrops(true);
753
 
}
754
 
 
755
 
QList<QString> WbRectangle::parseSvg(QDomElement &_svg, bool emitChanges) {
756
 
        QList<QString> changed = WbItem::parseSvg(_svg, emitChanges);
757
 
        // TODO: support rx and ry
758
 
        // 'width' & 'height'
759
 
        if(changed.contains("width") || changed.contains("height")) {
760
 
                bool okW, okH;
761
 
                qreal width = attributes["width"].toDouble(&okW);
762
 
                qreal height = attributes["height"].toDouble(&okH);
763
 
                if(okW && okH && width > 0 && height > 0)
764
 
                        setRect(-width/2, -height/2, width, height);
765
 
                else
766
 
                        setRect(0, 0, 0, 0);
767
 
        }
768
 
        return changed;
769
 
}
770
 
 
771
 
WbItem* WbRectangle::clone() {
772
 
        QDomElement _svg = svg();
773
 
        WbItem* cloned = new WbRectangle(_svg, id(), index(), parentWbItem(), 0);
774
 
        cloned->undos = undos;
775
 
        return cloned;
776
 
}
777
 
 
778
 
void WbRectangle::contextMenuEvent (QGraphicsSceneContextMenuEvent * event) {
779
 
        WbItemMenu* menu = constructContextMenu();
780
 
        menu->exec(event->screenPos());
781
 
        event->accept();
782
 
}
783
 
 
784
 
void WbRectangle::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
785
 
        handleMouseMoveEvent(event);
786
 
        if(!event->isAccepted())
787
 
                QGraphicsRectItem::mouseMoveEvent(event);
788
 
}
789
 
 
790
 
void WbRectangle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
791
 
        handleMouseReleaseEvent(event);
792
 
        if(!event->isAccepted())
793
 
                QGraphicsRectItem::mouseReleaseEvent(event);
794
 
}
795
 
 
796
 
/*
797
 
 *      WbLine
798
 
 */
799
 
 
800
 
WbLine::WbLine(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene * scene) : QGraphicsPathItem(0, scene), WbItem(id) {
801
 
        setParentWbItem(parent);
802
 
        setIndex(index);
803
 
        parseSvg(_svg);
804
 
        setFlag(QGraphicsItem::ItemIsSelectable);
805
 
        setFlag(QGraphicsItem::ItemIsMovable);
806
 
        setAcceptDrops(true);
807
 
}
808
 
 
809
 
QPainterPath WbLine::shape() const {
810
 
        QPainterPath qpath = path();
811
 
        qpath.lineTo(qpath.currentPosition() + QPointF(2, 0));
812
 
        qpath.lineTo(qpath.currentPosition() + QPointF(-2, 2));
813
 
        qpath.closeSubpath();
814
 
        qpath.lineTo(qpath.currentPosition() + QPointF(2, 0));
815
 
        qpath.lineTo(qpath.currentPosition() + QPointF(-2, 2));
816
 
        return qpath;
817
 
}
818
 
 
819
 
QList<QString> WbLine::parseSvg(QDomElement &_svg, bool emitChanges) {
820
 
        QList<QString> changed= WbItem::parseSvg(_svg, emitChanges);
821
 
        // 'x1' & 'y1' & 'x2' & 'y2'
822
 
        if(changed.contains("x1") || changed.contains("y1") || changed.contains("x2") || changed.contains("y2")) {
823
 
                bool okX1, okY1, okX2, okY2;
824
 
                qreal x1 = attributes["x1"].toDouble(&okX1);
825
 
                qreal y1 = attributes["y1"].toDouble(&okY1);
826
 
                qreal x2 = attributes["x2"].toDouble(&okX2);
827
 
                qreal y2 = attributes["y2"].toDouble(&okY2);
828
 
                if(okX1 && okY1 && okX2 && okY2) {
829
 
                        QPainterPath qpath(QPointF(x1, y1));
830
 
                        qpath.lineTo(QPointF(x2, y2));
831
 
                        setPath(qpath);
832
 
                } else
833
 
                        setPath(QPainterPath());
834
 
        }
835
 
        return changed;
836
 
}
837
 
 
838
 
WbItem* WbLine::clone() {
839
 
        QDomElement _svg = svg();
840
 
        WbItem* cloned = new WbLine(_svg, id(), index(), parentWbItem(), 0);
841
 
        cloned->undos = undos;
842
 
        return cloned;
843
 
}
844
 
 
845
 
void WbLine::contextMenuEvent (QGraphicsSceneContextMenuEvent * event) {
846
 
        constructContextMenu()->exec(event->screenPos());
847
 
        regenerateTransform();
848
 
}
849
 
 
850
 
void WbLine::mouseMoveEvent(QGraphicsSceneMouseEvent * event) {
851
 
        handleMouseMoveEvent(event);
852
 
        if(!event->isAccepted())
853
 
                QGraphicsPathItem::mouseMoveEvent(event);
854
 
}
855
 
 
856
 
void WbLine::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) {
857
 
        handleMouseReleaseEvent(event);
858
 
        if(!event->isAccepted())
859
 
                QGraphicsPathItem::mouseReleaseEvent(event);
860
 
}
861
 
 
862
 
/*
863
 
 *      WbPolyline
864
 
 */
865
 
 
866
 
WbPolyline::WbPolyline(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene * scene) : QGraphicsPathItem(0, scene), WbItem(id) {
867
 
        setParentWbItem(parent);
868
 
        setIndex(index);
869
 
        parseSvg(_svg);
870
 
        setFlag(QGraphicsItem::ItemIsSelectable);
871
 
        setFlag(QGraphicsItem::ItemIsMovable);
872
 
        setAcceptDrops(true);
873
 
}
874
 
 
875
 
QPainterPath WbPolyline::shape() const {
876
 
        QPainterPath qpath = path();
877
 
        qpath.lineTo(qpath.currentPosition() + QPointF(2, 0));
878
 
        qpath.lineTo(qpath.currentPosition() + QPointF(-2, 2));
879
 
        qpath.closeSubpath();
880
 
        qpath.lineTo(qpath.currentPosition() + QPointF(2, 0));
881
 
        qpath.lineTo(qpath.currentPosition() + QPointF(-2, 2));
882
 
        return qpath;
883
 
}
884
 
 
885
 
QList<QString> WbPolyline::parseSvg(QDomElement &_svg, bool emitChanges) {
886
 
        QList<QString> changed= WbItem::parseSvg(_svg, emitChanges);
887
 
        // 'points'
888
 
        if(changed.contains("points")) {
889
 
                QString::const_iterator itr = attributes["points"].constBegin();
890
 
                QList<qreal> points = WbItem::parseNumbersList(itr);
891
 
                if(points.size() > 1) {
892
 
                        QPainterPath qpath(QPointF(points.takeFirst(), points.takeFirst()));
893
 
                        while(points.size() > 1) {
894
 
                                qpath.lineTo(QPointF(points.takeFirst(), points.takeFirst()));
895
 
                        }
896
 
                        setPath(qpath);
897
 
                } else
898
 
                        setPath(QPainterPath());
899
 
        }
900
 
        return changed;
901
 
}
902
 
 
903
 
WbItem* WbPolyline::clone() {
904
 
        QDomElement _svg = svg();
905
 
        WbItem* cloned = new WbPolyline(_svg, id(), index(), parentWbItem(), 0);
906
 
        cloned->undos = undos;
907
 
        return cloned;
908
 
}
909
 
 
910
 
void WbPolyline::contextMenuEvent (QGraphicsSceneContextMenuEvent * event) {
911
 
        constructContextMenu()->exec(event->screenPos());
912
 
        regenerateTransform();
913
 
}
914
 
 
915
 
void WbPolyline::mouseMoveEvent(QGraphicsSceneMouseEvent * event) {
916
 
        handleMouseMoveEvent(event);
917
 
        if(!event->isAccepted())
918
 
                QGraphicsPathItem::mouseMoveEvent(event);
919
 
}
920
 
 
921
 
void WbPolyline::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) {
922
 
        handleMouseReleaseEvent(event);
923
 
        if(!event->isAccepted())
924
 
                QGraphicsPathItem::mouseReleaseEvent(event);
925
 
}
926
 
 
927
 
/*
928
 
 *      WbPolygon
929
 
 */
930
 
 
931
 
WbPolygon::WbPolygon(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene * scene) :  WbPolyline(_svg, id, index, parent, scene) {
932
 
        QDomElement _svg_ = svg();
933
 
        attributes.remove("points");
934
 
        parseSvg(_svg_);
935
 
}
936
 
 
937
 
QList<QString> WbPolygon::parseSvg(QDomElement &_svg, bool emitChanges) {
938
 
        QList<QString> changed = WbPolyline::parseSvg(_svg, emitChanges);
939
 
        // 'points'
940
 
        if(changed.contains("points")) {
941
 
                QPainterPath qpath = path();
942
 
                qpath.closeSubpath();
943
 
                setPath(qpath);
944
 
        }
945
 
        return changed;
946
 
}
947
 
 
948
 
WbItem* WbPolygon::clone() {
949
 
        QDomElement _svg = svg();
950
 
        WbItem* cloned = new WbCircle(_svg, id(), index(), parentWbItem(), 0);
951
 
        cloned->undos = undos;
952
 
        return cloned;
953
 
}
954
 
 
955
 
/*
956
 
 *      WbGraphicsTextItem
957
 
 */
958
 
 
959
 
WbGraphicsTextItem::WbGraphicsTextItem(WbText* wbtext, QGraphicsScene * scene) : QGraphicsTextItem(0, scene) {
960
 
        wbText_ = wbtext;
961
 
        setFlag(QGraphicsItem::ItemIsSelectable);
962
 
        setFlag(QGraphicsItem::ItemIsMovable);
963
 
        setTextInteractionFlags(Qt::TextInteractionFlags(Qt::NoTextInteraction));
964
 
        setAcceptDrops(true);
965
 
}
966
 
 
967
 
void WbGraphicsTextItem::contextMenuEvent (QGraphicsSceneContextMenuEvent * event) {
968
 
        if(hasFocus())
969
 
                QGraphicsTextItem::contextMenuEvent(event);
970
 
        else {
971
 
                WbItemMenu* menu = wbText_->constructContextMenu();
972
 
                // Add the default actions
973
 
                menu->addSeparator();
974
 
                QActionGroup* group = new QActionGroup(menu);
975
 
                IconAction* action = new IconAction(QObject::tr("Font..."), "psi/compact", QObject::tr("Font..."), 0, group);
976
 
                QObject::connect(action, SIGNAL(triggered()), wbText_, SLOT(setFont()));
977
 
                menu->addActionGroup(group);
978
 
        
979
 
                menu->exec(event->screenPos());
980
 
                event->accept();
981
 
        }
982
 
}
983
 
 
984
 
void WbGraphicsTextItem::focusOutEvent (QFocusEvent *event) {
985
 
        QGraphicsTextItem::focusOutEvent(event);
986
 
        wbText_->checkTextChanges();
987
 
        setTextInteractionFlags(Qt::TextInteractionFlags(Qt::NoTextInteraction));
988
 
//      setFlag(QGraphicsItem::ItemIsFocusable, false);
989
 
}
990
 
 
991
 
void WbGraphicsTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
992
 
        if(event->modifiers() == Qt::KeyboardModifiers(Qt::NoModifier)) {
993
 
                setTextInteractionFlags(Qt::TextInteractionFlags(Qt::TextEditorInteraction));
994
 
                setFlag(QGraphicsItem::ItemIsFocusable);
995
 
        }
996
 
        QGraphicsTextItem::mouseDoubleClickEvent(event);
997
 
}
998
 
 
999
 
void WbGraphicsTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
1000
 
        wbText_->handleMouseMoveEvent(event);
1001
 
        if(!event->isAccepted())
1002
 
                QGraphicsTextItem::mouseMoveEvent(event);
1003
 
}
1004
 
 
1005
 
void WbGraphicsTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
1006
 
        wbText_->handleMouseReleaseEvent(event);
1007
 
        if(!event->isAccepted())
1008
 
                QGraphicsTextItem::mouseReleaseEvent(event);
1009
 
}
1010
 
 
1011
 
/*
1012
 
 *      WbText
1013
 
 */
1014
 
 
1015
 
WbText::WbText(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene * scene) : WbItem(id) {
1016
 
        graphicsitem_ = new WbGraphicsTextItem(this, scene);
1017
 
        setParentWbItem(parent);
1018
 
        setIndex(index);
1019
 
        parseSvg(_svg);
1020
 
}
1021
 
 
1022
 
WbText::~WbText() {
1023
 
        graphicsitem_->deleteLater();
1024
 
}
1025
 
 
1026
 
QDomElement WbText::svg() {
1027
 
        QDomElement _svg = WbItem::svg();
1028
 
        QDomDocument d;
1029
 
        _svg.appendChild(d.createTextNode(text_));
1030
 
        return _svg;
1031
 
};
1032
 
 
1033
 
QList<QString> WbText::parseSvg(QDomElement &_svg, bool emitChanges) {
1034
 
        QList<QString> changed = WbItem::parseSvg(_svg, emitChanges);
1035
 
        QFont _font = graphicsitem_->font();
1036
 
        // 'font-family'
1037
 
        if(changed.contains("font-family"))
1038
 
                _font.setFamily(attributes["font-family"]);
1039
 
        // 'font-size'
1040
 
        if(changed.contains("font-size"))
1041
 
                _font.setPointSize(attributes["font-size"].toInt());
1042
 
        // 'font-style'
1043
 
        if(changed.contains("font-style")) {
1044
 
                if(attributes["font-style"] == "normal")
1045
 
                        _font.setStyle(QFont::StyleNormal);
1046
 
                else if(attributes["font-style"] == "italic")
1047
 
                        _font.setStyle(QFont::StyleItalic);
1048
 
                else if(attributes["font-style"] == "oblique")
1049
 
                        _font.setStyle(QFont::StyleOblique);
1050
 
        }
1051
 
        // 'font-weight'
1052
 
        if(changed.contains("font-weight"))
1053
 
                _font.setWeight(((attributes["font-size"].toInt() - 100) / 800) * 99);
1054
 
        if(graphicsitem_->font() != _font)
1055
 
                graphicsitem_->setFont(_font);
1056
 
        // text content
1057
 
        QString t = _svg.text();
1058
 
        if(text_ != t) {
1059
 
                if(emitChanges) {
1060
 
                        QDomDocument d;
1061
 
                        QDomElement oldSvg = d.createElement("e");
1062
 
                        oldSvg.appendChild(d.createTextNode(text_));
1063
 
                        emit contentChanged(id(), _svg.cloneNode().childNodes(), oldSvg.childNodes());
1064
 
                        graphicsitem_->adjustSize();
1065
 
                }
1066
 
                text_ = t;
1067
 
                graphicsitem_->setPlainText(t);
1068
 
        }
1069
 
 
1070
 
        return changed;
1071
 
}
1072
 
 
1073
 
WbItem* WbText::clone() {
1074
 
        QDomElement _svg = svg();
1075
 
        WbItem* cloned = new WbText(_svg, id(), index(), parentWbItem(), 0);
1076
 
        cloned->undos = undos;
1077
 
        return cloned;
1078
 
}
1079
 
 
1080
 
void WbText::checkTextChanges() {
1081
 
        if(graphicsitem_->toPlainText() != text_) {
1082
 
                QDomDocument d;
1083
 
                QDomElement _svg = d.createElement("e");
1084
 
                _svg.appendChild(d.createTextNode(graphicsitem_->toPlainText()));
1085
 
                QDomElement oldSvg = d.createElement("e");
1086
 
                oldSvg.appendChild(d.createTextNode(text_));
1087
 
                emit contentChanged(id(), _svg.cloneNode().childNodes(), oldSvg.childNodes());
1088
 
                text_ = graphicsitem_->toPlainText();
1089
 
                graphicsitem_->adjustSize();
1090
 
        }
1091
 
}
1092
 
 
1093
 
void WbText::setFont() {
1094
 
        bool ok;
1095
 
        QFont _font = QFontDialog::getFont(&ok, graphicsitem_->font());
1096
 
        if(ok) {
1097
 
                // Not supported features
1098
 
                _font.setUnderline(false);
1099
 
                _font.setOverline(false);
1100
 
                _font.setStrikeOut(false);
1101
 
                _font.setFixedPitch(false);
1102
 
                // end: Not supported features
1103
 
                if(_font != graphicsitem_->font()) {
1104
 
                        if(_font.family() != graphicsitem_->font().family())
1105
 
                                emit attributeChanged(id(), "font-family", _font.family(), graphicsitem_->font().family());
1106
 
                        if(_font.pointSize() != graphicsitem_->font().pointSize())
1107
 
                                emit attributeChanged(id(), "font-size", QString("%1").arg(_font.pointSize()), QString("%1").arg(graphicsitem_->font().pointSize()));
1108
 
                        if(_font.style() != graphicsitem_->font().style()) {
1109
 
                                QString oldStyle, newStyle;
1110
 
                                switch(graphicsitem_->font().style()) {
1111
 
                                        case QFont::StyleNormal:
1112
 
                                                oldStyle = "normal";
1113
 
                                                break;
1114
 
                                        case QFont::StyleItalic:
1115
 
                                                oldStyle = "italic";
1116
 
                                                break;
1117
 
                                        case QFont::StyleOblique:
1118
 
                                                oldStyle = "oblique";
1119
 
                                                break;
1120
 
                                }
1121
 
                                switch(_font.style()) {
1122
 
                                        case QFont::StyleNormal:
1123
 
                                                newStyle = "normal";
1124
 
                                                break;
1125
 
                                        case QFont::StyleItalic:
1126
 
                                                newStyle = "italic";
1127
 
                                                break;
1128
 
                                        case QFont::StyleOblique:
1129
 
                                                newStyle = "oblique";
1130
 
                                                break;
1131
 
                                }
1132
 
                                emit attributeChanged(id(), "font-style", newStyle, oldStyle);
1133
 
                        }
1134
 
                        if(_font.weight() != graphicsitem_->font().weight()) {
1135
 
                                int oldWeight = (graphicsitem_->font().weight() - (graphicsitem_->font().weight() % 10)) * 10;
1136
 
                                int newWeight = (_font.weight() - (_font.weight() % 10)) * 10;
1137
 
                                if(oldWeight < 100)
1138
 
                                        oldWeight = 100;
1139
 
                                if(newWeight < 100)
1140
 
                                        newWeight = 100;
1141
 
                                emit attributeChanged(id(), "font-weight", QString("%1").arg(newWeight), QString("%1").arg(oldWeight));
1142
 
                                _font.setWeight(((newWeight - 100) / 800) * 99);
1143
 
                        }
1144
 
                        graphicsitem_->setFont(_font);
1145
 
                }
1146
 
        }
1147
 
}
1148
 
 
1149
 
/*
1150
 
 *      WbImage
1151
 
 */
1152
 
 
1153
 
// WbImage::WbImage(const QString &id, qreal index, const QPointF &startPoint, const QString &parent, QGraphicsScene * scene) : QGraphicsPathItem(0, scene), WbItem(id) {
1154
 
//      setIndex(index);
1155
 
//      attributes["d"] = QString("M %1 %2").arg(startPoint.x()).arg(startPoint.y());
1156
 
//      setPath(QPainterPath(startPoint));
1157
 
//      setFlag(QGraphicsItem::ItemIsSelectable);
1158
 
//      setFlag(QGraphicsItem::ItemIsMovable);
1159
 
//      setAcceptDrops(true);
1160
 
// }
1161
 
 
1162
 
WbImage::WbImage(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene * scene) : QGraphicsPixmapItem(0, scene), WbItem(id) {
1163
 
        setParentWbItem(parent);
1164
 
        setIndex(index);
1165
 
        parseSvg(_svg);
1166
 
        setFlag(QGraphicsItem::ItemIsSelectable);
1167
 
        setFlag(QGraphicsItem::ItemIsMovable);
1168
 
        setAcceptDrops(true);
1169
 
}
1170
 
 
1171
 
QList<QString> WbImage::parseSvg(QDomElement &_svg, bool emitChanges) {
1172
 
        QList<QString> changed = WbItem::parseSvg(_svg, emitChanges);
1173
 
        if(changed.contains("xlink:href") || changed.contains("width") || changed.contains("height")) {
1174
 
                QString header = attributes["xlink:href"].left(23);
1175
 
                // we're looking for something like this "data:;image/png;base64,"
1176
 
                if(header.startsWith("data:")) {
1177
 
                        if(header.left(12).contains("image/")) {
1178
 
                                if(header.left(15).contains("png") || header.left(15).contains("jpg") || header.left(16).contains("jpeg") || header.left(15).contains("bmp") || header.left(15).contains("gif") || header.left(15).contains("pbm") || header.left(15).contains("pgm") || header.left(15).contains("ppm") || header.left(15).contains("xbm") || header.left(15).contains("xpm")) {
1179
 
                                        if(header.contains("base64,")) {
1180
 
//                                              qDebug() << "data: " << attributes["xlink:href"].mid(header.indexOf("base64,") + 7);
1181
 
                                                QCA::Base64 decoder(QCA::Decode);
1182
 
                                                decoder.setLineBreaksEnabled(true);
1183
 
                                                QImage image = QImage::fromData(decoder.stringToArray(attributes["xlink:href"].mid(header.indexOf("base64,") + 7)).toByteArray());
1184
 
                                                bool okW, okH;
1185
 
                                                int width = static_cast<int>(attributes["width"].toDouble(&okW));
1186
 
                                                int height = static_cast<int>(attributes["height"].toDouble(&okH));
1187
 
                                                // TODO: aspect ratio
1188
 
                                                if(okW && okH)
1189
 
                                                        image = image.scaled(QSize(width, height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1190
 
                                                setPixmap(QPixmap::fromImage(image));
1191
 
                                        }
1192
 
                                }
1193
 
                        }
1194
 
                }
1195
 
        }
1196
 
        return changed;
1197
 
}
1198
 
 
1199
 
WbItem* WbImage::clone() {
1200
 
        QDomElement _svg = svg();
1201
 
        WbItem* cloned = new WbImage(_svg, id(), index(), parentWbItem(), 0);
1202
 
        cloned->undos = undos;
1203
 
        return cloned;
1204
 
}
1205
 
 
1206
 
void WbImage::contextMenuEvent (QGraphicsSceneContextMenuEvent * event) {
1207
 
        constructContextMenu()->exec(event->screenPos());
1208
 
        regenerateTransform();
1209
 
}
1210
 
 
1211
 
void WbImage::mouseMoveEvent(QGraphicsSceneMouseEvent * event) {
1212
 
        handleMouseMoveEvent(event);
1213
 
        if(!event->isAccepted())
1214
 
                QGraphicsPixmapItem::mouseMoveEvent(event);
1215
 
}
1216
 
 
1217
 
void WbImage::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) {
1218
 
        handleMouseReleaseEvent(event);
1219
 
        if(!event->isAccepted())
1220
 
                QGraphicsPixmapItem::mouseReleaseEvent(event);
1221
 
}
1222
 
 
1223
 
/*
1224
 
 *      WbGroup
1225
 
 */
1226
 
 
1227
 
WbGroup::WbGroup(QDomElement &_svg, const QString &id, const qreal &index, const QString &parent, QGraphicsScene * scene) : QGraphicsItem(0, scene), WbItem(id) {
1228
 
        setParentWbItem(parent);
1229
 
        setIndex(index);
1230
 
        parseSvg(_svg);
1231
 
        setFlag(QGraphicsItem::ItemIsSelectable);
1232
 
        setFlag(QGraphicsItem::ItemIsMovable);
1233
 
        setAcceptDrops(true);
1234
 
        setHandlesChildEvents(true);
1235
 
}
1236
 
 
1237
 
WbItem* WbGroup::clone() {
1238
 
        QDomElement _svg = svg();
1239
 
        WbItem* cloned = new WbGroup(_svg, id(), index(), parentWbItem(), 0);
1240
 
        cloned->undos = undos;
1241
 
        return cloned;
1242
 
}
1243
 
 
1244
 
void WbGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) {
1245
 
        if (option->state & QStyle::State_Selected) {
1246
 
                painter->setBrush(Qt::NoBrush);
1247
 
                painter->drawRect(boundingRect_);
1248
 
        }
1249
 
}
1250
 
 
1251
 
QRectF WbGroup::boundingRect() const {
1252
 
        return boundingRect_;
1253
 
}
1254
 
 
1255
 
QVariant WbGroup::itemChange(GraphicsItemChange change, const QVariant &value) {
1256
 
        if(change == QGraphicsItem::ItemChildAddedChange) {
1257
 
                QGraphicsItem* child = qVariantValue<QGraphicsItem *>(value);
1258
 
                if(child) {
1259
 
                        if(QGraphicsItem::children().size() == 1)
1260
 
                                boundingRect_ = mapFromItem(child, child->boundingRect()).boundingRect();
1261
 
                        else
1262
 
                                addToBoundingRect(mapFromItem(child, child->boundingRect()).boundingRect());
1263
 
                }
1264
 
        } else if(change == QGraphicsItem::ItemChildRemovedChange) {
1265
 
                QGraphicsItem* child = qVariantValue<QGraphicsItem *>(value);
1266
 
                if(child) {
1267
 
                        QRectF itemrect = mapFromItem(child, child->boundingRect()).boundingRect();
1268
 
                        if(itemrect.x() == boundingRect_.x() || itemrect.y() == boundingRect_.y() || itemrect.right() == boundingRect_.right() || itemrect.bottom() == boundingRect_.bottom()) {
1269
 
                                // If the item was on one of the borders of the boundingRect_ recalculate it
1270
 
                                if(!QGraphicsItem::children().isEmpty()) {
1271
 
                                        boundingRect_ = QGraphicsItem::children().first()->boundingRect();
1272
 
                                        for(int i = 1; i < QGraphicsItem::children().size(); i++)
1273
 
                                                addToBoundingRect(QGraphicsItem::children().at(i)->boundingRect());
1274
 
                                } else
1275
 
                                        boundingRect_ = QRectF();
1276
 
                        }
1277
 
                }
1278
 
        }
1279
 
        return value;
1280
 
}
1281
 
 
1282
 
void WbGroup::contextMenuEvent (QGraphicsSceneContextMenuEvent * event) {
1283
 
        constructContextMenu()->exec(event->screenPos());
1284
 
        regenerateTransform();
1285
 
}
1286
 
 
1287
 
void WbGroup::mouseMoveEvent(QGraphicsSceneMouseEvent * event) {
1288
 
        handleMouseMoveEvent(event);
1289
 
        if(!event->isAccepted())
1290
 
                QGraphicsItem::mouseMoveEvent(event);
1291
 
}
1292
 
 
1293
 
void WbGroup::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) {
1294
 
        handleMouseReleaseEvent(event);
1295
 
        if(!event->isAccepted())
1296
 
                QGraphicsItem::mouseReleaseEvent(event);
1297
 
}
1298
 
 
1299
 
void WbGroup::addToBoundingRect(const QRectF &itemRect) {
1300
 
        if(itemRect.left() < boundingRect_.left())
1301
 
                boundingRect_.adjust(itemRect.left() - boundingRect_.left(), 0, 0, 0);
1302
 
        if(itemRect.top() < boundingRect_.top())
1303
 
                boundingRect_.adjust(0, itemRect.top() - boundingRect_.top(), 0, 0);
1304
 
        if(itemRect.right() > boundingRect_.right())
1305
 
                boundingRect_.adjust(0, 0, itemRect.right() - boundingRect_.right(), 0);
1306
 
        if(itemRect.bottom() > boundingRect_.bottom())
1307
 
                boundingRect_.adjust(0, 0, 0, itemRect.bottom() - boundingRect_.bottom());
1308
 
}
1309
 
 
1310
 
/*
1311
 
 * Parsing
1312
 
 ******************/
1313
 
 
1314
 
/*
1315
 
 * Many of he following methods are copied and/or adapted from
1316
 
 * the Qt Svg module's file called qsvghandler.cpp.
1317
 
 * The original header is shown below:
1318
 
 */
1319
 
 
1320
 
/****************************************************************************
1321
 
**
1322
 
** Copyright (C) 1992-2006 Trolltech AS. All rights reserved.
1323
 
**
1324
 
** This file is part of the QtSVG module of the Qt Toolkit.
1325
 
**
1326
 
** This file may be used under the terms of the GNU General Public
1327
 
** License version 2.0 as published by the Free Software Foundation
1328
 
** and appearing in the file LICENSE.GPL included in the packaging of
1329
 
** this file.  Please review the following information to ensure GNU
1330
 
** General Public Licensing requirements will be met:
1331
 
** http://www.trolltech.com/products/qt/opensource.html
1332
 
**
1333
 
** If you are unsure which license is appropriate for your use, please
1334
 
** review the following information:
1335
 
** http://www.trolltech.com/products/qt/licensing.html or contact the
1336
 
** sales department at sales@trolltech.com.
1337
 
**
1338
 
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
1339
 
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1340
 
**
1341
 
****************************************************************************/
1342
 
 
1343
 
// WbItem::WbItem(const QDomElement &svg, QObject * parent, QGraphicsScene * scene) : QGraphicsItem(parent, scene) {
1344
 
// 
1345
 
// }
1346
 
 
1347
 
/*
1348
 
 * Parsing: General
1349
 
 */
1350
 
 
1351
 
// QString WbItem::xmlSimplify(const QString &str)
1352
 
// {
1353
 
//       QString dummy = str;
1354
 
//       dummy.remove('\n');
1355
 
//       if (dummy.trimmed().isEmpty())
1356
 
//               return QString();
1357
 
//       QString temp;
1358
 
//       QString::const_iterator itr = dummy.constBegin();
1359
 
//       bool wasSpace = false;
1360
 
//       for (;itr != dummy.constEnd(); ++itr) {
1361
 
//               if ((*itr).isSpace()) {
1362
 
//                       if (wasSpace || !(*itr).isPrint()) {
1363
 
//                               continue;
1364
 
//                       }
1365
 
//                       temp += *itr;
1366
 
//                       wasSpace = true;
1367
 
//               } else {
1368
 
//                       temp += *itr;
1369
 
//                       wasSpace = false;
1370
 
//               }
1371
 
//       }
1372
 
//       return temp;
1373
 
// }
1374
 
 
1375
 
QList<qreal> WbItem::parseNumbersList(QString::const_iterator &itr)
1376
 
{
1377
 
        QList<qreal> points;
1378
 
        QString temp;
1379
 
        while ((*itr).isSpace())
1380
 
                ++itr;
1381
 
        while ((*itr).isNumber() ||
1382
 
                   (*itr) == '-' || (*itr) == '+' || (*itr) == '.') {
1383
 
                temp = QString();
1384
 
 
1385
 
                if ((*itr) == '-')
1386
 
                        temp += *itr++;
1387
 
                else if ((*itr) == '+')
1388
 
                        temp += *itr++;
1389
 
                while ((*itr).isDigit())
1390
 
                        temp += *itr++;
1391
 
                if ((*itr) == '.')
1392
 
                        temp += *itr++;
1393
 
                while ((*itr).isDigit())
1394
 
                        temp += *itr++;
1395
 
                if (( *itr) == 'e') {
1396
 
                        temp += *itr++;
1397
 
                        if ((*itr) == '-' ||
1398
 
                                (*itr) == '+')
1399
 
                                temp += *itr++;
1400
 
                }
1401
 
                while ((*itr).isDigit())
1402
 
                        temp += *itr++;
1403
 
                while ((*itr).isSpace())
1404
 
                        ++itr;
1405
 
                if ((*itr) == ',')
1406
 
                        ++itr;
1407
 
                points.append(temp.toDouble());
1408
 
                //eat the rest of space
1409
 
                while ((*itr).isSpace())
1410
 
                        ++itr;
1411
 
        }
1412
 
 
1413
 
        return points;
1414
 
}
1415
 
 
1416
 
QList<qreal> WbItem::parsePercentageList(QString::const_iterator &itr)
1417
 
{
1418
 
        QList<qreal> points;
1419
 
        QString temp;
1420
 
        while ((*itr).isSpace())
1421
 
                ++itr;
1422
 
        while ((*itr).isNumber() ||
1423
 
                   (*itr) == '-' || (*itr) == '+') {
1424
 
                temp = QString();
1425
 
 
1426
 
                if ((*itr) == '-')
1427
 
                        temp += *itr++;
1428
 
                else if ((*itr) == '+')
1429
 
                        temp += *itr++;
1430
 
                while ((*itr).isDigit())
1431
 
                        temp += *itr++;
1432
 
                if ((*itr) == '.')
1433
 
                        temp += *itr++;
1434
 
                while ((*itr).isDigit())
1435
 
                        temp += *itr++;
1436
 
                if (( *itr) == '%') {
1437
 
                        itr++;
1438
 
                }
1439
 
                while ((*itr).isSpace())
1440
 
                        ++itr;
1441
 
                if ((*itr) == ',')
1442
 
                        ++itr;
1443
 
                points.append(temp.toDouble());
1444
 
                //eat the rest of space
1445
 
                while ((*itr).isSpace())
1446
 
                        ++itr;
1447
 
        }
1448
 
 
1449
 
        return points;
1450
 
}
1451
 
 
1452
 
//inline 
1453
 
bool WbItem::isUnreserved(const QChar &c, bool first_char)
1454
 
{
1455
 
        return (c.isLetterOrNumber() || c == QLatin1Char('_') || c == QLatin1Char(':')
1456
 
                        || (!first_char && (c == QLatin1Char('.') || c == QLatin1Char('-'))));
1457
 
 
1458
 
}
1459
 
 
1460
 
QString WbItem::idFromUrl(const QString &url)
1461
 
{
1462
 
        QString::const_iterator itr = url.constBegin();
1463
 
        while ((*itr).isSpace())
1464
 
                ++itr;
1465
 
        if ((*itr) == '(')
1466
 
                ++itr;
1467
 
        while ((*itr).isSpace())
1468
 
                ++itr;
1469
 
        if ((*itr) == '#')
1470
 
                ++itr;
1471
 
        QString id;
1472
 
 
1473
 
        if (isUnreserved(*itr, true)) {         
1474
 
                while (isUnreserved(*itr)) {
1475
 
                        id += *itr;
1476
 
                        ++itr;  
1477
 
                }
1478
 
        }
1479
 
 
1480
 
        return id;
1481
 
}
1482
 
 
1483
 
QMatrix WbItem::parseTransformationMatrix(const QString &value)
1484
 
{
1485
 
        if(value.isEmpty())
1486
 
                return QMatrix();
1487
 
        QMatrix matrix;
1488
 
        QString::const_iterator itr = value.constBegin();
1489
 
 
1490
 
        while (itr != value.constEnd()) {
1491
 
                if ((*itr) == 'm') {  //matrix
1492
 
                        QString temp("m");
1493
 
                        int remains = 6;
1494
 
                        while (remains--) {
1495
 
                                temp += *itr++;
1496
 
                        }
1497
 
 
1498
 
                        while ((*itr).isSpace())
1499
 
                                ++itr;
1500
 
                        ++itr;// '('
1501
 
                        QList<qreal> points = WbItem::parseNumbersList(itr);
1502
 
                        ++itr; // ')'
1503
 
 
1504
 
                        Q_ASSERT(points.count() == 6);
1505
 
                        matrix = matrix * QMatrix(points[0], points[1],
1506
 
                                                                          points[2], points[3],
1507
 
                                                                          points[4], points[5]);
1508
 
 
1509
 
                        //qDebug()<<"matrix is "<<temp;
1510
 
                } else if ((*itr) == 't') { //translate
1511
 
                        QString trans;
1512
 
                        int remains = 9;
1513
 
                        while (remains--) {
1514
 
                                trans += *itr++;
1515
 
                        }
1516
 
                        while ((*itr).isSpace())
1517
 
                                ++itr;
1518
 
                        ++itr;// '('
1519
 
                        QList<qreal> points = WbItem::parseNumbersList(itr);
1520
 
                        ++itr; // ')'
1521
 
 
1522
 
                        Q_ASSERT(points.count() == 2 ||
1523
 
                                         points.count() == 1);
1524
 
                        if (points.count() == 2)
1525
 
                                matrix.translate(points[0], points[1]);
1526
 
                        else
1527
 
                                matrix.translate(points[0], 0);
1528
 
 
1529
 
                        //qDebug()<<"trans is "<<points;
1530
 
                } else if ((*itr) == 'r') { //rotate
1531
 
                        QString rot;
1532
 
                        int remains = 6;
1533
 
                        while (remains--) {
1534
 
                                rot += *itr++;
1535
 
                        }
1536
 
                        while ((*itr).isSpace())
1537
 
                                ++itr;
1538
 
 
1539
 
                        ++itr;// '('
1540
 
                        QList<qreal> points = WbItem::parseNumbersList(itr);
1541
 
                        ++itr;// ')'
1542
 
                        Q_ASSERT(points.count() == 3 ||
1543
 
                                         points.count() == 1);
1544
 
                        if (points.count() == 3) {
1545
 
                                matrix.translate(points[1], points[2]);
1546
 
                                matrix.rotate(points[0]);
1547
 
                                matrix.translate(-points[1], -points[2]);
1548
 
                        }
1549
 
                        else
1550
 
                                matrix.rotate(points[0]);
1551
 
 
1552
 
                        //qDebug()<<"rot is "<<points;
1553
 
                } else if ((*itr) == 's') { //scale | skewX | skewY
1554
 
                        QString temp;
1555
 
                        int remains = 5;
1556
 
                        while (remains--) {
1557
 
                                temp += *itr++;
1558
 
                        }
1559
 
                        while ((*itr).isSpace())
1560
 
                                ++itr;
1561
 
 
1562
 
                        ++itr;// '('
1563
 
                        QList<qreal> points = WbItem::parseNumbersList(itr);
1564
 
                        ++itr;// ')'
1565
 
                        Q_ASSERT(points.count() == 2 ||
1566
 
                                         points.count() == 1);
1567
 
                        if (temp == QLatin1String("scale")) {
1568
 
                                if (points.count() == 2) {
1569
 
                                        matrix.scale(points[0], points[1]);
1570
 
                                }
1571
 
                                else
1572
 
                                        matrix.scale(points[0], points[0]);
1573
 
                        } else if (temp == QLatin1String("skewX")) {
1574
 
                                const qreal deg2rad = qreal(0.017453292519943295769);
1575
 
                                matrix.shear(tan(points[0]*deg2rad), 0);
1576
 
                        } else if (temp == QLatin1String("skewY")) {
1577
 
                                const qreal deg2rad = qreal(0.017453292519943295769);
1578
 
                                matrix.shear(0, tan(points[0]*deg2rad));
1579
 
                        }
1580
 
                } else if ((*itr) == ' '  ||
1581
 
                                   (*itr) == '\t' ||
1582
 
                                   (*itr) == '\n') {
1583
 
                        ++itr;
1584
 
                }
1585
 
                if (itr != value.constEnd())
1586
 
                        ++itr;
1587
 
        }
1588
 
        return matrix;
1589
 
}
1590
 
 
1591
 
QPen WbItem::parseQPen(QString stroke, const QString &dashArray, const QString &dashOffset, const QString &linecap, const QString &linejoin, const QString &miterlimit, QString strokeopacity, QString opacity, const QString &width)
1592
 
{
1593
 
        // TODO: do something with 'dashOffset'
1594
 
        Q_UNUSED(dashOffset);
1595
 
 
1596
 
        QPen pen;
1597
 
 
1598
 
        if (!strokeopacity.isEmpty())
1599
 
                opacity = strokeopacity;
1600
 
 
1601
 
        if (!stroke.isEmpty() || !width.isEmpty()) {
1602
 
                if (stroke != QLatin1String("none")) {
1603
 
                        if (!stroke.isEmpty()) {
1604
 
                                if (stroke.startsWith("url")) {
1605
 
                                        // TODO: support stroke='url...'
1606
 
//                                       stroke = stroke.remove(0, 3);
1607
 
//                                       QString id = idFromUrl(stroke);
1608
 
//                                       QSvgStructureNode *group = 0;
1609
 
//                                       QSvgNode *dummy = node;
1610
 
//                                       while (dummy && (dummy->type() != QSvgNode::DOC  &&
1611
 
//                                                                        dummy->type() != QSvgNode::G  &&
1612
 
//                                                                        dummy->type() != QSvgNode::DEFS &&
1613
 
//                                                                        dummy->type() != QSvgNode::SWITCH)) {
1614
 
//                                               dummy = dummy->parent();
1615
 
//                                       }
1616
 
//                                       if (dummy)
1617
 
//                                               group = static_cast<QSvgStructureNode*>(dummy);
1618
 
//                                       if (group) {
1619
 
//                                               QSvgStyleProperty *style =
1620
 
//                                                       group->scopeStyle(id);
1621
 
//                                               if (style->type() == QSvgStyleProperty::GRADIENT) {
1622
 
//                                                       QBrush b(*((QSvgGradientStyle*)style)->qgradient());
1623
 
//                                                       pen.setBrush(b);
1624
 
//                                               } else if (style->type() == QSvgStyleProperty::SOLID_COLOR) {
1625
 
//                                                       pen.setColor(
1626
 
//                                                               ((QSvgSolidColorStyle*)style)->qcolor());
1627
 
//                                               }
1628
 
//                                       } else {
1629
 
//                                               qDebug()<<"QSvgHandler::parsePen no parent group?";
1630
 
//                                       }
1631
 
                                } else {
1632
 
                                        pen.setColor(constructColor(stroke, opacity));
1633
 
                                }
1634
 
                                //since we could inherit stroke="none"
1635
 
                                //we need to reset the style of our stroke to something
1636
 
                                pen.setStyle(Qt::SolidLine);
1637
 
                        }
1638
 
                        if (!width.isEmpty()) {
1639
 
// //                           QSvgHandler::LengthType lt;
1640
 
                                qreal widthF = parseLength(width);
1641
 
                                // TODO: support percentage widths
1642
 
                                if (!widthF) {
1643
 
                                        pen.setWidthF(1);
1644
 
//                                       return;
1645
 
                                }
1646
 
                                pen.setWidthF(widthF);
1647
 
                        }
1648
 
                        qreal penw = pen.widthF();
1649
 
 
1650
 
                        if (!linejoin.isEmpty()) {
1651
 
                                if (linejoin == "miter")
1652
 
                                        pen.setJoinStyle(Qt::MiterJoin);
1653
 
                                else if (linejoin == "round")
1654
 
                                        pen.setJoinStyle(Qt::RoundJoin);
1655
 
                                else if (linejoin == "bevel")
1656
 
                                        pen.setJoinStyle(Qt::BevelJoin);
1657
 
                        }
1658
 
                        if (!miterlimit.isEmpty()) {
1659
 
                                pen.setMiterLimit(miterlimit.toDouble()/2);
1660
 
                        }
1661
 
 
1662
 
                        if (!linecap.isEmpty()) {
1663
 
                                if (linecap == "butt")
1664
 
                                        pen.setCapStyle(Qt::FlatCap);
1665
 
                                else if (linecap == "round")
1666
 
                                        pen.setCapStyle(Qt::RoundCap);
1667
 
                                else if (linecap == "square")
1668
 
                                        pen.setCapStyle(Qt::SquareCap);
1669
 
                        }
1670
 
 
1671
 
                        if (!dashArray.isEmpty()) {
1672
 
                                QString::const_iterator itr = dashArray.constBegin();
1673
 
                                QList<qreal> dashes = parseNumbersList(itr);
1674
 
                                QVector<qreal> vec(dashes.size());
1675
 
 
1676
 
                                int i = 0;
1677
 
                                foreach(qreal dash, dashes) {
1678
 
                                        vec[i++] = dash/penw;
1679
 
                                }
1680
 
                                pen.setDashPattern(vec);
1681
 
                        }
1682
 
 
1683
 
                } else {
1684
 
                        pen.setStyle(Qt::NoPen);
1685
 
                }
1686
 
        } else {
1687
 
        // TODO: check what the actual defaults are
1688
 
                pen = QPen(QColor(Qt::black), 1, Qt::NoPen, Qt::FlatCap, Qt::MiterJoin);
1689
 
        }
1690
 
        return pen;
1691
 
}
1692
 
 
1693
 
QColor WbItem::constructColor(const QString &colorStr, const QString &opacity)
1694
 
{
1695
 
        QColor c = resolveColor(colorStr);
1696
 
        if (!opacity.isEmpty()) {
1697
 
                qreal op = opacity.toDouble();
1698
 
                if (op <= 1)
1699
 
                        op *= 255;
1700
 
                c.setAlpha(int(op));
1701
 
        }
1702
 
        return c;
1703
 
}
1704
 
 
1705
 
QColor WbItem::resolveColor(const QString &colorStr)
1706
 
{
1707
 
        QColor color;
1708
 
        static QHash<QString, QColor> colors;
1709
 
        QString colorStrTr = colorStr.trimmed();
1710
 
        if (colors.isEmpty()) {
1711
 
                colors.insert("black",   QColor(  0,   0,   0));
1712
 
                colors.insert("green",   QColor(  0, 128,   0));
1713
 
                colors.insert("silver",  QColor(192, 192, 192));
1714
 
                colors.insert("lime",   QColor(  0, 255,   0));
1715
 
                colors.insert("gray",   QColor(128, 128, 128));
1716
 
                colors.insert("olive",   QColor(128, 128,   0));
1717
 
                colors.insert("white",   QColor(255, 255, 255));
1718
 
                colors.insert("yellow",  QColor(255, 255,   0));
1719
 
                colors.insert("maroon",  QColor(128,   0,   0));
1720
 
                colors.insert("navy",   QColor(  0,   0, 128));
1721
 
                colors.insert("red",     QColor(255,   0,   0));
1722
 
                colors.insert("blue",   QColor(  0,   0, 255));
1723
 
                colors.insert("purple",  QColor(128,   0, 128));
1724
 
                colors.insert("teal",   QColor(  0, 128, 128));
1725
 
                colors.insert("fuchsia", QColor(255,   0, 255));
1726
 
                colors.insert("aqua",   QColor(  0, 255, 255));
1727
 
        }
1728
 
        if (colors.contains(colorStrTr)) {
1729
 
                color = colors[colorStrTr];
1730
 
        } else if (colorStr.startsWith("rgb(")) {
1731
 
                QString::const_iterator itr = colorStr.constBegin();
1732
 
                ++itr; ++itr; ++itr; ++itr;
1733
 
                QString::const_iterator itr_back = itr;
1734
 
                QList<qreal> compo = parseNumbersList(itr);
1735
 
                //1 means that it failed after reaching non-parsable
1736
 
                //character which is going to be "%"
1737
 
                if (compo.size() == 1) {
1738
 
                        itr = itr_back;
1739
 
                        compo = parsePercentageList(itr);
1740
 
                        compo[0] *= 2.55;
1741
 
                        compo[1] *= 2.55;
1742
 
                        compo[2] *= 2.55;
1743
 
                }
1744
 
 
1745
 
                color = QColor(int(compo[0]),
1746
 
                                           int(compo[1]),
1747
 
                                           int(compo[2]));
1748
 
        } else if (colorStr == QLatin1String("inherited") ||
1749
 
                           colorStr == QLatin1String("inherit"))  {
1750
 
                // TODO: handle inherited color
1751
 
                color = QColor(Qt::black);
1752
 
        } else if (colorStr == QLatin1String("currentColor")) {
1753
 
                //TODO: handle current Color
1754
 
                color = QColor(Qt::black);
1755
 
        }
1756
 
        return color;
1757
 
}
1758
 
 
1759
 
qreal WbItem::parseLength(const QString &str)
1760
 
{
1761
 
        QString numStr = str.trimmed();
1762
 
        qreal len = 0;
1763
 
 
1764
 
        if (numStr.endsWith("%")) {
1765
 
                numStr.chop(1);
1766
 
                len = numStr.toDouble();
1767
 
//              type = QSvgHandler::PERCENT;
1768
 
        } else if (numStr.endsWith("px")) {
1769
 
                numStr.chop(2);
1770
 
                len = numStr.toDouble();
1771
 
//              type = QSvgHandler::PX;
1772
 
        } else if (numStr.endsWith("pc")) {
1773
 
                numStr.chop(2);
1774
 
                len = numStr.toDouble();
1775
 
//              type = QSvgHandler::PC;
1776
 
        } else if (numStr.endsWith("pt")) {
1777
 
                numStr.chop(2);
1778
 
                len = numStr.toDouble();
1779
 
//              type = QSvgHandler::PT;
1780
 
        } else if (numStr.endsWith("mm")) {
1781
 
                numStr.chop(2);
1782
 
                len = numStr.toDouble();
1783
 
//              type = QSvgHandler::MM;
1784
 
        } else if (numStr.endsWith("cm")) {
1785
 
                numStr.chop(2);
1786
 
                len = numStr.toDouble();
1787
 
//              type = QSvgHandler::CM;
1788
 
        } else if (numStr.endsWith("in")) {
1789
 
                numStr.chop(2);
1790
 
                len = numStr.toDouble();
1791
 
//              type = QSvgHandler::IN;
1792
 
        } else {
1793
 
                len = numStr.toDouble();
1794
 
//              type = handler->defaultCoordinateSystem();
1795
 
                //type = QSvgHandler::OTHER;
1796
 
        }
1797
 
        //qDebug()<<"len is "<<len<<", from "<<numStr;
1798
 
        return len;
1799
 
}
1800
 
 
1801
 
/*!
1802
 
 *      Parsing: WbPath 
1803
 
 */
1804
 
 
1805
 
bool WbPath::parsePathDataFast(const QString &data, QPainterPath &path)
1806
 
{
1807
 
        QString::const_iterator itr = data.constBegin();
1808
 
        qreal x0 = 0, y0 = 0;                     // starting point
1809
 
        qreal x = 0, y = 0;                             // current point
1810
 
        char lastMode = 0;
1811
 
        QChar pathElem;
1812
 
        QPointF ctrlPt;
1813
 
 
1814
 
        while (itr != data.constEnd()) {
1815
 
                while ((*itr).isSpace())
1816
 
                        ++itr;
1817
 
                pathElem = *itr;
1818
 
                ++itr;
1819
 
                QList<qreal> arg = WbItem::parseNumbersList(itr);
1820
 
                if (pathElem == 'z' || pathElem == 'Z')
1821
 
                        arg.append(0);//dummy
1822
 
                while (!arg.isEmpty()) {
1823
 
                        qreal offsetX = x;              // correction offsets
1824
 
                        qreal offsetY = y;              // for relative commands
1825
 
                        switch (pathElem.toAscii()) {
1826
 
                        case 'm': {
1827
 
                                x = x0 = arg[0] + offsetX;
1828
 
                                y = y0 = arg[1] + offsetY;
1829
 
                                path.moveTo(x0, y0);
1830
 
                                arg.pop_front(); arg.pop_front();
1831
 
                        }
1832
 
                                break;
1833
 
                        case 'M': {
1834
 
                                x = x0 = arg[0];
1835
 
                                y = y0 = arg[1];
1836
 
                                path.moveTo(x0, y0);
1837
 
                                arg.pop_front(); arg.pop_front();
1838
 
                        }
1839
 
                                break;
1840
 
                        case 'z':
1841
 
                        case 'Z': {
1842
 
                                x = x0;
1843
 
                                y = y0;
1844
 
                                path.closeSubpath();
1845
 
                                arg.pop_front();//pop dummy
1846
 
                        }
1847
 
                                break;
1848
 
                        case 'l': {
1849
 
                                x = arg.front() + offsetX;
1850
 
                                arg.pop_front();
1851
 
                                y = arg.front() + offsetY;
1852
 
                                arg.pop_front();
1853
 
                                path.lineTo(x, y);
1854
 
 
1855
 
                        }
1856
 
                                break;
1857
 
                        case 'L': {
1858
 
                                x = arg.front(); arg.pop_front();
1859
 
                                y = arg.front(); arg.pop_front();
1860
 
                                path.lineTo(x, y);
1861
 
                        }
1862
 
                                break;
1863
 
                        case 'h': {
1864
 
                                x = arg.front() + offsetX; arg.pop_front();
1865
 
                                path.lineTo(x, y);
1866
 
                        }
1867
 
                                break;
1868
 
                        case 'H': {
1869
 
                                x = arg[0];
1870
 
                                path.lineTo(x, y);
1871
 
                                arg.pop_front();
1872
 
                        }
1873
 
                                break;
1874
 
                        case 'v': {
1875
 
                                y = arg[0] + offsetY;
1876
 
                                path.lineTo(x, y);
1877
 
                                arg.pop_front();
1878
 
                        }
1879
 
                                break;
1880
 
                        case 'V': {
1881
 
                                y = arg[0];
1882
 
                                path.lineTo(x, y);
1883
 
                                arg.pop_front();
1884
 
                        }
1885
 
                                break;
1886
 
                        case 'c': {
1887
 
                                QPointF c1(arg[0]+offsetX, arg[1]+offsetY);
1888
 
                                QPointF c2(arg[2]+offsetX, arg[3]+offsetY);
1889
 
                                QPointF e(arg[4]+offsetX, arg[5]+offsetY);
1890
 
                                path.cubicTo(c1, c2, e);
1891
 
                                ctrlPt = c2;
1892
 
                                x = e.x();
1893
 
                                y = e.y();
1894
 
                                arg.pop_front(); arg.pop_front();
1895
 
                                arg.pop_front(); arg.pop_front();
1896
 
                                arg.pop_front(); arg.pop_front();
1897
 
                                break;
1898
 
                        }
1899
 
                        case 'C': {
1900
 
                                QPointF c1(arg[0], arg[1]);
1901
 
                                QPointF c2(arg[2], arg[3]);
1902
 
                                QPointF e(arg[4], arg[5]);
1903
 
                                path.cubicTo(c1, c2, e);
1904
 
                                ctrlPt = c2;
1905
 
                                x = e.x();
1906
 
                                y = e.y();
1907
 
                                arg.pop_front(); arg.pop_front();
1908
 
                                arg.pop_front(); arg.pop_front();
1909
 
                                arg.pop_front(); arg.pop_front();
1910
 
                                break;
1911
 
                        }
1912
 
                        case 's': {
1913
 
                                QPointF c1;
1914
 
                                if (lastMode == 'c' || lastMode == 'C' ||
1915
 
                                        lastMode == 's' || lastMode == 'S')
1916
 
                                        c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
1917
 
                                else
1918
 
                                        c1 = QPointF(x, y);
1919
 
                                QPointF c2(arg[0]+offsetX, arg[1]+offsetY);
1920
 
                                QPointF e(arg[2]+offsetX, arg[3]+offsetY);
1921
 
                                path.cubicTo(c1, c2, e);
1922
 
                                ctrlPt = c2;
1923
 
                                x = e.x();
1924
 
                                y = e.y();
1925
 
                                arg.pop_front(); arg.pop_front();
1926
 
                                arg.pop_front(); arg.pop_front();
1927
 
                                break;
1928
 
                        }
1929
 
                        case 'S': {
1930
 
                                QPointF c1;
1931
 
                                if (lastMode == 'c' || lastMode == 'C' ||
1932
 
                                        lastMode == 's' || lastMode == 'S')
1933
 
                                        c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
1934
 
                                else
1935
 
                                        c1 = QPointF(x, y);
1936
 
                                QPointF c2(arg[0], arg[1]);
1937
 
                                QPointF e(arg[2], arg[3]);
1938
 
                                path.cubicTo(c1, c2, e);
1939
 
                                ctrlPt = c2;
1940
 
                                x = e.x();
1941
 
                                y = e.y();
1942
 
                                arg.pop_front(); arg.pop_front();
1943
 
                                arg.pop_front(); arg.pop_front();
1944
 
                                break;
1945
 
                        }
1946
 
                        case 'q': {
1947
 
                                QPointF c(arg[0]+offsetX, arg[1]+offsetY);
1948
 
                                QPointF e(arg[2]+offsetX, arg[3]+offsetY);
1949
 
                                path.quadTo(c, e);
1950
 
                                ctrlPt = c;
1951
 
                                x = e.x();
1952
 
                                y = e.y();
1953
 
                                arg.pop_front(); arg.pop_front();
1954
 
                                arg.pop_front(); arg.pop_front();
1955
 
                                break;
1956
 
                        }
1957
 
                        case 'Q': {
1958
 
                                QPointF c(arg[0], arg[1]);
1959
 
                                QPointF e(arg[2], arg[3]);
1960
 
                                path.quadTo(c, e);
1961
 
                                ctrlPt = c;
1962
 
                                x = e.x();
1963
 
                                y = e.y();
1964
 
                                arg.pop_front(); arg.pop_front();
1965
 
                                arg.pop_front(); arg.pop_front();
1966
 
                                break;
1967
 
                        }
1968
 
                        case 't': {
1969
 
                                QPointF e(arg[0]+offsetX, arg[1]+offsetY);
1970
 
                                QPointF c;
1971
 
                                if (lastMode == 'q' || lastMode == 'Q' ||
1972
 
                                        lastMode == 't' || lastMode == 'T')
1973
 
                                        c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
1974
 
                                else
1975
 
                                        c = QPointF(x, y);
1976
 
                                path.quadTo(c, e);
1977
 
                                ctrlPt = c;
1978
 
                                x = e.x();
1979
 
                                y = e.y();
1980
 
                                arg.pop_front(); arg.pop_front();
1981
 
                                break;
1982
 
                        }
1983
 
                        case 'T': {
1984
 
                                QPointF e(arg[0], arg[1]);
1985
 
                                QPointF c;
1986
 
                                if (lastMode == 'q' || lastMode == 'Q' ||
1987
 
                                        lastMode == 't' || lastMode == 'T')
1988
 
                                        c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
1989
 
                                else
1990
 
                                        c = QPointF(x, y);
1991
 
                                path.quadTo(c, e);
1992
 
                                ctrlPt = c;
1993
 
                                x = e.x();
1994
 
                                y = e.y();
1995
 
                                arg.pop_front(); arg.pop_front();
1996
 
                                break;
1997
 
                        }
1998
 
                        case 'a': {
1999
 
                                qreal rx = arg[0];
2000
 
                                qreal ry = arg[1];
2001
 
                                qreal xAxisRotation = arg[2];
2002
 
                                qreal largeArcFlag  = arg[3];
2003
 
                                qreal sweepFlag = arg[4];
2004
 
                                qreal ex = arg[5] + offsetX;
2005
 
                                qreal ey = arg[6] + offsetY;
2006
 
                                qreal curx = x;
2007
 
                                qreal cury = y;
2008
 
                                pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
2009
 
                                                int(sweepFlag), ex, ey, curx, cury);
2010
 
 
2011
 
                                x = ex;
2012
 
                                y = ey;
2013
 
 
2014
 
                                arg.pop_front(); arg.pop_front();
2015
 
                                arg.pop_front(); arg.pop_front();
2016
 
                                arg.pop_front(); arg.pop_front();
2017
 
                                arg.pop_front();
2018
 
                        }
2019
 
                                break;
2020
 
                        case 'A': {
2021
 
                                qreal rx = arg[0];
2022
 
                                qreal ry = arg[1];
2023
 
                                qreal xAxisRotation = arg[2];
2024
 
                                qreal largeArcFlag  = arg[3];
2025
 
                                qreal sweepFlag = arg[4];
2026
 
                                qreal ex = arg[5];
2027
 
                                qreal ey = arg[6];
2028
 
                                qreal curx = x;
2029
 
                                qreal cury = y;
2030
 
                                pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
2031
 
                                                int(sweepFlag), ex, ey, curx, cury);
2032
 
                                x = ex;
2033
 
                                y = ey;
2034
 
                                arg.pop_front(); arg.pop_front();
2035
 
                                arg.pop_front(); arg.pop_front();
2036
 
                                arg.pop_front(); arg.pop_front();
2037
 
                                arg.pop_front();
2038
 
                        }
2039
 
                                break;
2040
 
                        default:
2041
 
                                qDebug() << QString("path data is ") << pathElem;
2042
 
                                Q_ASSERT(!"invalid path data");
2043
 
                                break;
2044
 
                        }
2045
 
                        lastMode = pathElem.toAscii();
2046
 
                }
2047
 
        }
2048
 
        return true;
2049
 
}
2050
 
 
2051
 
void WbPath::pathArcSegment(QPainterPath &path, qreal xc, qreal yc, qreal th0, qreal th1, qreal rx, qreal ry, qreal xAxisRotation)
2052
 
{
2053
 
        qreal sinTh, cosTh;
2054
 
        qreal a00, a01, a10, a11;
2055
 
        qreal x1, y1, x2, y2, x3, y3;
2056
 
        qreal t;
2057
 
        qreal thHalf;
2058
 
 
2059
 
        sinTh = sin(xAxisRotation * (M_PI / 180.0));
2060
 
        cosTh = cos(xAxisRotation * (M_PI / 180.0));
2061
 
 
2062
 
        a00 =  cosTh * rx;
2063
 
        a01 = -sinTh * ry;
2064
 
        a10 =  sinTh * rx;
2065
 
        a11 =  cosTh * ry;
2066
 
 
2067
 
        thHalf = 0.5 * (th1 - th0);
2068
 
        t = (8.0 / 3.0) * sin(thHalf * 0.5) * sin(thHalf * 0.5) / sin(thHalf);
2069
 
        x1 = xc + cos(th0) - t * sin(th0);
2070
 
        y1 = yc + sin(th0) + t * cos(th0);
2071
 
        x3 = xc + cos(th1);
2072
 
        y3 = yc + sin(th1);
2073
 
        x2 = x3 + t * sin(th1);
2074
 
        y2 = y3 - t * cos(th1);
2075
 
 
2076
 
        path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
2077
 
                                 a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
2078
 
                                 a00 * x3 + a01 * y3, a10 * x3 + a11 * y3);
2079
 
}
2080
 
 
2081
 
// the arc handling code underneath is from XSVG (BSD license)
2082
 
/*
2083
 
 * Copyright  2002 USC/Information Sciences Institute
2084
 
 *
2085
 
 * Permission to use, copy, modify, distribute, and sell this software
2086
 
 * and its documentation for any purpose is hereby granted without
2087
 
 * fee, provided that the above copyright notice appear in all copies
2088
 
 * and that both that copyright notice and this permission notice
2089
 
 * appear in supporting documentation, and that the name of
2090
 
 * Information Sciences Institute not be used in advertising or
2091
 
 * publicity pertaining to distribution of the software without
2092
 
 * specific, written prior permission.  Information Sciences Institute
2093
 
 * makes no representations about the suitability of this software for
2094
 
 * any purpose.  It is provided "as is" without express or implied
2095
 
 * warranty.
2096
 
 *
2097
 
 * INFORMATION SCIENCES INSTITUTE DISCLAIMS ALL WARRANTIES WITH REGARD
2098
 
 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
2099
 
 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INFORMATION SCIENCES
2100
 
 * INSTITUTE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
2101
 
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
2102
 
 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2103
 
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2104
 
 * PERFORMANCE OF THIS SOFTWARE.
2105
 
 *
2106
 
 */
2107
 
void WbPath::pathArc(QPainterPath &path,
2108
 
                                        qreal   rx,
2109
 
                                        qreal   ry,
2110
 
                                        qreal   x_axis_rotation,
2111
 
                                        int             large_arc_flag,
2112
 
                                        int             sweep_flag,
2113
 
                                        qreal   x,
2114
 
                                        qreal   y,
2115
 
                                        qreal curx, qreal cury)
2116
 
{
2117
 
        qreal sin_th, cos_th;
2118
 
        qreal a00, a01, a10, a11;
2119
 
        qreal x0, y0, x1, y1, xc, yc;
2120
 
        qreal d, sfactor, sfactor_sq;
2121
 
        qreal th0, th1, th_arc;
2122
 
        int i, n_segs;
2123
 
        qreal dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check;
2124
 
 
2125
 
        rx = qAbs(rx);
2126
 
        ry = qAbs(ry);
2127
 
 
2128
 
        sin_th = sin(x_axis_rotation * (M_PI / 180.0));
2129
 
        cos_th = cos(x_axis_rotation * (M_PI / 180.0));
2130
 
 
2131
 
        dx = (curx - x) / 2.0;
2132
 
        dy = (cury - y) / 2.0;
2133
 
        dx1 =  cos_th * dx + sin_th * dy;
2134
 
        dy1 = -sin_th * dx + cos_th * dy;
2135
 
        Pr1 = rx * rx;
2136
 
        Pr2 = ry * ry;
2137
 
        Px = dx1 * dx1;
2138
 
        Py = dy1 * dy1;
2139
 
        /* Spec : check if radii are large enough */
2140
 
        check = Px / Pr1 + Py / Pr2;
2141
 
        if (check > 1) {
2142
 
                rx = rx * sqrt(check);
2143
 
                ry = ry * sqrt(check);
2144
 
        }
2145
 
 
2146
 
        a00 =  cos_th / rx;
2147
 
        a01 =  sin_th / rx;
2148
 
        a10 = -sin_th / ry;
2149
 
        a11 =  cos_th / ry;
2150
 
        x0 = a00 * curx + a01 * cury;
2151
 
        y0 = a10 * curx + a11 * cury;
2152
 
        x1 = a00 * x + a01 * y;
2153
 
        y1 = a10 * x + a11 * y;
2154
 
        /* (x0, y0) is current point in transformed coordinate space.
2155
 
           (x1, y1) is new point in transformed coordinate space.
2156
 
 
2157
 
           The arc fits a unit-radius circle in this space.
2158
 
        */
2159
 
        d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
2160
 
        sfactor_sq = 1.0 / d - 0.25;
2161
 
        if (sfactor_sq < 0) sfactor_sq = 0;
2162
 
        sfactor = sqrt(sfactor_sq);
2163
 
        if (sweep_flag == large_arc_flag) sfactor = -sfactor;
2164
 
        xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
2165
 
        yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
2166
 
        /* (xc, yc) is center of the circle. */
2167
 
 
2168
 
        th0 = atan2(y0 - yc, x0 - xc);
2169
 
        th1 = atan2(y1 - yc, x1 - xc);
2170
 
 
2171
 
        th_arc = th1 - th0;
2172
 
        if (th_arc < 0 && sweep_flag)
2173
 
                th_arc += 2 * M_PI;
2174
 
        else if (th_arc > 0 && !sweep_flag)
2175
 
                th_arc -= 2 * M_PI;
2176
 
 
2177
 
        n_segs = int(ceil(qAbs(th_arc / (M_PI * 0.5 + 0.001))));
2178
 
 
2179
 
        for (i = 0; i < n_segs; i++) {
2180
 
                pathArcSegment(path, xc, yc,
2181
 
                                           th0 + i * th_arc / n_segs,
2182
 
                                           th0 + (i + 1) * th_arc / n_segs,
2183
 
                                           rx, ry, x_axis_rotation);
2184
 
        }
2185
 
}