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();
169
QString oldParent = parent();
170
double oldPrimaryWeight = primaryWeight();
172
if(edit->version() == version_) {
173
// process the "in order" edit
175
// clone the previous VersionData
176
VersionData* data = new VersionData(*versions_.last());
177
data->version = version_;
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) {
193
// Check for partial replacements
194
QList<SxeRecordEdit::Key> keys = edit->keys();
195
if(keys.contains(SxeRecordEdit::ReplaceFrom)
196
&& keys.contains(SxeRecordEdit::ReplaceN)) {
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));
205
qDebug(QString("Could not convert 'replacefrom' = '%1' to int.").arg(edit->value(SxeRecordEdit::ReplaceFrom)));
207
qDebug(QString("Could not convert 'replacen' = '%1' to int.").arg(edit->value(SxeRecordEdit::ReplaceN)));
209
qDebug(QString("'replacefrom' = '%1' is negative.").arg(edit->value(SxeRecordEdit::ReplaceFrom)));
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()));
216
newValue = edit->value(key);
219
// Only process further if some change resulted
220
if(newValue != data->data) {
221
data->data = newValue;
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);
228
emit chdataChanged(node_, edit->remote());
230
} else if(key == SxeRecordEdit::ProcessingInstructionTarget && edit->value(key) != processingInstructionTarget()) {
231
data->identifier = edit->value(key);
233
if(node_.isProcessingInstruction()) {
234
// emit processingInstructionTargetToBeChanged(node_, edit->remote());
236
// TODO: figure out a way to change the target
237
// will probably need to recreate the pi
239
// emit processingInstructionTargetChanged(node_, edit->remote());
241
} else if(key == SxeRecordEdit::ProcessingInstructionData && edit->value(key) != processingInstructionData()) {
242
data->data = edit->value(key);
244
if(node_.isProcessingInstruction()) {
245
emit processingInstructionDataToBeChanged(node_, edit->remote());
246
node_.toProcessingInstruction().setData(data->data);
247
emit processingInstructionDataChanged(node_, edit->remote());
252
} else if (edit->version() < version_) {
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();
261
if((node_.isElement() || node_.isAttr())
262
&& node_.nodeName() != name()) {
263
// TODO: update the name somehow
266
if((node_.isText() || node_.isAttr() || node_.isComment())
267
&& node_.nodeValue() != chdata()) {
268
node_.setNodeValue(chdata());
271
if(node_.isProcessingInstruction()) {
272
if(node_.toProcessingInstruction().target() != processingInstructionTarget()) {
273
// TODO: change the target somehow
276
if(node_.toProcessingInstruction().data() != processingInstructionData()) {
277
node_.toProcessingInstruction().setData(processingInstructionData());
156
bool SxeRecord::applySxeRecordEdit(SxeRecordEdit* edit) {
157
if(!node_.isNull() && edits_.size() > 0) {
159
if(edit->version() == version() + 1 && !edits_.last()->overridenBy(*edit)) {
161
// process the "in order" edit
163
processInOrderRecordEdit(edit);
172
updateNode(edit->remote());
180
void SxeRecord::processInOrderRecordEdit(const SxeRecordEdit* edit) {
182
foreach(SxeRecordEdit::Key key, edit->keys()) {
184
if(key == SxeRecordEdit::Parent && edit->value(key) != parent()) {
186
parent_ = edit->value(key);
188
} else if(key == SxeRecordEdit::PrimaryWeight && edit->value(key).toDouble() != primaryWeight()) {
190
primaryWeight_ = edit->value(key).toDouble();
192
} else if(key == SxeRecordEdit::Name && edit->value(key) != name()) {
194
identifier_ = edit->value(key);
196
} else if(key == SxeRecordEdit::ProcessingInstructionTarget && edit->value(key) != processingInstructionTarget()) {
198
identifier_ = edit->value(key);
200
} else if(key == SxeRecordEdit::Chdata || key == SxeRecordEdit::ProcessingInstructionData) {
202
// Check for partial replacements
203
QList<SxeRecordEdit::Key> keys = edit->keys();
204
if(keys.contains(SxeRecordEdit::ReplaceFrom)
205
&& keys.contains(SxeRecordEdit::ReplaceN)) {
207
// 'replacefrom' & 'replacen' exist, do they contain integers?
209
int from = edit->value(SxeRecordEdit::ReplaceFrom).toInt(&ok1);
210
int n = edit->value(SxeRecordEdit::ReplaceN).toInt(&ok2);
212
if(ok1 && ok2 && from >= 0 && n >= 0 && from + n <= data_.length()) {
214
// Do partial replace if the range makes sense
215
data_.replace(from, n, edit->value(key));
219
qDebug() << QString("Could not convert 'replacefrom' = '%1' to int.").arg(edit->value(SxeRecordEdit::ReplaceFrom));
221
qDebug() << QString("Could not convert 'replacen' = '%1' to int.").arg(edit->value(SxeRecordEdit::ReplaceN));
223
qDebug() << QString("'replacefrom' = '%1' is negative.").arg(edit->value(SxeRecordEdit::ReplaceFrom));
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());
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());
232
data_ = edit->value(key);
287
if(parent() != oldParent || primaryWeight() != oldPrimaryWeight)
288
emit nodeToBeMoved(node_, edit->remote());
241
void SxeRecord::reorderEdits() {
242
qSort(edits_.begin(), edits_.end(), referencedEditLessThan);
246
// Apply all the valid record edits
247
for(int i = 1; i < edits_.size(); i++) {
249
if (edits_[i]->type() == SxeEdit::Record) {
250
SxeRecordEdit* edit = dynamic_cast<SxeRecordEdit*>(edits_[i]);
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
259
qDebug() << QString("Edit of type %1 at %2!").arg(edits_[i]->type()).arg(i).toAscii();
266
void SxeRecord::updateNode(bool remote) {
267
if(parent_ != lastParent_ || primaryWeight_ != lastPrimaryWeight_)
268
emit nodeToBeMoved(node_, remote);
270
if(identifier_ != lastIdentifier_) {
272
if ((node_.isElement() || node_.isAttr())
273
&& node_.nodeName() != name()) {
275
// emit nameToBeChanged(node_, remote);
276
// TODO: update the name somehow
277
// emit nameChanged(node_, remote);
279
} else if(node_.isProcessingInstruction()) {
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);
288
if(data_ != lastData_) {
290
// qDebug() << QString("Setting '%1' to \"%2\"").arg(node_.nodeName()).arg(data_).toAscii();
292
if((node_.isText() || node_.isAttr() || node_.isComment())) {
294
emit chdataToBeChanged(node_, remote);
295
node_.setNodeValue(data_);
296
emit chdataChanged(node_, remote);
298
} else if(node_.isProcessingInstruction()) {
300
emit processingInstructionDataToBeChanged(node_, remote);
301
node_.toProcessingInstruction().setData(data_);
302
emit processingInstructionDataChanged(node_, remote);
296
310
QString SxeRecord::rid() const {