Code

094944257338f1430830608e50ac91b9bf4c2698
[inkscape.git] / src / jabber_whiteboard / serializer.cpp
1 /**
2  * Inkboard message -> XML::Event* serializer
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/attribute-record.h"
14 #include "jabber_whiteboard/serializer.h"
16 #include "util/list.h"
17 #include "util/share.h"
19 #include "jabber_whiteboard/message-utilities.h"
20 #include "jabber_whiteboard/message-tags.h"
21 #include "jabber_whiteboard/typedefs.h"
22 #include "jabber_whiteboard/node-tracker.h"
23 #include "jabber_whiteboard/node-utilities.h"
24 #include "jabber_whiteboard/node-tracker-observer.h"
26 namespace Inkscape {
28 namespace Whiteboard {
30 void
31 Serializer::notifyChildAdded(XML::Node& node, XML::Node& child, XML::Node* prev)
32 {
33         // do not recurse upon initial notification
34         this->_newObjectEventHelper(node, child, prev, false);
35         this->_nn.insert(&child);
36 }
38 void
39 Serializer::_newObjectEventHelper(XML::Node& node, XML::Node& child, XML::Node* prev, bool recurse)
40 {
41         // 1.  Check if we are tracking the parent node,
42         // and issue it an ID if we are not.
43         std::string parentid = this->_findOrGenerateNodeID(node);
45         // 2.  Check if the child node is a special node.
46         // Special nodes are nodes that should appear only once in a document.
47         // If it is, we do not want to generate a new ID for the child; we will use
48         // the existing ID.  Otherwise, we will generate a new ID for it, since we 
49         // have not yet seen it.
50         std::string childid;
51         if (this->_xnt->isSpecialNode(child.name())) {
52                 childid = this->_xnt->get(child);
53         } else {
54                 // If the child id already exists in the new node buffer, then we've already seen it.
55                 if (!this->actions.tryToTrack(&child, NODE_ADD)) {
56                                 return;
57                 } else {
58                         childid = this->_xnt->generateKey();
59 //                      childid = this->_findOrGenerateNodeID(child);
60                 }
61         }
63         // 3.  Find this node's previous node, and, if it has one, retrieve its ID.
64         std::string previd;
65         if (prev) {
66                 previd = this->_findOrGenerateNodeID(*prev);
67         }
69         // 4.  Serialize.
70         Glib::ustring childmsg = MessageUtilities::makeTagWithContent(MESSAGE_CHILD, childid);
71         Glib::ustring parentmsg = MessageUtilities::makeTagWithContent(MESSAGE_PARENT, parentid);
72         Glib::ustring namemsg = MessageUtilities::makeTagWithContent(MESSAGE_NAME, child.name());
73         Glib::ustring nodetype = MessageUtilities::makeTagWithContent(MESSAGE_NODETYPE, NodeUtilities::nodeTypeToString(child));
75         Glib::ustring prevmsg;
76         if (!previd.empty()) {
77                 prevmsg = MessageUtilities::makeTagWithContent(MESSAGE_REF, previd);
78         }
80         Glib::ustring buf = MessageUtilities::makeTagWithContent(MESSAGE_NEWOBJ, childmsg + parentmsg + prevmsg + namemsg + nodetype);
83         this->_events.push_back(buf);
85         // 5.  Add the child node to the new nodes buffers.
86         this->newnodes.push_back(SerializedEventNodeAction(KeyNodePair(childid, &child), NODE_ADD));
87         this->newkeys[&child] = childid;
88         this->_parent_child_map[&child] = &node;
90         // 6.  Scan attributes and content.
91         Inkscape::Util::List<Inkscape::XML::AttributeRecord const> attrlist = child.attributeList();
93         for(; attrlist; attrlist++) {
94                 this->notifyAttributeChanged(child, attrlist->key, Util::ptr_shared<char>(), attrlist->value);
95         }
96         
97         if (child.content()) {
98                 this->notifyContentChanged(child, Util::ptr_shared<char>(), Util::share_string(child.content()));
99         }
101         this->_attributes_scanned.insert(childid);
103         // 7.  Repeat this process for each child of this child.
104         if (recurse && child.childCount() > 0) {
105                 XML::Node* prev = child.firstChild();
106                 for(XML::Node* ch = child.firstChild(); ch; ch = ch->next()) {
107                         if (ch == child.firstChild()) {
108                                 // No prev node in this case.
109                                 this->_newObjectEventHelper(child, *ch, NULL, true);
110                         } else {
111                                 this->_newObjectEventHelper(child, *ch, prev, true);
112                                 prev = ch;
113                         }
114                 }
115         }
117         return;
121 void
122 Serializer::notifyChildRemoved(XML::Node& node, XML::Node& child, XML::Node* prev)
124         // 1.  Get the ID of the child.
125         std::string childid;
127         _pc_map_type::iterator i = this->_parent_child_map.find(&child);
128         if (i != this->_parent_child_map.end() && i->second != &node) {
129                 // Don't look in local! Go for the tracker.
130                 childid = this->_xnt->get(child);
131         } else if (i == this->_parent_child_map.end()) {
132                 childid = this->_findOrGenerateNodeID(child);
133         } else if (i->second == &node) {
134                 childid = this->_findOrGenerateNodeID(child);
135                 this->_parent_child_map.erase(i);
136         } else {
137                 childid = this->_findOrGenerateNodeID(child);
138         }
139         
140         // 2.  Double-deletes don't make any sense.  If we've seen this node already and if it's
141         // marked for deletion, return.
142         if (!this->actions.tryToTrack(&child, NODE_REMOVE)) {
143                         return;
144         } else {
145                 // 2a.  Although we do not have to remove all child nodes of this subtree,
146                 // we _do_ have to mark each child node as deleted.
147                 this->_recursiveMarkAsRemoved(child);
148         }
150         // 2.  Mark this node as deleted.  We don't want to be faced with the possibility of 
151         // generating a new key for this deleted node, so insert it into both maps.
152         this->newnodes.push_back(SerializedEventNodeAction(KeyNodePair(childid, &child), NODE_REMOVE));
153         this->newkeys[&child] = childid;
154         this->_nn.erase(&child);
155         std::string parentid = this->_findOrGenerateNodeID(node);
158         // 4.  Serialize the event.
159         this->_attributes_scanned.erase(childid);
160         Glib::ustring childidmsg = MessageUtilities::makeTagWithContent(MESSAGE_CHILD, childid);
161         Glib::ustring parentidmsg = MessageUtilities::makeTagWithContent(MESSAGE_PARENT, parentid);
162         this->_events.push_back(MessageUtilities::makeTagWithContent(MESSAGE_DELETE, childidmsg + parentidmsg));
166 void
167 Serializer::notifyChildOrderChanged(XML::Node& node, XML::Node& child, XML::Node* old_prev, XML::Node* new_prev)
169         // 1.  Find the ID of the node, or generate it if it does not exist.
170         std::string nodeid = this->_findOrGenerateNodeID(child);
171         
172         // 2.  Find the ID of the parent of this node, or generate it if it does not exist.
173         std::string parentid = this->_findOrGenerateNodeID(*(child.parent()));
175         // 3.  Get the ID for the new child reference node, or generate it if it does not exist.
176         std::string newprevid = this->_findOrGenerateNodeID(*new_prev);
178         // 4.  Get the ID for the old child reference node, or generate it if it does not exist.
179         std::string oldprevid = this->_findOrGenerateNodeID(*old_prev);
181         // 5.  Serialize the event.
182         Glib::ustring nodeidmsg = MessageUtilities::makeTagWithContent(MESSAGE_ID, nodeid);
183         Glib::ustring parentidmsg = MessageUtilities::makeTagWithContent(MESSAGE_PARENT, parentid);
184         Glib::ustring oldprevidmsg = MessageUtilities::makeTagWithContent(MESSAGE_OLDVAL, oldprevid);
185         Glib::ustring newprevidmsg = MessageUtilities::makeTagWithContent(MESSAGE_NEWVAL, newprevid);
187         this->_events.push_back(MessageUtilities::makeTagWithContent(MESSAGE_ORDERCHANGE, nodeidmsg + parentidmsg + oldprevidmsg + newprevidmsg));
190 void
191 Serializer::notifyContentChanged(XML::Node& node, Util::ptr_shared<char> old_content, Util::ptr_shared<char> new_content)
193         // 1.  Find the ID of the node, or generate it if it does not exist.
194         std::string nodeid = this->_findOrGenerateNodeID(node);
196         std::string oldvalmsg, newvalmsg;
198         // 2.  If the old and new content are identical, don't send out this change.
199         // (identical meaning "same string" or "same string content")
200         if (old_content == new_content) {
201                 return;
202         }
204         if (old_content.pointer() != NULL && new_content.pointer() != NULL) {
205                 if (strcmp(old_content.pointer(), new_content.pointer()) == 0) {
206                         return;
207                 }
208         }
210         // 3.  Serialize the event.
211         if (old_content.pointer() != NULL) {
212                 oldvalmsg = MessageUtilities::makeTagWithContent(MESSAGE_OLDVAL, old_content.pointer());
213         }
215         if (new_content.pointer() != NULL) {
216                 newvalmsg = MessageUtilities::makeTagWithContent(MESSAGE_NEWVAL, new_content.pointer());
217         }
219         Glib::ustring nodeidmsg = MessageUtilities::makeTagWithContent(MESSAGE_ID, nodeid);
220         this->_events.push_back(MessageUtilities::makeTagWithContent(MESSAGE_NODECONTENT, nodeidmsg + oldvalmsg + newvalmsg));
223 void
224 Serializer::notifyAttributeChanged(XML::Node& node, GQuark name, Util::ptr_shared<char> old_value, Util::ptr_shared<char> new_value)
226         // 1.  Find the ID of the node that has had an attribute modified, or generate it if it
227         // does not exist.
228         std::string nodeid = this->_findOrGenerateNodeID(node);
230         // Proceed with 2-4 if the node has not already been scanned by notifyChildAdded.
231         if (this->_attributes_scanned.find(nodeid) == this->_attributes_scanned.end()) {
232                 // 2.  Convert the key to a string.
233                 Glib::ustring key = g_quark_to_string(name);
235                 // 3.  If oldval == newval, don't echo this change.
236                 if (new_value.pointer() != NULL && old_value.pointer() != NULL) {
237                         if (strcmp(new_value.pointer(), old_value.pointer()) == 0) {
238                                 return;
239                         }
240                 }
242                 // 4.  Serialize the event.
243                 Glib::ustring keymsg = MessageUtilities::makeTagWithContent(MESSAGE_KEY, key);
244                 Glib::ustring oldvalmsg, newvalmsg;
246                 if (old_value.pointer() != NULL) {
247                         oldvalmsg = MessageUtilities::makeTagWithContent(MESSAGE_OLDVAL, old_value.pointer());
248                 }
250                 if (new_value.pointer() != NULL) {
251                         newvalmsg = MessageUtilities::makeTagWithContent(MESSAGE_NEWVAL, new_value.pointer());
252                 }
254                 Glib::ustring nodeidmsg = MessageUtilities::makeTagWithContent(MESSAGE_ID, nodeid);
256                 this->_events.push_back(MessageUtilities::makeTagWithContent(MESSAGE_CHANGE, nodeidmsg + keymsg + oldvalmsg + newvalmsg));
257         }
260 void
261 Serializer::synthesizeChildNodeAddEvents()
263         _New_nodes_type::iterator i = this->_nn.begin();
264         for(; i != this->_nn.end(); ++i) {
265                 XML::Node* parent = *i;
266                 // The root of the subtree defined by parent has already been considered; now,
267                 // recursively look at the rest of the tree.
268                 XML::Node* prev = parent->firstChild();
269                 for(XML::Node* ch = parent->firstChild(); ch; ch = ch->next()) {
270                         if (ch == parent->firstChild()) {
271                                 this->_newObjectEventHelper(*parent, *ch, NULL, true);
272                         } else {
273                                 this->_newObjectEventHelper(*parent, *ch, prev, true);
274                                 prev = ch;
275                         }
276                 }
277         }
281 void
282 Serializer::_recursiveMarkAsRemoved(XML::Node& node)
284         this->actions.tryToTrack(&node, NODE_REMOVE);
286         for(XML::Node* ch = node.firstChild(); ch; ch = ch->next()) {
287                 this->_recursiveMarkAsRemoved(*ch);
288         }
295 /*
296   Local Variables:
297   mode:c++
298   c-file-style:"stroustrup"
299   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
300   indent-tabs-mode:nil
301   fill-column:99
302   End:
303 */
304 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :