Code

removed string localisation
[inkscape.git] / src / jabber_whiteboard / message-utilities.cpp
1 /**
2  * Message generation utilities
3  * 
4  * Authors:
5  * David Yip <yipdw@rose-hulman.edu>
6  * Jonas Collaros, Stephen Montgomery
7  *
8  * Copyright (c) 2004-2005 Authors
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
13 #include <glibmm/i18n.h>
15 #include "util/share.h"
16 #include "util/list.h"
18 #include "xml/node.h"
19 #include "xml/attribute-record.h"
20 #include "xml/repr.h"
22 #include "jabber_whiteboard/defines.h"
23 #include "jabber_whiteboard/typedefs.h"
24 #include "jabber_whiteboard/node-utilities.h"
25 #include "jabber_whiteboard/message-utilities.h"
26 #include "jabber_whiteboard/node-tracker.h"
28 #include <iostream>
30 namespace Inkscape {
32 namespace Whiteboard {
34 // This method can be instructed to not build a message string but only collect nodes that _would_ be transmitted
35 // and subsequently added to the tracker.  This can be useful in the case where an Inkboard user is the only one
36 // in a chatroom and therefore needs to fill out the node tracker, but does not need to build the message string.
37 // This can be controlled with the only_collect_nodes flag, which will only create pointers to new XML::Nodes 
38 // in the maps referenced by newidsbuf and newnodesbuf.  Passing NULL as the message buffer has the same effect.
39 //
40 // only_collect_nodes defaults to false because most invocations of this method also use the message string.
41 void
42 MessageUtilities::newObjectMessage(Glib::ustring &msgbuf, 
43                        KeyNodeTable& newnodesbuf,
44                        NewChildObjectMessageList& childmsgbuf, 
45                        XMLNodeTracker* xmt, 
46                        Inkscape::XML::Node const* node,
47                        bool only_collect_nodes,
48                        bool collect_children)
49 {
50         // Initialize pointers
51         Glib::ustring id, refid, parentid;
53         gchar const* name = NULL;
54         XML::Node* parent = NULL;
55         XML::Node* ref = NULL;
57         bool only_add_children = false;
59         //g_log(NULL, G_LOG_LEVEL_DEBUG, "newObjectMessage: processing node %p of type %s", node, NodeUtilities::nodeTypeToString(*node).data());
61         if (node != NULL) {
62                 parent = sp_repr_parent(node);
63                 if (parent != NULL) {
64                         //g_log(NULL, G_LOG_LEVEL_DEBUG, "Attempting to find ID for parent node %p (on node %p)", parent, node);
65                         parentid = NodeUtilities::findNodeID(*parent, xmt, newnodesbuf);
66                         if (parentid.empty()) {
67                                 g_warning("Parent %p is not being tracked, creating new ID", parent);
68                                 parentid = xmt->generateKey();
69                                 newnodesbuf.put(parentid, parent);
70                         }
72                         if ( node != parent->firstChild() && parent != NULL ) {
73                                 ref = parent->firstChild();
74                                 while (ref->next() != node) {
75                                         ref = ref->next();
76                                 }
77                         }       
78                 }
80                 if (ref != NULL) {
81                         //g_log(NULL, G_LOG_LEVEL_DEBUG, "Attempting to find ID for ref node %p (on %p)", ref, node);
82                         refid = NodeUtilities::findNodeID(*ref, xmt, newnodesbuf);
83                         if (refid.empty() && ref != NULL) {
84                                 g_warning("Ref %p is not being tracked, creating new ID", ref);
85                                 refid = xmt->generateKey();
86                                 newnodesbuf.put(refid, ref);
87                         }
88                 }
90                 name = static_cast< gchar const* >(node->name());
91         }
93         // Generate an id for this object and append it onto the list, if 
94         // it's not already in the tracker
95         if (!xmt->isSpecialNode(node->name())) {
96                 if (!xmt->isTracking(*node)) {
97                         id = xmt->generateKey();        
98                         //g_log(NULL, G_LOG_LEVEL_DEBUG, "Inserting %p with id %s", node, id.c_str());
99                         newnodesbuf.put(id, node);
100                 } else {
101                         id = xmt->get(*node);
102                 //g_log(NULL, G_LOG_LEVEL_DEBUG, "Found id %s for node %p; not inserting into new nodes buffers.", id.c_str(), node);
103                 }
104         } else {
105                 //g_log(NULL, G_LOG_LEVEL_DEBUG, "Processing special node; not generating key");
106                 id = xmt->get(*node);
107                 if (id.empty()) {
108                         g_warning("Node %p (name %s) is a special node, but it could not be found in the node tracker (possible unexpected duplicate?)  Generating unique ID anyway.", node, node->name());
109                         id = xmt->generateKey();
110                         newnodesbuf.put(id, node);
111                 }
112                 only_add_children = true;
113         }
115         // If we're only adding children (i.e. this is a special node)
116         // don't process the given node.
117         if( !only_add_children && !id.empty() && msgbuf != NULL && !only_collect_nodes ) {
118                 // <MESSAGE_NEWOBJ>
119                 msgbuf = msgbuf + "<" + MESSAGE_NEWOBJ + ">";
121                 // <MESSAGE_PARENT>
122                 msgbuf = msgbuf + "<" + MESSAGE_PARENT + ">";
124                 if(!parentid.empty()) {
125                         msgbuf += parentid;
126                 }
128                 // </MESSAGE_NEWOBJ><MESSAGE_CHILD>id</MESSAGE_CHILD>
129                 msgbuf = msgbuf + "</" + MESSAGE_PARENT + ">";
131                 msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">";
132                 msgbuf += id;
134                 msgbuf = msgbuf + "</" + MESSAGE_CHILD + ">";
136                 if(!refid.empty()) {
137                         // <MESSAGE_REF>refid</MESSAGE_REF>
138                         msgbuf = msgbuf + "<" + MESSAGE_REF + ">";
139                         
140                         msgbuf += refid;
142                         msgbuf = msgbuf + "</" + MESSAGE_REF + ">";
143                 }
145                 // <MESSAGE_NODETYPE>*node.type()</MESSAGE_NODETYPE>
146                 msgbuf = msgbuf + "<" + MESSAGE_NODETYPE + ">" + NodeUtilities::nodeTypeToString(*node);
147                 msgbuf = msgbuf + "</" + MESSAGE_NODETYPE + ">";
149                 if (node->content() != NULL) {
150                         // <MESSAGE_CONTENT>node->content()</MESSAGE_CONTENT>
151                         msgbuf = msgbuf + "<" + MESSAGE_CONTENT + ">" + node->content();
152                         msgbuf = msgbuf + "</" + MESSAGE_CONTENT + ">";
153                 }
155                 // <MESSAGE_NAME>name</MESSAGE_NAME>
156                 msgbuf = msgbuf + "<" + MESSAGE_NAME + ">";
158                 if( name != NULL )
159                         msgbuf += name;
161                 msgbuf = msgbuf + "</" + MESSAGE_NAME + ">";
163                 // </MESSAGE_NEWOBJ>
164                 msgbuf = msgbuf + "</" + MESSAGE_NEWOBJ + ">";
165         } else if (id.empty()) {
166                 // if ID is NULL, then we have a real problem -- we were not able to find a key
167                 // nor generate one.  The only thing we can really do here is abort, since we have
168                 // no way to let the other client(s) uniquely identify this object.
169                 g_warning(_("ID for new object is NULL even after generation and lookup attempts: the new object will NOT be sent, nor will any of its child objects!"));
170                 return;
171         } else {
173         }
175         //g_log(NULL, G_LOG_LEVEL_DEBUG, "Generated message");
177         if (!only_collect_nodes && msgbuf != NULL && !id.empty()) {
178                 // Collect new object's attributes and append them onto the msgbuf
179                 Inkscape::Util::List<Inkscape::XML::AttributeRecord const> attrlist = node->attributeList();
181                 for(; attrlist; attrlist++) {
182                         MessageUtilities::objectChangeMessage(msgbuf,
183                          xmt, id, g_quark_to_string(attrlist->key),
184                           NULL, attrlist->value, false);
185                 }
186         }
188         if (!only_collect_nodes)
189                 childmsgbuf.push_back(msgbuf);
191         if (!id.empty() && collect_children) {
192                 Glib::ustring childbuf;
193                 // Collect any child objects of this new object
194                 for ( Inkscape::XML::Node const *child = node->firstChild(); child != NULL; child = child->next() ) {
195                         childbuf.clear();
196                         MessageUtilities::newObjectMessage(childbuf,
197                         newnodesbuf, childmsgbuf, xmt, child, only_collect_nodes);
198                         if (!only_collect_nodes) {
199                                 // we're recursing down the tree, so we're picking up child nodes first
200                                 // and parents afterwards
201 //                              childmsgbuf.push_front(childbuf);
202                         }
204                 }
205         }
208 void
209 MessageUtilities::objectChangeMessage(Glib::ustring &msgbuf, 
210                                     XMLNodeTracker* xmt, 
211                                     const Glib::ustring &id, 
212                                     gchar const* key, 
213                                     gchar const* oldval, 
214                                     gchar const* newval, 
215                                     bool is_interactive)
217     // Construct message
219     // <MESSAGE_CHANGE><MESSAGE_ID>id</MESSAGE_ID>
220     msgbuf = msgbuf + "<" + MESSAGE_CHANGE + ">";
221     msgbuf = msgbuf + "<" + MESSAGE_ID + ">";
222     msgbuf += id;
223     msgbuf = msgbuf + "</" + MESSAGE_ID + ">";
225     // <MESSAGE_KEY>key</MESSAGE_KEY>
226     msgbuf = msgbuf + "<" + MESSAGE_KEY + ">";
227     if (key != NULL) {
228             msgbuf += key;
229     }
230     msgbuf = msgbuf + "</" + MESSAGE_KEY + ">";
232     // <MESSAGE_OLDVAL>oldval</MESSAGE_OLDVAL>
233     msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">";
234     if (oldval != NULL) {
235             msgbuf += oldval;
236     }
237     msgbuf = msgbuf + "</" + MESSAGE_OLDVAL + ">";
239     // <MESSAGE_NEWVAL>newval</MESSAGE_NEWVAL>
240     msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">";
241     if (newval != NULL) {
242             msgbuf += newval;
243     }
244     msgbuf = msgbuf + "</" + MESSAGE_NEWVAL + ">";
246     // <MESSAGE_ISINTERACTIVE>is_interactive</MESSAGE_ISINTERACTIVE>
247     msgbuf = msgbuf + "<" + MESSAGE_ISINTERACTIVE + ">";
248     if (is_interactive) {
249             msgbuf += "true";
250     } else {
251             msgbuf += "false";
252     }
253     msgbuf = msgbuf + "</" + MESSAGE_ISINTERACTIVE + ">";
255     // </MESSAGE_CHANGE>
256     msgbuf = msgbuf + "</" + MESSAGE_CHANGE + ">";
259 void
260 MessageUtilities::objectDeleteMessage(Glib::ustring &msgbuf, 
261                             XMLNodeTracker* xmt,
262                             Inkscape::XML::Node const& parent,
263                             Inkscape::XML::Node const& child,
264                             Inkscape::XML::Node const* prev)
266     /*
267     gchar const* parentid = NULL;
268     gchar const* previd = NULL;
269     gchar const* childid = NULL;
271     childid = child.attribute("id");
272     parentid = parent.attribute("id");
273     if (prev != NULL) {
274             previd = prev->attribute("id");
275     }*/
277     Glib::ustring parentid, previd, childid;
279     childid = xmt->get(child);
280     parentid = xmt->get(parent);
281     previd = xmt->get(*prev);
283     if (childid.empty())
284         return;
285             
286  
287      // <MESSAGE_DELETE><MESSAGE_PARENT>parentid</MESSAGE_PARENT>
288      msgbuf = msgbuf + "<" + MESSAGE_DELETE + ">" + "<" + MESSAGE_PARENT + ">";
289      if (!parentid.empty()) {
290              msgbuf += parentid;
291      }
292      msgbuf = msgbuf + "</" + MESSAGE_PARENT + ">";
294      // <MESSAGE_CHILD>childid</MESSAGE_CHILD>
295      msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">";
296      if (!childid.empty()) {
297              msgbuf += childid;
298      }
299      msgbuf = msgbuf + "</" + MESSAGE_CHILD + ">";
301      // <MESSAGE_REF>previd</MESSAGE_REF>
302      msgbuf = msgbuf + "<" + MESSAGE_REF + ">";
303      if (!previd.empty()) {
304              msgbuf += previd;
305      }
306      msgbuf = msgbuf + "</" + MESSAGE_REF + ">";
308      // </MESSAGE_DELETE>
309      msgbuf = msgbuf + "</" + MESSAGE_DELETE + ">";
312 void
313 MessageUtilities::contentChangeMessage(Glib::ustring& msgbuf, 
314                        const Glib::ustring &nodeid, 
315                        Util::ptr_shared<char> old_value,
316                        Util::ptr_shared<char> new_value)
318     if (nodeid.empty())
319         return;
320         
321      // <MESSAGE_NODECONTENT>
322      msgbuf = msgbuf + "<" + MESSAGE_NODECONTENT + ">";
324      // <MESSAGE_ID>nodeid</MESSAGE_ID>
325      msgbuf = msgbuf + "<" + MESSAGE_ID + ">";
326      msgbuf += nodeid;
327      msgbuf = msgbuf + "</" + MESSAGE_ID + ">";
329      // <MESSAGE_OLDVAL>old_value</MESSAGE_OLDVAL>
330      msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">";
331      msgbuf += old_value.pointer();
332      msgbuf = msgbuf + "</" + MESSAGE_OLDVAL + ">";
334      // <MESSAGE_NEWVAL>new_value</MESSAGE_NEWVAL>
335      msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">";
336      msgbuf += new_value.pointer();
337      msgbuf = msgbuf + "</" + MESSAGE_NEWVAL + ">";
339      // </MESSAGE_NODECONTENT>
340      msgbuf = msgbuf + "</" + MESSAGE_NODECONTENT + ">";
343 void
344 MessageUtilities::childOrderChangeMessage(Glib::ustring& msgbuf, 
345                           const Glib::ustring &childid, 
346                           const Glib::ustring &oldprevid, 
347                           const Glib::ustring &newprevid)
349     if (childid.empty())
350         return;
351         
352     // <MESSAGE_ORDERCHANGE>
353     msgbuf = msgbuf + "<" + MESSAGE_ORDERCHANGE + ">";
355     // <MESSAGE_ID>nodeid</MESSAGE_ID>
356     msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">";
357     msgbuf += childid;
358     msgbuf = msgbuf + "</" + MESSAGE_CHILD + ">";
360     // <MESSAGE_OLDVAL>oldprevid</MESSAGE_OLDVAL>
361     /*
362     msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">";
363     msgbuf += (*oldprevid);
364     msgbuf = msgbuf + "</" + MESSAGE_OLDVAL + ">";
365     */
367     // <MESSAGE_NEWVAL>newprevid</MESSAGE_NEWVAL>
368     msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">";
369     msgbuf += newprevid;
370     msgbuf = msgbuf + "</" + MESSAGE_NEWVAL + ">";
372     // </MESSAGE_ORDERCHANGE>
373     msgbuf = msgbuf + "</" + MESSAGE_ORDERCHANGE + ">";
378 bool
379 MessageUtilities::getFirstMessageTag(struct Node& buf, const Glib::ustring &msg)
381     if (msg.empty())
382         return false;
384     // See if we have a valid start tag, i.e. < ... >.  If we do,
385     // continue; if not, stop and return NULL.
386     //
387     // find_first_of returns ULONG_MAX when it cannot find the first
388     // instance of the given character.
390     Glib::ustring::size_type startDelim = msg.find_first_of('<');
391     if (startDelim != ULONG_MAX) {
392             Glib::ustring::size_type endDelim = msg.find_first_of('>');
393             if (endDelim != ULONG_MAX) {
394                     if (endDelim > startDelim) {
395                             buf.tag = msg.substr(startDelim+1, (endDelim-startDelim)-1);
396                             if (buf.tag.find_first_of('/') == ULONG_MAX) { // start tags should not be end tags
399                                     // construct end tag (</buf.data>)
400                                     Glib::ustring endTag(buf.tag);
401                                     endTag.insert(0, "/");
403                                     Glib::ustring::size_type endTagLoc = msg.find(endTag, endDelim);
404                                     if (endTagLoc != ULONG_MAX) {
405                                             buf.data = msg.substr(endDelim+1, ((endTagLoc - 1) - (endDelim + 1)));
406                                             buf.next_pos = endTagLoc + endTag.length() + 1;
408                                             return true;
409                                     }
410                             }
411                     }
412             }
413     }
415     return false;
418 bool
419 MessageUtilities::findTag(struct Node& buf, const Glib::ustring &msg)
421     if (msg.empty())
422         return false;
424     // Read desired tag type out of buffer, and append
425     // < > to it 
427     Glib::ustring searchterm("<");
428     searchterm += buf.tag;
429     searchterm + ">";
431     Glib::ustring::size_type tagStart = msg.find(searchterm, 0);
432     if (tagStart != ULONG_MAX) {
433             // Find ending tag starting at the point at the end of
434             // the start tag.
435             searchterm.insert(1, "/");
436             Glib::ustring::size_type tagEnd = msg.find(searchterm, tagStart + searchterm.length());
437             if (tagEnd != ULONG_MAX) {
438                     Glib::ustring::size_type start = tagStart + searchterm.length();
439                     buf.data = msg.substr(start, tagEnd - start);
440                     return true;
441             }
442     }
443     return false;
446 Glib::ustring
447 MessageUtilities::makeTagWithContent(const Glib::ustring &tagname,
448                                      const Glib::ustring &content)
450     Glib::ustring buf = "<" + tagname + ">";
451     buf += content;
452     buf += "</" + tagname + ">";
453     return buf;
463 /*
464   Local Variables:
465   mode:c++
466   c-file-style:"stroustrup"
467   c-file-offsets:((innamespace . 0)(inline-open . 0))
468   indent-tabs-mode:nil
469   fill-column:99
470   End:
471 */
472 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :