1 /**
2 * Inkboard message -> XML::Event* deserializer
3 *
4 * Authors:
5 * David Yip <yipdw@rose-hulman.edu>
6 *
7 * Copyright (c) 2005 Authors
8 *
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
12 #include "xml/log-builder.h"
13 #include "xml/event.h"
14 #include "xml/node.h"
15 #include "xml/repr.h"
17 #include "util/share.h"
19 #include "gc-anchored.h"
21 #include "jabber_whiteboard/message-utilities.h"
22 #include "jabber_whiteboard/typedefs.h"
23 #include "jabber_whiteboard/node-utilities.h"
24 #include "jabber_whiteboard/node-tracker.h"
25 #include "jabber_whiteboard/deserializer.h"
26 #include <glibmm.h>
28 namespace Inkscape {
30 namespace Whiteboard {
32 void
33 Deserializer::deserializeEventAdd(Glib::ustring const& msg)
34 {
35 // 1. Extract required attributes: parent, child, node name, and node type.
36 // If any of these cannot be found, return.
37 std::string parent, child, prev;
38 Glib::ustring name, type;
40 struct Node buf;
42 buf.tag = MESSAGE_PARENT;
43 if (!MessageUtilities::findTag(buf, msg)) {
44 return;
45 }
46 parent = buf.data.c_str();
48 buf.tag = MESSAGE_CHILD;
49 if (!MessageUtilities::findTag(buf, msg)) {
50 return;
51 }
52 child = buf.data.c_str();
54 KeyToNodeMap::iterator i = this->_newnodes.find(child);
55 if (i != this->_newnodes.end()) {
56 if (this->_node_action_tracker.getAction(i->second) == NODE_ADD) {
57 return;
58 }
59 }
61 buf.tag = MESSAGE_NAME;
62 if (!MessageUtilities::findTag(buf, msg)) {
63 return;
64 } else {
65 name = buf.data;
66 }
68 buf.tag = MESSAGE_NODETYPE;
69 if (!MessageUtilities::findTag(buf, msg)) {
70 return;
71 } else {
72 type = buf.data;
73 }
75 // 2. Extract optional attributes: the node previous to the new child node.
76 buf.tag = MESSAGE_REF;
77 if (MessageUtilities::findTag(buf, msg)) {
78 prev = buf.data.c_str();
79 }
81 // 3. Check if the received child node is a special node. If it is, and we are already
82 // tracking it, then we should not add the node.
83 if (this->_xnt->isSpecialNode(name)) {
84 if (this->_xnt->isTracking(this->_xnt->getSpecialNodeKeyFromName(name))) {
85 return;
86 }
87 }
89 // 4. Look up the parent node. If we cannot find it, return.
90 XML::Node* parentRepr = this->_getNodeByID(parent);
91 if (parentRepr == NULL) {
92 g_warning("Cannot find parent node identified by %s", parent.c_str());
93 return;
94 }
96 // 5. Look up the node previous to the child, if it exists.
97 // If we cannot find it, we may be in a change conflict situation.
98 // In that case, just append the node.
99 XML::Node* prevRepr = NULL;
100 if (!prev.empty()) {
101 prevRepr = this->_getNodeByID(prev);
102 if (prevRepr == NULL) {
103 g_warning("Prev node %s could not be found; appending incoming node. Document may not be synchronized.", prev.c_str());
104 prevRepr = parentRepr->lastChild();
105 }
106 }
108 if (prevRepr) {
109 if (prevRepr->parent() != parentRepr) {
110 if (this->_parent_child_map[prevRepr] != parentRepr) {
111 g_warning("ref mismatch on node %s: child=%s ref=%p parent=%p ref->parent()=%p", prev.c_str(), child.c_str(), prevRepr, parentRepr, prevRepr->parent());
112 g_warning("parent_child_map[%p (%s)] = %p (%s)", prevRepr, this->_xnt->get(*prevRepr).c_str(), this->_parent_child_map[prevRepr], this->_xnt->get(*(this->_parent_child_map[prevRepr])).c_str());
113 return;
114 }
115 }
116 }
118 XML::Node* childRepr = NULL;
120 // 6. Create the child node.
122 switch (NodeUtilities::stringToNodeType(type)) {
123 case XML::TEXT_NODE:
124 buf.tag = MESSAGE_CONTENT;
125 if (!MessageUtilities::findTag(buf, msg)) {
126 childRepr = sp_repr_new_text("");
127 } else {
128 childRepr = sp_repr_new_text(buf.data.c_str());
129 }
130 break;
131 case XML::DOCUMENT_NODE:
132 // TODO
133 case XML::COMMENT_NODE:
134 buf.tag = MESSAGE_CONTENT;
135 if (!MessageUtilities::findTag(buf, msg)) {
136 childRepr = sp_repr_new_comment("");
137 } else {
138 childRepr = sp_repr_new_comment(buf.data.c_str());
139 }
140 break;
141 case XML::ELEMENT_NODE:
142 default:
143 childRepr = sp_repr_new(name.data());
144 break;
145 }
148 this->_actions.push_back(SerializedEventNodeAction(KeyNodePair(child, childRepr), NODE_ADD));
149 this->_newnodes[child] = childRepr;
150 this->_newkeys[childRepr] = child;
153 // 8. Deserialize the event.
154 this->_builder.addChild(*parentRepr, *childRepr, prevRepr);
155 this->_parent_child_map.erase(childRepr);
156 this->_parent_child_map[childRepr] = parentRepr;
157 this->_addOneEvent(this->_builder.detach());
158 Inkscape::GC::release(childRepr);
159 }
161 void
162 Deserializer::deserializeEventDel(Glib::ustring const& msg)
163 {
164 // 1. Extract required attributes: parent, child. If we do not know these,
165 // return.
166 std::string parent, child, prev;
168 struct Node buf;
170 buf.tag = MESSAGE_PARENT;
171 if (!MessageUtilities::findTag(buf, msg)) {
172 return;
173 }
174 parent = buf.data.c_str();
176 buf.tag = MESSAGE_CHILD;
177 if (!MessageUtilities::findTag(buf, msg)) {
178 return;
179 }
180 child = buf.data.c_str();
182 KeyToNodeMap::iterator i = this->_newnodes.find(child);
183 if (i != this->_newnodes.end()) {
184 if (this->_node_action_tracker.getAction(i->second) == NODE_REMOVE) {
185 return;
186 }
187 }
189 // 2. Extract optional attributes: previous node.
190 buf.tag = MESSAGE_REF;
191 if (MessageUtilities::findTag(buf, msg)) {
192 prev = buf.data.c_str();
193 }
195 // 3. Retrieve nodes. If we cannot find all nodes involved, return.
196 XML::Node* parentRepr = this->_getNodeByID(parent);
197 XML::Node* childRepr = this->_getNodeByID(child);
198 XML::Node* prevRepr = NULL;
199 if (!prev.empty()) {
200 prevRepr = this->_getNodeByID(prev);
201 if (prevRepr == NULL) {
202 return;
203 }
204 }
206 // 4. Deserialize the event.
207 if (parentRepr && childRepr) {
208 if (childRepr->parent() == parentRepr || this->_parent_child_map[childRepr] == parentRepr) {
209 // this->_actions.push_back(SerializedEventNodeAction(KeyNodePair(child, childRepr), NODE_REMOVE));
210 this->_builder.removeChild(*parentRepr, *childRepr, prevRepr);
211 this->_parent_child_map.erase(childRepr);
212 this->_addOneEvent(this->_builder.detach());
214 // 5. Mark the removed node and all its children for removal from the tracker.
215 this->_recursiveMarkForRemoval(childRepr);
216 } else {
217 g_warning("child->parent() == parent mismatch on child=%s (%p), parent=%s: parent=%p child->parent()=%p", child.c_str(), childRepr, parent.c_str(), parentRepr, childRepr->parent());
218 g_warning("parent_child_map[%p] = %p", childRepr, this->_parent_child_map[childRepr]);
219 }
220 } else {
221 g_warning("Missing parentRepr and childRepr: parent=%p, child=%p", parentRepr, childRepr);
222 }
223 }
225 void
226 Deserializer::deserializeEventChgOrder(Glib::ustring const& msg)
227 {
228 // 1. Extract required attributes: node ID, parent ID, new previous node ID.
229 // If we do not know these, return.
230 std::string id, parentid, oldprevid, newprevid;
231 Node buf;
233 buf.tag = MESSAGE_ID;
234 if (MessageUtilities::findTag(buf, msg)) {
235 id = buf.data.raw();
236 } else {
237 return;
238 }
240 buf.tag = MESSAGE_PARENT;
241 if (MessageUtilities::findTag(buf, msg)) {
242 parentid = buf.data.raw();
243 } else {
244 return;
245 }
247 // 2. Extract optional attributes: old previous node, new previous node.
248 buf.tag = MESSAGE_OLDVAL;
249 if (MessageUtilities::findTag(buf, msg)) {
250 oldprevid = buf.data.raw();
251 }
253 buf.tag = MESSAGE_NEWVAL;
254 if (MessageUtilities::findTag(buf, msg)) {
255 newprevid = buf.data.raw();
256 } else {
257 return;
258 }
260 // 3. Find the identified nodes. If we do not know about the parent and child, return.
261 XML::Node* node = this->_getNodeByID(id);
262 XML::Node* parent = this->_getNodeByID(parentid);
263 XML::Node* oldprev = NULL;
264 XML::Node* newprev = NULL;
265 if (!oldprevid.empty()) {
266 oldprev = this->_getNodeByID(oldprevid);
267 }
269 if (!newprevid.empty()) {
270 newprev = this->_getNodeByID(newprevid);
271 }
273 if (parent && node) {
274 // 4. Deserialize the event.
275 this->_builder.setChildOrder(*parent, *node, oldprev, newprev);
276 this->_addOneEvent(this->_builder.detach());
277 } else {
278 return;
279 }
280 }
282 void
283 Deserializer::deserializeEventChgContent(Glib::ustring const& msg)
284 {
285 // 1. Extract required attributes: node ID. If we do not know these, return.
286 std::string id;
287 Util::ptr_shared<char> oldval, newval;
288 Node buf;
290 buf.tag = MESSAGE_ID;
291 if (!MessageUtilities::findTag(buf, msg)) {
292 return;
293 } else {
294 id = buf.data.raw();
295 }
297 // 2. Extract optional attributes: old value, new value.
298 buf.tag = MESSAGE_OLDVAL;
299 if (MessageUtilities::findTag(buf, msg)) {
300 oldval = Util::share_string(buf.data.c_str());
301 } else {
302 oldval = Util::share_static_string("");
303 }
305 buf.tag = MESSAGE_NEWVAL;
306 if (MessageUtilities::findTag(buf, msg)) {
307 newval = Util::share_string(buf.data.c_str());
308 } else {
309 newval = Util::share_static_string("");
310 }
312 // 3. Find the node identified by the ID. If we cannot find it, return.
313 XML::Node* node = this->_getNodeByID(id);
314 if (node == NULL) {
315 return;
316 }
318 // 4. Deserialize the event.
319 this->_builder.setContent(*node, oldval, newval);
320 this->_addOneEvent(this->_builder.detach());
321 }
323 void
324 Deserializer::deserializeEventChgAttr(Glib::ustring const& msg)
325 {
326 // 1. Extract required attributes: node ID, attribute key. If we do not know these,
327 // return.
329 struct Node buf;
330 buf.tag = MESSAGE_ID;
331 if (!MessageUtilities::findTag(buf, msg)) {
332 return;
333 }
335 std::string id = buf.data.data();
337 buf.tag = MESSAGE_KEY;
338 if (!MessageUtilities::findTag(buf, msg)) {
339 return;
340 }
342 Glib::ustring key = buf.data;
344 // 2. Extract optional attributes: new value. If we do not find it in the message,
345 // assume there is no new value.
346 buf.tag = MESSAGE_NEWVAL;
347 Util::ptr_shared<char> newval;
348 if (MessageUtilities::findTag(buf, msg)) {
349 newval = Util::share_string(buf.data.c_str());
350 } else {
351 newval = Util::share_static_string("");
352 }
354 // 3. Extract optional attributes: old value. If we do not find it in the message,
355 // assume that there is no old value.
356 buf.tag = MESSAGE_OLDVAL;
357 Util::ptr_shared<char> oldval;
358 if (MessageUtilities::findTag(buf, msg)) {
359 oldval = Util::share_string(buf.data.c_str());
360 } else {
361 oldval = Util::share_static_string("");
362 }
364 // 4. Look up this node in the local node database and external tracker.
365 // If it cannot be found, return.
366 XML::Node* node = this->_getNodeByID(id);
367 if (node == NULL) {
368 g_warning("Could not find node %s on which to change attribute", id.c_str());
369 return;
370 }
372 // 5. If this node is in the actions queue and is marked as "new", we need to apply
373 // _all_ received attributes to it _before_ adding it to the document tree.
374 if (this->_newnodes.find(id) != this->_newnodes.end()) {
375 node->setAttribute(key.c_str(), newval.pointer());
376 }
378 // 6. Deserialize the event.
379 this->_builder.setAttribute(*node, g_quark_from_string(key.c_str()), oldval, newval);
380 this->_updated.insert(node);
381 this->_addOneEvent(this->_builder.detach());
382 }
384 void
385 Deserializer::_recursiveMarkForRemoval(XML::Node* node)
386 {
387 if (node != NULL) {
388 NodeToKeyMap::iterator i = this->_newkeys.find(node);
389 if (i == this->_newkeys.end()) {
390 std::string id = this->_xnt->get(*node);
391 if (!id.empty()) {
392 this->_actions.push_back(SerializedEventNodeAction(KeyNodePair(id, node), NODE_REMOVE));
393 }
394 } else {
395 this->_actions.push_back(SerializedEventNodeAction(KeyNodePair((*i).second, node), NODE_REMOVE));
396 }
398 for (XML::Node* child = node->firstChild(); child; child = child->next()) {
399 this->_recursiveMarkForRemoval(child);
400 }
401 }
402 }
404 }
406 }
408 /*
409 Local Variables:
410 mode:c++
411 c-file-style:"stroustrup"
412 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
413 indent-tabs-mode:nil
414 fill-column:99
415 End:
416 */
417 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :