~ubuntu-branches/ubuntu/oneiric/psi/oneiric

« back to all changes in this revision

Viewing changes to src/sxe/sxerecord.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2009-09-25 17:49:51 UTC
  • mfrom: (6.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090925174951-lvm7kdap82o8xhn3
Tags: 0.13-1
* Updated to upstream version 0.13
* Set Standards-Version to 3.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 
21
21
#include "sxerecord.h"
22
22
 
23
 
//----------------------------------------------------------------------------
24
 
// SxeRecord::VersionData
25
 
//----------------------------------------------------------------------------
26
 
 
27
 
SxeRecord::VersionData::VersionData(QString _parent, /*QString _ns,*/ QString _identifier, QString _data)  {
28
 
    version = 0;
29
 
    primaryWeight = 0;
30
 
    parent = _parent;
31
 
    // ns = _ns;
32
 
    identifier = _identifier;
33
 
    data = _data;
34
 
}
35
 
 
36
 
SxeRecord::VersionData::VersionData(const VersionData &other) : parent(other.parent), /*ns(other.ns),*/ identifier(other.identifier), data(other.data)  {
37
 
    version = other.version;
38
 
    primaryWeight = other.primaryWeight;
39
 
}
 
23
 
 
24
static bool referencedEditLessThan(const SxeEdit* e1, const SxeEdit* e2) { return *e1 < *e2; }
40
25
 
41
26
 
42
27
//----------------------------------------------------------------------------
45
30
 
46
31
SxeRecord::SxeRecord(QString rid) {
47
32
    rid_ = rid;
48
 
    version_ = 0;
49
33
};
50
34
 
51
35
SxeRecord::~SxeRecord() {
52
 
    while(!versions_.isEmpty())
53
 
        delete versions_.takeFirst();
54
36
    while(!edits_.isEmpty())
55
37
        delete edits_.takeFirst();
56
38
};
59
41
    return node_;
60
42
}
61
43
 
62
 
void SxeRecord::apply(QDomDocument &doc, SxeEdit* edit, bool importing) {
 
44
void SxeRecord::apply(QDomDocument &doc, SxeEdit* edit) {
63
45
    if(edit->rid() == rid()) {
64
 
        if((edit->type() == SxeEdit::New && applySxeNewEdit(doc, dynamic_cast<const SxeNewEdit*>(edit)))
65
 
        || (edit->type() == SxeEdit::Remove && applySxeRemoveEdit(dynamic_cast<const SxeRemoveEdit*>(edit)))
66
 
        || (edit->type() == SxeEdit::Record && applySxeRecordEdit(dynamic_cast<const SxeRecordEdit*>(edit), importing))) {
67
 
            edits_ += edit;
68
 
        }
 
46
        if(edit->type() == SxeEdit::New)
 
47
            applySxeNewEdit(doc, dynamic_cast<SxeNewEdit*>(edit));
 
48
        else if (edit->type() == SxeEdit::Remove)
 
49
            applySxeRemoveEdit(dynamic_cast<SxeRemoveEdit*>(edit));
 
50
        else if (edit->type() == SxeEdit::Record)
 
51
            applySxeRecordEdit(dynamic_cast<SxeRecordEdit*>(edit));
69
52
    } else {
70
 
        qDebug(QString("Tried to apply an edit meant for %1 to %2.").arg(edit->rid()).arg(rid()).toAscii());
 
53
        qDebug() << QString("Tried to apply an edit meant for %1 to %2.").arg(edit->rid()).arg(rid()).toAscii();
71
54
    }
72
55
}
73
56
 
74
57
QList<const SxeEdit*> SxeRecord::edits() const {
75
58
    QList<const SxeEdit*> edits;
76
 
    foreach(SxeEdit* e, edits_) {
77
 
        edits.append(e);
78
 
    }
 
59
        foreach(SxeEdit* e, edits_) {
 
60
            edits.append(e);
 
61
        }
79
62
    return edits;
80
63
};
81
64
 
82
 
bool SxeRecord::applySxeNewEdit(QDomDocument &doc, const SxeNewEdit* edit) {
83
 
    if(!(edits_.size() == 0 && version_ == 0 && node_.isNull())) {
 
65
bool SxeRecord::applySxeNewEdit(QDomDocument &doc, SxeNewEdit* edit) {
 
66
    if(!(edits_.size() == 0 && node_.isNull())) {
84
67
        qDebug("Someone's not behaving! Tried to apply a SxeNewEdit to an existing node.");
85
68
        emit nodeRemovalRequired(node_);
86
69
        return false;
118
101
    } else
119
102
        return false;
120
103
 
121
 
    VersionData* data = new VersionData();
122
 
 
123
 
    data->version = 0;
124
 
    data->parent = edit->parent();
125
 
    data->primaryWeight = edit->primaryWeight();
126
 
    data->identifier = edit->name();
127
 
    data->data = edit->chdata();
128
 
 
129
 
    versions_ += data;
 
104
    edits_ += edit;
 
105
    revertToZero();
130
106
 
131
107
    emit nodeToBeAdded(node_, edit->remote(), edit->rid());
 
108
 
 
109
    lastParent_ = parent();
 
110
    lastPrimaryWeight_ = primaryWeight();
132
111
    
133
112
    return true;
134
113
}
135
114
 
136
 
bool SxeRecord::applySxeRemoveEdit(const SxeRemoveEdit* edit) {
 
115
void SxeRecord::revertToZero() {
 
116
#ifndef NDEBUG
 
117
    if (edits_[0]->type() != SxeEdit::New)
 
118
        qDebug() << QString("First edit is of type %1!").arg(edits_[0]->type());
 
119
#endif
 
120
 
 
121
    const SxeNewEdit* edit = dynamic_cast<const SxeNewEdit*>(edits_[0]);
 
122
 
 
123
    parent_ = edit->parent();
 
124
    primaryWeight_ = edit->primaryWeight();
 
125
    identifier_ = edit->name();
 
126
    data_ = edit->chdata();
 
127
}
 
128
 
 
129
bool SxeRecord::applySxeRemoveEdit(SxeRemoveEdit* edit) {
137
130
    if(!node_.isNull()) {
138
131
        emit nodeToBeRemoved(node_, edit->remote());
139
132
 
150
143
            node_.parentNode().removeChild(node_);
151
144
            emit nodeRemoved(node_, edit->remote());
152
145
        }
153
 
        
 
146
 
 
147
        edits_ += edit;
 
148
 
154
149
        // delete the record
155
150
        deleteLater();
156
151
    }
158
153
    return true;
159
154
}
160
155
 
161
 
bool SxeRecord::applySxeRecordEdit(const SxeRecordEdit* edit, bool importing) {
162
 
        if(!node_.isNull() && edits_.size() > 0) {
163
 
            if(importing && version_ < edit->version())
164
 
                // don't check for "in-order" 
165
 
                version_ = edit->version();
166
 
            else
167
 
                version_++;
168
 
 
169
 
            QString oldParent = parent();
170
 
            double oldPrimaryWeight = primaryWeight();
171
 
 
172
 
            if(edit->version() == version_) {
173
 
                // process the "in order" edit
174
 
                
175
 
                // clone the previous VersionData
176
 
                VersionData* data = new VersionData(*versions_.last());
177
 
                data->version = version_;
178
 
 
179
 
                versions_ += data;
180
 
 
181
 
                foreach(SxeRecordEdit::Key key, edit->keys()) {
182
 
                    if(key == SxeRecordEdit::Parent && edit->value(key) != parent()) {
183
 
                        data->parent = edit->value(key);
184
 
                    } else if(key == SxeRecordEdit::PrimaryWeight && edit->value(key).toDouble() != primaryWeight()) {
185
 
                        data->primaryWeight = edit->value(key).toDouble();
186
 
                    } else if(key == SxeRecordEdit::Name && edit->value(key) != name()) {
187
 
                        data->identifier = edit->value(key);
188
 
                        // TODO: change the name somehow... by copying all the child nodes to a new node i suppose
189
 
                        // emit nameChanged(node_, edit->remote());
190
 
                    } else if(key == SxeRecordEdit::Chdata) {
191
 
                        QString newValue;
192
 
                        
193
 
                        // Check for partial replacements
194
 
                        QList<SxeRecordEdit::Key> keys = edit->keys();
195
 
                        if(keys.contains(SxeRecordEdit::ReplaceFrom)
196
 
                            && keys.contains(SxeRecordEdit::ReplaceN)) {
197
 
                            bool ok1, ok2;
198
 
                            int from = edit->value(SxeRecordEdit::ReplaceFrom).toInt(&ok1);
199
 
                            int n = edit->value(SxeRecordEdit::ReplaceN).toInt(&ok2);
200
 
                            newValue = data->data;
201
 
                            if(ok1 && ok2 && from >= 0 && n >= 0 && from + n <= data->data.length()) {
202
 
                                newValue.replace(from, n, edit->value(key));
203
 
                            } else {
204
 
                                if(!ok1)
205
 
                                    qDebug(QString("Could not convert 'replacefrom' = '%1' to int.").arg(edit->value(SxeRecordEdit::ReplaceFrom)));
206
 
                                if(!ok2)
207
 
                                    qDebug(QString("Could not convert 'replacen' = '%1' to int.").arg(edit->value(SxeRecordEdit::ReplaceN)));
208
 
                                if(from < 0)
209
 
                                    qDebug(QString("'replacefrom' = '%1' is negative.").arg(edit->value(SxeRecordEdit::ReplaceFrom)));
210
 
                                if(n < 0)
211
 
                                    qDebug(QString("'replacen' = '%1' is negative.").arg(edit->value(SxeRecordEdit::ReplaceN)));
212
 
                                if(from + n > data->data.length())
213
 
                                    qDebug(QString("from (%1) + n (%2) > data->data.length() (%3).").arg(from).arg(n).arg(data->data.length()));
214
 
                            }
215
 
                        } else {
216
 
                            newValue = edit->value(key);
217
 
                        }
218
 
 
219
 
                        // Only process further if some change resulted
220
 
                        if(newValue != data->data) {
221
 
                            data->data = newValue;
222
 
 
223
 
                            emit chdataToBeChanged(node_, edit->remote());
224
 
                            // qDebug(QString("Setting '%1' to \"%2\"").arg(node_.nodeName()).arg(data->data).toAscii());
225
 
                            if(node_.isAttr() || node_.isText() || node_.isComment())
226
 
                                node_.setNodeValue(data->data);
227
 
 
228
 
                            emit chdataChanged(node_, edit->remote());
229
 
                        }
230
 
                    } else if(key == SxeRecordEdit::ProcessingInstructionTarget && edit->value(key) != processingInstructionTarget()) {
231
 
                        data->identifier = edit->value(key);
232
 
 
233
 
                        if(node_.isProcessingInstruction()) {
234
 
                            // emit processingInstructionTargetToBeChanged(node_, edit->remote());
235
 
 
236
 
                            // TODO: figure out a way to change the target
237
 
                            //      will probably need to recreate the pi
238
 
 
239
 
                            // emit processingInstructionTargetChanged(node_, edit->remote());
240
 
                        }
241
 
                    } else if(key == SxeRecordEdit::ProcessingInstructionData && edit->value(key) != processingInstructionData()) {
242
 
                        data->data = edit->value(key);
243
 
 
244
 
                        if(node_.isProcessingInstruction()) {
245
 
                            emit processingInstructionDataToBeChanged(node_, edit->remote());
246
 
                            node_.toProcessingInstruction().setData(data->data);
247
 
                            emit processingInstructionDataChanged(node_, edit->remote());
248
 
                        }
249
 
                    }
250
 
                }
251
 
 
252
 
            } else if (edit->version() < version_) {
253
 
 
254
 
                // Revert the changes down to version of the SxeEdit - 1.
255
 
                // by deleting the higher versions and edits
256
 
                while(versions_.size() > 1 && versions_.last()->version >= edit->version())
257
 
                    delete versions_.takeLast();
258
 
                while(edits_.size() > 0 && edits_.last()->type() == SxeEdit::Record && dynamic_cast<const SxeRecordEdit*>(edits_.last())->version() >= edit->version())
259
 
                    delete edits_.takeLast();
260
 
 
261
 
                if((node_.isElement() || node_.isAttr())
262
 
                    && node_.nodeName() != name()) {
263
 
                    // TODO: update the name somehow
264
 
                }
265
 
 
266
 
                if((node_.isText() || node_.isAttr() || node_.isComment())
267
 
                    && node_.nodeValue() != chdata()) {
268
 
                    node_.setNodeValue(chdata());
269
 
                }
270
 
 
271
 
                if(node_.isProcessingInstruction()) {
272
 
                    if(node_.toProcessingInstruction().target() != processingInstructionTarget()) {
273
 
                        // TODO: change the target somehow
274
 
                    }
275
 
 
276
 
                    if(node_.toProcessingInstruction().data() != processingInstructionData()) {
277
 
                        node_.toProcessingInstruction().setData(processingInstructionData());
278
 
                    }
279
 
                }
280
 
                
 
156
bool SxeRecord::applySxeRecordEdit(SxeRecordEdit* edit) {
 
157
    if(!node_.isNull() && edits_.size() > 0) {
 
158
 
 
159
        if(edit->version() == version() + 1 && !edits_.last()->overridenBy(*edit)) {
 
160
 
 
161
            // process the "in order" edit
 
162
            edits_ += edit;
 
163
            processInOrderRecordEdit(edit);
 
164
 
 
165
        } else {
 
166
 
 
167
            edits_ += edit;
 
168
            reorderEdits();
 
169
 
 
170
        }
 
171
 
 
172
        updateNode(edit->remote());
 
173
 
 
174
        return true;
 
175
 
 
176
    }
 
177
    return false;    
 
178
}
 
179
 
 
180
void SxeRecord::processInOrderRecordEdit(const SxeRecordEdit* edit) {
 
181
 
 
182
    foreach(SxeRecordEdit::Key key, edit->keys()) {
 
183
 
 
184
        if(key == SxeRecordEdit::Parent && edit->value(key) != parent()) {
 
185
 
 
186
            parent_ = edit->value(key);
 
187
 
 
188
        } else if(key == SxeRecordEdit::PrimaryWeight && edit->value(key).toDouble() != primaryWeight()) {
 
189
 
 
190
            primaryWeight_ = edit->value(key).toDouble();
 
191
 
 
192
        } else if(key == SxeRecordEdit::Name && edit->value(key) != name()) {
 
193
 
 
194
            identifier_ = edit->value(key);
 
195
 
 
196
        } else if(key == SxeRecordEdit::ProcessingInstructionTarget && edit->value(key) != processingInstructionTarget()) {
 
197
 
 
198
            identifier_ = edit->value(key);
 
199
 
 
200
        } else if(key == SxeRecordEdit::Chdata || key == SxeRecordEdit::ProcessingInstructionData) {
 
201
            
 
202
            // Check for partial replacements
 
203
            QList<SxeRecordEdit::Key> keys = edit->keys();
 
204
            if(keys.contains(SxeRecordEdit::ReplaceFrom)
 
205
                && keys.contains(SxeRecordEdit::ReplaceN)) {
 
206
 
 
207
                // 'replacefrom' & 'replacen' exist, do they contain integers?
 
208
                bool ok1, ok2;
 
209
                int from = edit->value(SxeRecordEdit::ReplaceFrom).toInt(&ok1);
 
210
                int n = edit->value(SxeRecordEdit::ReplaceN).toInt(&ok2);
 
211
 
 
212
                if(ok1 && ok2 && from >= 0 && n >= 0 && from + n <= data_.length()) {
 
213
 
 
214
                    // Do partial replace if the range makes sense
 
215
                    data_.replace(from, n, edit->value(key));
 
216
 
 
217
                } else {
 
218
                    if(!ok1)
 
219
                        qDebug() << QString("Could not convert 'replacefrom' = '%1' to int.").arg(edit->value(SxeRecordEdit::ReplaceFrom));
 
220
                    if(!ok2)
 
221
                        qDebug() << QString("Could not convert 'replacen' = '%1' to int.").arg(edit->value(SxeRecordEdit::ReplaceN));
 
222
                    if(from < 0)
 
223
                        qDebug() << QString("'replacefrom' = '%1' is negative.").arg(edit->value(SxeRecordEdit::ReplaceFrom));
 
224
                    if(n < 0)
 
225
                        qDebug() << QString("'replacen' = '%1' is negative.").arg(edit->value(SxeRecordEdit::ReplaceN));
 
226
                    if(from + n > data_.length())
 
227
                        qDebug() << QString("from (%1) + n (%2) > data_.length() (%3).").arg(from).arg(n).arg(data_.length());
 
228
                }
 
229
 
281
230
            } else {
282
 
                // This should never happen given the seriality condition.
283
 
                // Reason to worry about misbehaviour of peers but not much to do from here.
284
 
                qWarning(QString("Configure to node '%1' version '%2' arrived when the node had version '%3'.").arg(edit->rid()).arg(version_).arg(edit->version() - 1).toAscii());
 
231
 
 
232
                data_ = edit->value(key);
 
233
 
285
234
            }
286
235
 
287
 
            if(parent() != oldParent || primaryWeight() != oldPrimaryWeight)
288
 
                emit nodeToBeMoved(node_, edit->remote());
289
 
 
290
 
            return true;
291
 
 
292
 
        }
293
 
        return false;    
 
236
        }
 
237
    }
 
238
 
 
239
}
 
240
 
 
241
void SxeRecord::reorderEdits() {
 
242
    qSort(edits_.begin(), edits_.end(), referencedEditLessThan);
 
243
 
 
244
    revertToZero();
 
245
 
 
246
    // Apply all the valid record edits
 
247
    for(int i = 1; i < edits_.size(); i++) {
 
248
 
 
249
        if (edits_[i]->type() == SxeEdit::Record) {
 
250
            SxeRecordEdit* edit = dynamic_cast<SxeRecordEdit*>(edits_[i]);
 
251
 
 
252
            // Check that the version matches and that the next edit doesn't override it.
 
253
            if (i == edit->version() && (i+1 == edits_.size() || !edit->overridenBy(*edits_[i+1])))
 
254
                processInOrderRecordEdit(edit);
 
255
            else if (edit->version() <= i)
 
256
                edit->nullify();  // There's no way the edit could be applied anymore
 
257
 
 
258
        } else {
 
259
            qDebug() << QString("Edit of type %1 at %2!").arg(edits_[i]->type()).arg(i).toAscii();
 
260
        }
 
261
 
 
262
    }
 
263
 
 
264
}
 
265
 
 
266
void SxeRecord::updateNode(bool remote) {
 
267
    if(parent_ != lastParent_ || primaryWeight_ != lastPrimaryWeight_)
 
268
        emit nodeToBeMoved(node_, remote);
 
269
 
 
270
    if(identifier_ != lastIdentifier_) {
 
271
 
 
272
        if ((node_.isElement() || node_.isAttr())
 
273
            && node_.nodeName() != name()) {
 
274
 
 
275
            // emit nameToBeChanged(node_, remote);
 
276
            // TODO: update the name somehow
 
277
            // emit nameChanged(node_, remote);
 
278
 
 
279
        } else if(node_.isProcessingInstruction()) {
 
280
 
 
281
            // emit processingInstructionTargetToBeChanged(node_, remote);
 
282
            // TODO: figure out a way to change the target
 
283
            //      will probably need to recreate the pi
 
284
            // emit processingInstructionTargetChanged(node_, remote);
 
285
        }
 
286
    }
 
287
 
 
288
    if(data_ != lastData_) {
 
289
 
 
290
        // qDebug() << QString("Setting '%1' to \"%2\"").arg(node_.nodeName()).arg(data_).toAscii();
 
291
 
 
292
        if((node_.isText() || node_.isAttr() || node_.isComment())) {
 
293
 
 
294
            emit chdataToBeChanged(node_, remote);
 
295
            node_.setNodeValue(data_);
 
296
            emit chdataChanged(node_, remote);
 
297
 
 
298
        } else if(node_.isProcessingInstruction()) {
 
299
 
 
300
            emit processingInstructionDataToBeChanged(node_, remote);
 
301
            node_.toProcessingInstruction().setData(data_);
 
302
            emit processingInstructionDataChanged(node_, remote);
 
303
 
 
304
        }
 
305
 
 
306
    }
 
307
 
294
308
}
295
309
 
296
310
QString SxeRecord::rid() const {
298
312
};
299
313
 
300
314
QString SxeRecord::parent() const {
301
 
    if(versions_.isEmpty())
302
 
        return "";
303
 
    else
304
 
        return versions_.last()->parent;
 
315
    return parent_;
305
316
}
306
317
 
307
318
double SxeRecord::primaryWeight() const {
308
 
    if(versions_.isEmpty())
309
 
        return 0;
310
 
    else
311
 
        return versions_.last()->primaryWeight;
 
319
    return primaryWeight_;
312
320
}
313
321
 
314
322
int SxeRecord::version() const {
315
 
    return version_;
 
323
    return edits_.size() - 1;
316
324
}
317
325
 
318
326
QString SxeRecord::name() const {
319
 
    if(versions_.isEmpty())
320
 
        return QString();
321
 
    else
322
 
        return versions_.last()->identifier;
 
327
    return identifier_;
323
328
}
324
329
 
325
330
QString SxeRecord::nameSpace() const {
330
335
}
331
336
 
332
337
QString SxeRecord::chdata() const {
333
 
    if(versions_.isEmpty())
334
 
        return QString();
335
 
    else
336
 
        return versions_.last()->data;
 
338
    return data_;
337
339
}
338
340
 
339
341
QString SxeRecord::processingInstructionTarget() const {
340
 
    if(versions_.isEmpty())
341
 
        return QString();
342
 
    else
343
 
        return versions_.last()->identifier;
 
342
    return identifier_;
344
343
}
345
344
 
346
345
QString SxeRecord::processingInstructionData() const {
347
 
    if(versions_.isEmpty())
348
 
        return QString();
349
 
    else
350
 
        return versions_.last()->data;
 
346
    return data_;
351
347
}
352
348
 
353
349
bool SxeRecord::hasSmallerSecondaryWeight(const SxeRecord &other) const {