~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to src/wbscene.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
 
 * wbscene.cpp - an SVG whiteboard scene class
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 "wbscene.h"
22
 
 
23
 
WbScene::WbScene(const QString &session, const QString &ownJid, QObject * parent) : QGraphicsScene(parent) {
24
 
        importing = false;
25
 
        highestIndex_ = 0;
26
 
        highestId_ = 0;
27
 
        session_ = session;
28
 
        ownJid_ = ownJid;
29
 
 
30
 
        WbRoot* w = new WbRoot(this);
31
 
        QDomElement svg = w->svg();
32
 
        // Default values
33
 
        svg.setAttribute("viewBox", "0 0 600 600");
34
 
        svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
35
 
        svg.setAttribute("version", "1.1");
36
 
        svg.setAttribute("baseProfile", "tiny");
37
 
        w->parseSvg(svg, false);
38
 
        elements_.insert("root", w);
39
 
};
40
 
 
41
 
QString WbScene::session() {
42
 
        return session_;
43
 
}
44
 
 
45
 
const QString & WbScene::ownJid() const {
46
 
        return ownJid_;
47
 
}
48
 
 
49
 
bool WbScene::processWb(const QDomElement &wb) {
50
 
        QDomNodeList children = wb.childNodes();
51
 
        for(uint i=0; i < children.length(); i++) {
52
 
                if(children.item(i).nodeName() == "new")        
53
 
                        processNew(children.item(i).toElement());
54
 
                else if(children.item(i).nodeName() == "configure")
55
 
                        processConfigure(children.item(i).toElement());
56
 
                else if(children.item(i).nodeName() == "move")
57
 
                        processMove(children.item(i).toElement());
58
 
                else if(children.item(i).nodeName() == "remove")
59
 
                        processRemove(children.item(i).toElement());
60
 
        }
61
 
        return true;
62
 
}
63
 
 
64
 
WbItem* WbScene::findWbItem(const QString &id) const {
65
 
        if(elements_.contains(id))
66
 
                return elements_.value(id);
67
 
        else
68
 
                return 0;
69
 
}
70
 
 
71
 
WbItem* WbScene::findWbItem(QGraphicsItem* item) const {
72
 
        QHashIterator<QString, WbItem*> i(elements_);
73
 
        while (i.hasNext()) {
74
 
                i.next();
75
 
                if(i.value()->graphicsItem() == item)
76
 
                        return i.value();
77
 
        }
78
 
        return 0;
79
 
}
80
 
 
81
 
void WbScene::addWbItem(WbItem *item) {
82
 
        connect(item, SIGNAL(attributeChanged(QString, QString, QString, QString)), SLOT(queueAttributeEdit(QString, QString, QString, QString)));
83
 
        connect(item, SIGNAL(parentChanged(QString, QString, QString)), SLOT(queueParentEdit(QString, QString, QString)));
84
 
        connect(item, SIGNAL(contentChanged(QString, QDomNodeList, QDomNodeList)), SLOT(queueContentEdit(QString, QDomNodeList, QDomNodeList)));
85
 
        connect(item, SIGNAL(indexChanged(QString, qreal)), SLOT(queueMove(QString, qreal)));
86
 
 
87
 
        if(item->graphicsItem() && item->graphicsItem()->scene() != this)
88
 
                addItem(item->graphicsItem());
89
 
 
90
 
        elements_.insert(item->id(), item);
91
 
}
92
 
 
93
 
bool WbScene::removeElement(const QString &id, bool emitChanges)
94
 
{
95
 
        WbItem* wbitem = findWbItem(id);
96
 
        if(wbitem) {
97
 
                // Reparent children to root
98
 
                if(wbitem->graphicsItem()) {
99
 
                        QGraphicsLineItem lineitem(0, 0);
100
 
                        foreach(QGraphicsItem* c, wbitem->graphicsItem()->children()) {
101
 
                                // FIXME: should just be c->setParentItem(0);, this is a workaround for a qt bug
102
 
                                c->setParentItem(&lineitem);
103
 
                                c->setParentItem(0);
104
 
                        }
105
 
                        if(wbitem->graphicsItem()->scene())
106
 
                                wbitem->graphicsItem()->scene()->removeItem(wbitem->graphicsItem());
107
 
                }
108
 
                elements_.remove(wbitem->id());
109
 
                if(emitChanges)
110
 
                        queueRemove(wbitem->id());
111
 
                wbitem->deleteLater();
112
 
                return true;
113
 
        } else
114
 
                return false;
115
 
}
116
 
 
117
 
void WbScene::queueTransformationChange(WbItem* item) {
118
 
        if(item && !pendingTranformations_.contains(item))
119
 
                pendingTranformations_.append(QPointer<WbItem>(item));
120
 
}
121
 
 
122
 
void WbScene::regenerateTransformations() {
123
 
        foreach(QPointer<WbItem> item, pendingTranformations_) {
124
 
                if(item)
125
 
                        item->regenerateTransform();
126
 
        }
127
 
        pendingTranformations_.clear();
128
 
}
129
 
 
130
 
QDomElement WbScene::element(const QString &id) const {
131
 
        WbItem* i = findWbItem(id);
132
 
        if(i)
133
 
                return i->svg();
134
 
        else
135
 
                return QDomElement();
136
 
}
137
 
 
138
 
QList<WbItem*> WbScene::elements() const {
139
 
        QList<QString> elementKeys = elements_.keys();
140
 
        QList<QString> returnKeys;
141
 
        // Append nodes so that parents are listed before children
142
 
        int elementsAdded = 1;
143
 
        while(elementsAdded != 0 && !elementKeys.isEmpty()) {
144
 
                elementsAdded = 0;
145
 
                foreach(QString key, elementKeys) {
146
 
                        QString parent = elements_[key]->parentWbItem();
147
 
                        if(parent == "root" || returnKeys.contains(parent) || !elements_.contains(parent)) {
148
 
                                returnKeys.append(key);
149
 
                                elementsAdded++;
150
 
                        }
151
 
                        elementKeys.removeAll(key);
152
 
                }
153
 
        }
154
 
 
155
 
        QList<WbItem*> returnedElements;
156
 
        foreach(QString key, returnKeys) {
157
 
                WbItem* element = elements_[key]->clone();
158
 
                returnedElements.append(element);
159
 
        }
160
 
        return returnedElements;
161
 
}
162
 
 
163
 
void WbScene::setStrokeColor() {
164
 
        QColor newColor = QColorDialog::getColor();
165
 
        if(newColor.isValid()) {
166
 
                foreach(QGraphicsItem* selecteditem, selectedItems()) {
167
 
                        WbItem* selectedwbitem = findWbItem(selecteditem);
168
 
                        if(selectedwbitem)
169
 
                                selectedwbitem->setStrokeColor(newColor);
170
 
                }
171
 
        }
172
 
}
173
 
 
174
 
void WbScene::setFillColor() {
175
 
        QColor newColor = QColorDialog::getColor();
176
 
        if(newColor.isValid()) {
177
 
                foreach(QGraphicsItem* selecteditem, selectedItems()) {
178
 
                        WbItem* selectedwbitem = findWbItem(selecteditem);
179
 
                        if(selectedwbitem)
180
 
                                selectedwbitem->setFillColor(newColor);
181
 
                }
182
 
        }
183
 
}
184
 
 
185
 
void WbScene::setStrokeWidth(QAction* a) {
186
 
        foreach(QGraphicsItem* selecteditem, selectedItems()) {
187
 
                WbItem* selectedwbitem = findWbItem(selecteditem);
188
 
                if(selectedwbitem)
189
 
                        selectedwbitem->setStrokeWidth(a->data().toInt());
190
 
        }
191
 
}
192
 
 
193
 
void WbScene::bringForward(int n) {
194
 
        if(n == 0)
195
 
                return;
196
 
        // bring each selected item
197
 
        foreach(QGraphicsItem* selecteditem, selectedItems()) {
198
 
                if (!selecteditem->parentItem() || !selecteditem->parentItem()->isSelected()) {
199
 
                        WbItem* selectedwbitem = findWbItem(selecteditem);
200
 
                        if(selectedwbitem) {
201
 
                                QList<qreal> collidingindeces;
202
 
                                qreal selecteditemindex = selectedwbitem->index();
203
 
                                foreach(QGraphicsItem* collidingitem, selecteditem->collidingItems()) {
204
 
                                        if(!selectedItems().contains(collidingitem)) {
205
 
                                                WbItem* collidingwbitem =findWbItem(collidingitem);
206
 
                                                if(collidingwbitem) {
207
 
                                                        qreal collidingitemindex = collidingwbitem->index();
208
 
                                                        if(collidingitemindex > selecteditemindex) {
209
 
                                                                int i = 0;
210
 
                                                                while(i < collidingindeces.size() && collidingindeces.at(i) < collidingitemindex)
211
 
                                                                        i++;
212
 
                                                                collidingindeces.insert(i, collidingitemindex);
213
 
                                                        }
214
 
                                                }
215
 
                                        }
216
 
                                }
217
 
                                if(!collidingindeces.isEmpty()) {
218
 
                                        if(n < 0 || n >= collidingindeces.size())
219
 
                                                selectedwbitem->setIndex(collidingindeces.last() + 1.1, true);
220
 
                                        else
221
 
                                                selectedwbitem->setIndex(collidingindeces.at(n-1) + ((collidingindeces.at(n) - collidingindeces.at(n-1)) / 2), true);
222
 
                                }
223
 
                        }
224
 
                }
225
 
        }
226
 
}
227
 
 
228
 
void WbScene::bringToFront() {
229
 
        bringForward(-1);
230
 
}
231
 
 
232
 
void WbScene::sendBackwards(int n) {
233
 
        if(n == 0)
234
 
                return;
235
 
        // bring each selected item
236
 
        foreach(QGraphicsItem* selecteditem, selectedItems()) {
237
 
                if (!selecteditem->parentItem() || !selecteditem->parentItem()->isSelected()) {
238
 
                        WbItem* selectedwbitem = findWbItem(selecteditem);
239
 
                        if(selectedwbitem) {
240
 
                                QList<qreal> collidingindeces;
241
 
                                qreal selecteditemindex = selectedwbitem->index();
242
 
                                foreach(QGraphicsItem* collidingitem, selecteditem->collidingItems()) {
243
 
                                        if(!selectedItems().contains(collidingitem)) {
244
 
                                                WbItem* collidingwbitem = findWbItem(collidingitem);
245
 
                                                if(collidingwbitem) {
246
 
                                                        qreal collidingitemindex = collidingwbitem->index();
247
 
                                                        if(collidingitemindex < selecteditemindex) {
248
 
                                                                int i = 0;
249
 
                                                                while(i < collidingindeces.size() && collidingindeces.at(i) < collidingitemindex)
250
 
                                                                        i++;
251
 
                                                                collidingindeces.insert(i, collidingitemindex);
252
 
                                                        }
253
 
                                                }
254
 
                                        }
255
 
                                }
256
 
                                if(!collidingindeces.isEmpty()) {
257
 
                                        if(n < 0 || n >= collidingindeces.size())
258
 
                                                selectedwbitem->setIndex(collidingindeces.first() - 1.1, true);
259
 
                                        else
260
 
                                                selectedwbitem->setIndex(collidingindeces.at(collidingindeces.size() - n) - ((collidingindeces.at(collidingindeces.size() - n) - collidingindeces.at(collidingindeces.size() - n - 1)) / 2), true);
261
 
                                }
262
 
                        }
263
 
                }
264
 
        }
265
 
}
266
 
 
267
 
void WbScene::sendToBack() {
268
 
        sendBackwards(-1);
269
 
}
270
 
 
271
 
void WbScene::group() {
272
 
        if(selectedItems().size() > 1) {
273
 
                // Create the group
274
 
                QDomElement _svg = QDomDocument().createElement("g");
275
 
                WbGroup* group = new WbGroup(_svg, newId(), newIndex(), "root", this);
276
 
                addWbItem(group);
277
 
                // Send out the group item
278
 
                queueNew(group->id(), group->index(), group->svg());
279
 
                // Reparent each selected item
280
 
                foreach(QGraphicsItem* selecteditem, selectedItems()) {
281
 
                        WbItem* selectedwbitem = findWbItem(selecteditem);
282
 
                        if(selectedwbitem)
283
 
                                selectedwbitem->setParentWbItem(group->id(), true);
284
 
                }
285
 
                clearSelection();
286
 
                group->setSelected(true);
287
 
        }
288
 
}
289
 
 
290
 
void WbScene::ungroup() {
291
 
        foreach(QGraphicsItem* selecteditem, selectedItems()) {
292
 
                // 87654201 == WbGroup::type()
293
 
                if(selecteditem->type() == 87654201) {
294
 
                        WbItem* selectedwbitem = findWbItem(selecteditem);
295
 
                        if(selectedwbitem) {
296
 
                                // If the group has some transformation, the children should be accordingly transformed as the group is removed
297
 
                                if(!selecteditem->sceneMatrix().isIdentity() || selecteditem->pos() != QPointF()) {
298
 
                                        foreach(QGraphicsItem* child, selecteditem->children()) {
299
 
                                                child->setMatrix(child->sceneMatrix());
300
 
                                                WbItem* childwbitem = findWbItem(child);
301
 
                                                if(childwbitem)
302
 
                                                        childwbitem->regenerateTransform();
303
 
                                        }
304
 
                                }
305
 
                                queueRemove(selectedwbitem->id());
306
 
                                removeElement(selectedwbitem->id());
307
 
                        }
308
 
                }
309
 
                clearSelection();
310
 
        }
311
 
}
312
 
 
313
 
void WbScene::sendWb() {
314
 
        if(queue_.size() < 1)
315
 
                return;
316
 
        QDomDocument d;
317
 
        QDomElement wb = d.createElementNS("http://jabber.org/protocol/svgwb", "wb");
318
 
        wb.setAttribute("session", session_);
319
 
        WbItem* i;
320
 
        while(queue_.size() > 0) {
321
 
                // only append the version just before sending the element
322
 
                // and not when being queued to avoid unnecessary rejections
323
 
                if(queue_.first().type == Edit::AttributeEdit || queue_.first().type == Edit::ParentEdit || queue_.first().type == Edit::ContentEdit) {
324
 
                        i = findWbItem(queue_.first().target);
325
 
                        QDomElement configure = d.createElement("configure");
326
 
                        configure.setAttribute("target", queue_.first().target);
327
 
                        configure.setAttribute("version", ++i->version);
328
 
                        // Lump all consequtive configure edits witht the same target into one <configure/>.
329
 
                        while(queue_.first().type == Edit::AttributeEdit || queue_.first().type == Edit::ParentEdit || queue_.first().type == Edit::ContentEdit && queue_.first().target == configure.attribute("target")) {
330
 
                                // Store the EditUndo's for each edit
331
 
                                Edit edit = queue_.takeFirst();
332
 
                                i->undos.append(EditUndo(i->version, edit));
333
 
                                configure.appendChild(edit.xml);
334
 
                                if(queue_.isEmpty())
335
 
                                        break;
336
 
                        }
337
 
                        wb.appendChild(configure);
338
 
                } else
339
 
                        wb.appendChild(queue_.takeFirst().xml);
340
 
        }
341
 
        emit newWb(wb);
342
 
}
343
 
 
344
 
void WbScene::queueNew(const QString &id, const qreal &index, const QDomElement &svg) {
345
 
        QDomDocument d;
346
 
        QDomElement n = d.createElement("new");
347
 
        n.setAttribute("id", id);
348
 
        n.setAttribute("index", index);
349
 
        n.appendChild(svg.cloneNode());
350
 
        queue_.append(Edit(Edit::NewEdit, n));
351
 
 
352
 
        if(index > highestIndex_)
353
 
                highestIndex_ = static_cast<int>(index);
354
 
 
355
 
        //TODO: detect if more edits coming
356
 
        sendWb();
357
 
}
358
 
 
359
 
void WbScene::queueAttributeEdit(const QString &target, const QString &attribute, const QString &value, QString oldValue, int from, int to) {
360
 
        // Remove queued edits that have the same target and attribute if not a partial string replace
361
 
        if(from < 0 || to < from)
362
 
                removeFromQueue(target, attribute, oldValue);
363
 
        QDomDocument d;
364
 
        Edit e = Edit(Edit::AttributeEdit, target, d.createElement("attribute"), oldValue);
365
 
        e.xml.setAttribute("name", attribute);
366
 
        if(from > -1 && to >= from) {
367
 
                e.xml.setAttribute("from", from);
368
 
                e.xml.setAttribute("to", to);
369
 
        }
370
 
        e.xml.appendChild(d.createTextNode(value));
371
 
        queue_.append(e);
372
 
 
373
 
        //TODO: detect if more edits coming
374
 
        sendWb();
375
 
}
376
 
 
377
 
void WbScene::queueParentEdit(const QString &target, const QString &value, QString oldValue) {
378
 
        // Remove queued edits that have the same target and attribute
379
 
        removeFromQueue(target, oldValue);
380
 
        QDomDocument d;
381
 
        Edit e = Edit(Edit::ParentEdit, target, d.createElement("parent"), oldValue);
382
 
        e.xml.appendChild(d.createTextNode(value));
383
 
        queue_.append(e);
384
 
 
385
 
        //TODO: detect if more edits coming
386
 
        sendWb();
387
 
}
388
 
 
389
 
void WbScene::queueContentEdit(const QString &target, const QDomNodeList &value, QDomNodeList oldValue) {
390
 
        // Remove queued edits that have the same target and attribute
391
 
        removeFromQueue(target, oldValue);
392
 
        QDomDocument d;
393
 
        Edit e = Edit(target, d.createElement("content"), oldValue);
394
 
        for(uint j=0; j < value.length(); j++)
395
 
                e.xml.appendChild(value.at(j));
396
 
        queue_.append(e);
397
 
 
398
 
        //TODO: detect if more edits coming
399
 
        sendWb();
400
 
}
401
 
 
402
 
void WbScene::queueMove(const QString &target, qreal di) {
403
 
        QDomDocument d;
404
 
        QDomElement n = d.createElement("move");
405
 
        n.setAttribute("target", target);
406
 
        n.setAttribute("di", di);
407
 
        queue_.append(Edit(Edit::MoveEdit, n));
408
 
 
409
 
        //TODO: detect if more edits coming
410
 
        sendWb();
411
 
}
412
 
 
413
 
void WbScene::queueRemove(const QString &target) {
414
 
        QDomDocument d;
415
 
        QDomElement n = d.createElement("remove");
416
 
        n.setAttribute("target", target);
417
 
        queue_.append(Edit(Edit::RemoveEdit, n));
418
 
 
419
 
        //TODO: detect if more edits coming
420
 
        sendWb();       
421
 
}
422
 
 
423
 
bool WbScene::setElement(QDomElement &element, const QString &parent, const QString &id, const qreal &index)
424
 
{
425
 
        if(id.length() < 1)
426
 
                return false;
427
 
        WbItem* target = findWbItem(id);
428
 
 
429
 
        // Get the QGraphicsItem* type of pointer to the parent WbItem
430
 
        if(target) {
431
 
                target->parseSvg(element, false);
432
 
                if(parent != target->parentWbItem())
433
 
                        target->setParentWbItem(parent);
434
 
                if(index != target->index())
435
 
                        target->setIndex(index);
436
 
                return true;
437
 
        } else {
438
 
                if(element.tagName() == "path")
439
 
                        target = new WbPath(element, id, index, parent, this);
440
 
                else if(element.tagName() == "ellipse")
441
 
                        target = new WbEllipse(element, id, index, parent, this);
442
 
                else if(element.tagName() == "circle")
443
 
                        target = new WbCircle(element, id, index, parent, this);
444
 
                else if(element.tagName() == "rect")
445
 
                        target = new WbRectangle(element, id, index, parent, this);
446
 
                else if(element.tagName() == "line")
447
 
                        target = new WbLine(element, id, index, parent, this);
448
 
                else if(element.tagName() == "polyline")
449
 
                        target = new WbPolyline(element, id, index, parent, this);
450
 
                else if(element.tagName() == "polygon")
451
 
                        target = new WbPolygon(element, id, index, parent, this);
452
 
                else if(element.tagName() == "text")
453
 
                        target = new WbText(element, id, index, parent, this);
454
 
                else if(element.tagName() == "image")
455
 
                        target = new WbImage(element, id, index, parent, this);
456
 
                else if(element.tagName() == "g")
457
 
                        target = new WbGroup(element, id, index, parent, this);
458
 
                else
459
 
                        target = new WbUnknown(element, id, index, parent, this);
460
 
                // Add the element pointer to the hash of elements_
461
 
                if(target) {
462
 
                        addWbItem(target);
463
 
                        return true;
464
 
                }
465
 
        }
466
 
        return false;
467
 
}
468
 
 
469
 
bool WbScene::processNew(const QDomElement &New) {
470
 
        QDomElement element = New.firstChildElement();
471
 
        if(New.hasAttribute("id") && !element.isNull()) {
472
 
                QString id = New.attribute("id");
473
 
                QString parent = New.attribute("parent");
474
 
                if(parent.isEmpty())
475
 
                        parent = "root";
476
 
                qreal index;
477
 
                // FIXME: Actually, 'index' is REQUIRED in the JEP, leaving this as a fallback for now
478
 
                if(New.hasAttribute("index"))
479
 
                        index = New.attribute("index").toDouble();
480
 
                else
481
 
                        index = id.left(id.indexOf("/")).toDouble();
482
 
                // Check that element with 'id' doesn't exist yet.
483
 
                if(!findWbItem(id)) {
484
 
//                      qDebug() << QString("Adding - id: %1, index: %2").arg(id).arg(index).toAscii();
485
 
                        if(setElement(element, parent, id, index)) {
486
 
                                // save the highest index and id if appropriate
487
 
                                if(index > highestIndex_)
488
 
                                        highestIndex_ = static_cast<int>(index);
489
 
                                if(id.left(id.indexOf("/")).toInt() > highestId_)
490
 
                                        highestId_ = id.left(id.indexOf("/")).toInt();
491
 
                                return true;
492
 
                        }
493
 
                }
494
 
        }
495
 
        return false;
496
 
}
497
 
 
498
 
bool WbScene::processConfigure(const QDomElement &configure) {
499
 
        WbItem* wbitem = findWbItem(configure.attribute("target"));
500
 
        if(wbitem) {
501
 
                // Note that _svg->svg() returns a deep copy
502
 
                QDomElement _svg = wbitem->svg();
503
 
                if(importing)
504
 
                        wbitem->version = configure.attribute("version").toInt();
505
 
                else
506
 
                        wbitem->version++;
507
 
                if(configure.attribute("version").toInt() == wbitem->version) {
508
 
//                      qDebug) << (QString("Applying <configure/> - configure version: %1, current version: %2 target: %3 attribute: %4 value: %5").arg(configure.attribute("version")).arg(wbitem->version-1).arg(configure.attribute("target")).arg(configure.attribute("attribute")).arg(configure.attribute("value")).toAscii());
509
 
                        QDomNodeList configureChildren = configure.childNodes();
510
 
                        QString newParent = wbitem->parentWbItem();
511
 
                        for(uint i = 0; i < configureChildren.length(); i++) {
512
 
                                if(configureChildren.at(i).isElement()) {
513
 
                                        QDomElement edit = configureChildren.at(i).toElement();
514
 
                                        if(edit.nodeName() == "attribute" && !edit.attribute("name").isEmpty()) {
515
 
                                                QString attributeName = edit.attribute("name");
516
 
                                                QString oldValue = _svg.attribute(edit.attribute("name"));
517
 
                                                // Remove queued <configure>s that had the same target and attribute and retrieve the correct oldvalue
518
 
                                                removeFromQueue(configure.attribute("target"), attributeName, oldValue);
519
 
                                                wbitem->undos.append(EditUndo(configure.attribute("version").toInt(), attributeName, oldValue));
520
 
                                                QString newValue;
521
 
                                                if(!edit.attribute("from").isEmpty() && !edit.attribute("to").isEmpty()) {
522
 
                                                        bool okF, okT;
523
 
                                                        int from = edit.attribute("from").toInt(&okF);
524
 
                                                        int to = edit.attribute("to").toInt(&okT);
525
 
                                                        if(okF && okT && from <= to) {
526
 
                                                                newValue = oldValue;
527
 
                                                                newValue.replace(from, to - from, edit.text());
528
 
                                                        } else
529
 
                                                                newValue = edit.text();
530
 
                                                } else
531
 
                                                        newValue = edit.text();
532
 
                                                _svg.setAttribute(attributeName, newValue);
533
 
                                        } else if(edit.nodeName() == "content") {
534
 
                                                QDomNodeList oldContent = _svg.cloneNode().childNodes();
535
 
                                                // Remove queued <configure>s that had the same target and attribute and retrieve the correct oldvalue
536
 
                                                removeFromQueue(configure.attribute("target"), oldContent);
537
 
                                                wbitem->undos.append(EditUndo(configure.attribute("version").toInt(), oldContent));
538
 
                                                while(_svg.hasChildNodes())
539
 
                                                        _svg.removeChild(_svg.firstChild());
540
 
                                                for(uint j=0; j < edit.childNodes().length(); j++)
541
 
                                                        _svg.appendChild(edit.childNodes().at(j));
542
 
                                        } else if(edit.nodeName() == "parent") {
543
 
                                                QString oldParent = newParent;
544
 
                                                // Remove queued <configure>s that had the same target and attribute and retrieve the correct oldvalue
545
 
                                                removeFromQueue(configure.attribute("target"), oldParent);
546
 
                                                wbitem->undos.append(EditUndo(configure.attribute("version").toInt(), oldParent));
547
 
                                                newParent = edit.text();
548
 
                                        }
549
 
                                }
550
 
                        }
551
 
                        if(setElement(_svg, newParent, wbitem->id(), wbitem->index())) {
552
 
                                return true;
553
 
                        } else {
554
 
                                wbitem->undos.removeLast();
555
 
//                              wbitem->version--;
556
 
                                return false;
557
 
                        }
558
 
                } else if (configure.attribute("version").toInt() < wbitem->version) {
559
 
//                      qDebug() << (QString("Reverting <configure/>'s - configure version: %1, current version: %2 target: %3 attribute: %4 value: %5").arg(configure.attribute("version")).arg(wbitem->version-1).arg(configure.attribute("target")).arg(configure.attribute("attribute")).arg(configure.attribute("value")).toAscii());
560
 
                        // Revert the changes down to version of the configure - 1.
561
 
                        if(!wbitem->undos.isEmpty()) {
562
 
                                QString oldParent = wbitem->parentWbItem();
563
 
                                while(configure.attribute("version").toInt() <= wbitem->undos.last().version) {
564
 
                                        EditUndo u = wbitem->undos.takeLast();
565
 
//                                      qDebug() << (QString("setting %1 to %2").arg(u.attribute).arg(u.oldValue).toAscii());
566
 
                                        if(u.type == Edit::AttributeEdit) {
567
 
                                                if(u.oldValue.isNull())
568
 
                                                        _svg.removeAttribute(u.attribute);
569
 
                                                else
570
 
                                                        _svg.setAttribute(u.attribute, u.oldValue);
571
 
                                        } else if(u.type == Edit::ContentEdit) {
572
 
                                                while(_svg.hasChildNodes())
573
 
                                                        _svg.removeChild(_svg.firstChild());
574
 
                                                for(uint j=0; j < u.oldContent.length(); j++)
575
 
                                                        _svg.appendChild(u.oldContent.at(j));
576
 
                                        } else if(u.type == Edit::ParentEdit) {
577
 
                                                oldParent = u.oldParent;
578
 
                                        }
579
 
                                        if(wbitem->undos.isEmpty())
580
 
                                                break;
581
 
                                }
582
 
                                if(setElement(_svg, oldParent, wbitem->id(), wbitem->index()))
583
 
                                        return true;
584
 
                                else {
585
 
                                        // Freak out! Should never happen.
586
 
//                                      wbitem->version--;
587
 
                                        qCritical(QString("Couldn't revert wbitem with id '%1' back to version '%2'").arg(configure.attribute("target")).arg(configure.attribute("version")).toAscii());
588
 
                                        return false;
589
 
                                }
590
 
                        }
591
 
                        // The configure was processed succesfully even though no action was taken.
592
 
                        // This may happen if the wbitem was already reverted by another configure.
593
 
                        return true;
594
 
                } else if (configure.attribute("version").toInt() > wbitem->version) {
595
 
                        // This should never happen given the seriality condition.
596
 
                        // Reason to worry about misfunction of infrastructure but not much to do from here.
597
 
                        qWarning(QString("Configure to wbitem '%1' version '%1' arrived when the wbitem had version '%3'.").arg(configure.attribute("target")).arg(configure.attribute("version")).arg(wbitem->version-1).toAscii());
598
 
                        wbitem->version--;
599
 
                        return false;
600
 
                }
601
 
        }
602
 
        return false;
603
 
}
604
 
 
605
 
bool WbScene::processMove(const QDomElement &move) {
606
 
        WbItem* wbitem = findWbItem(move.attribute("target"));
607
 
        if(wbitem) {
608
 
//              qDebug() << (QString("Moving - target: %1 index: %2").arg(move.attribute("target")).arg(move.attribute("di")).toAscii());
609
 
                wbitem->setIndex(wbitem->index() + move.attribute("di").toDouble());
610
 
                if(wbitem->index() > highestIndex_)
611
 
                        highestIndex_ = static_cast<int>(wbitem->index());
612
 
                return true;
613
 
        }
614
 
        return false;
615
 
}
616
 
 
617
 
bool WbScene::processRemove(const QDomElement &remove) {
618
 
        if(findWbItem(remove.attribute("target"))) {
619
 
//              qDebug() << (QString("Removing - target: %1").arg(remove.attribute("target")).toAscii());
620
 
                if(removeElement(remove.attribute("target"))) {
621
 
                        return true;
622
 
                }
623
 
        }
624
 
        return false;
625
 
}
626
 
 
627
 
void WbScene::removeFromQueue(const QString &target, const QString &attribute, QString &oldValue) {
628
 
        // remove queued edits that have the same target and attribute
629
 
        for(int i = queue_.size() - 1; i >= 0; i--) {
630
 
                if(queue_.at(i).type == Edit::AttributeEdit && queue_.at(i).target == target && queue_.at(i).xml.attribute("name") == attribute) {
631
 
                        // Set the "older" old value since that's the correct one to undo if necessary;
632
 
                        oldValue = queue_.at(i).oldValue;
633
 
                        queue_.removeAt(i);
634
 
                        // We can return because there can never be two that match
635
 
                        return;
636
 
                }
637
 
        }
638
 
}
639
 
 
640
 
void WbScene::removeFromQueue(const QString &target, QString &oldValue) {
641
 
        // remove queued edits that have the same target and set the parent
642
 
        for(int i = queue_.size() - 1; i >= 0; i--) {
643
 
                if(queue_.at(i).type == Edit::ParentEdit && queue_.at(i).target == target) {
644
 
                        // Set the "older" old parent since that's the correct one to undo if necessary;
645
 
                        oldValue = queue_.at(i).oldParent;
646
 
                        queue_.removeAt(i);
647
 
                        // We can return because there can never be two that match
648
 
                        return;
649
 
                }
650
 
        }
651
 
}
652
 
 
653
 
void WbScene::removeFromQueue(const QString &target, QDomNodeList &oldValue) {
654
 
        // remove queued edits that have the same target and set the content
655
 
        for(int i = queue_.size() - 1; i >= 0; i--) {
656
 
                if(queue_.at(i).type == Edit::ContentEdit && queue_.at(i).target == target) {
657
 
                        // Set the "older" old content since that's the correct one to undo if necessary;
658
 
                        oldValue = queue_.at(i).oldContent;
659
 
                        queue_.removeAt(i);
660
 
                        // We can return because there can never be two that match
661
 
                        return;
662
 
                }
663
 
        }
664
 
}
665
 
 
666
 
QString WbScene::newId() {
667
 
        return QString("%1/%2").arg(++highestId_).arg(ownJid_);
668
 
}
669
 
 
670
 
qreal WbScene::newIndex() {
671
 
        return ++highestIndex_;
672
 
}