Code

replace Util::SharedCStringPtr with the more general Util::shared_ptr<>
[inkscape.git] / src / jabber_whiteboard / deserializer.cpp
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;
119         
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);
161 void
162 Deserializer::deserializeEventDel(Glib::ustring const& msg)
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         }
225 void
226 Deserializer::deserializeEventChgOrder(Glib::ustring const& msg)
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         }
282 void
283 Deserializer::deserializeEventChgContent(Glib::ustring const& msg)
285         // 1.  Extract required attributes: node ID.  If we do not know these, return.
286         std::string id;
287         Util::shared_ptr<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("");
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("");
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());
323 void
324 Deserializer::deserializeEventChgAttr(Glib::ustring const& msg)
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::shared_ptr<char> newval;
348         if (MessageUtilities::findTag(buf, msg)) {
349                 newval = Util::share_string(buf.data.c_str());
350         } else {
351                 newval = Util::share_static("");
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::shared_ptr<char> oldval;
358         if (MessageUtilities::findTag(buf, msg)) {
359                 oldval = Util::share_string(buf.data.c_str());
360         } else {
361                 oldval = Util::share_static("");
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.cString());      
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());
384 void 
385 Deserializer::_recursiveMarkForRemoval(XML::Node* node)
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         }
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 :