summaryrefslogtreecommitdiffstats
path: root/src/jabber_whiteboard/message-utilities.cpp
diff options
context:
space:
mode:
authorMenTaLguY <mental@rydia.net>2006-01-16 02:36:01 +0000
committermental <mental@users.sourceforge.net>2006-01-16 02:36:01 +0000
commit179fa413b047bede6e32109e2ce82437c5fb8d34 (patch)
treea5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/jabber_whiteboard/message-utilities.cpp
downloadinkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz
inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/jabber_whiteboard/message-utilities.cpp')
-rw-r--r--src/jabber_whiteboard/message-utilities.cpp452
1 files changed, 452 insertions, 0 deletions
diff --git a/src/jabber_whiteboard/message-utilities.cpp b/src/jabber_whiteboard/message-utilities.cpp
new file mode 100644
index 000000000..431545ac0
--- /dev/null
+++ b/src/jabber_whiteboard/message-utilities.cpp
@@ -0,0 +1,452 @@
+/**
+ * Message generation utilities
+ *
+ * Authors:
+ * David Yip <yipdw@rose-hulman.edu>
+ * Jonas Collaros, Stephen Montgomery
+ *
+ * Copyright (c) 2004-2005 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glibmm/i18n.h>
+
+#include "util/shared-c-string-ptr.h"
+#include "util/list.h"
+
+#include "xml/node.h"
+#include "xml/attribute-record.h"
+#include "xml/repr.h"
+
+#include "jabber_whiteboard/defines.h"
+#include "jabber_whiteboard/typedefs.h"
+#include "jabber_whiteboard/node-utilities.h"
+#include "jabber_whiteboard/message-utilities.h"
+#include "jabber_whiteboard/node-tracker.h"
+
+#include <iostream>
+
+namespace Inkscape {
+
+namespace Whiteboard {
+
+// This method can be instructed to not build a message string but only collect nodes that _would_ be transmitted
+// and subsequently added to the tracker. This can be useful in the case where an Inkboard user is the only one
+// in a chatroom and therefore needs to fill out the node tracker, but does not need to build the message string.
+// This can be controlled with the only_collect_nodes flag, which will only create pointers to new XML::Nodes
+// in the maps referenced by newidsbuf and newnodesbuf. Passing NULL as the message buffer has the same effect.
+//
+// only_collect_nodes defaults to false because most invocations of this method also use the message string.
+void
+MessageUtilities::newObjectMessage(Glib::ustring* msgbuf, KeyToNodeMap& newidsbuf, NodeToKeyMap& newnodesbuf, NewChildObjectMessageList& childmsgbuf, XMLNodeTracker* xmt, Inkscape::XML::Node const* node, bool only_collect_nodes, bool collect_children)
+{
+ // Initialize pointers
+ std::string id, refid, parentid;
+
+ gchar const* name = NULL;
+ XML::Node* parent = NULL;
+ XML::Node* ref = NULL;
+
+ bool only_add_children = false;
+
+
+ if (node != NULL) {
+ parent = sp_repr_parent(node);
+ if (parent != NULL) {
+ parentid = NodeUtilities::findNodeID(*parent, xmt, newnodesbuf);
+ if (parentid.empty()) {
+ g_warning("Parent %p is not being tracked, creating new ID", parent);
+ parentid = xmt->generateKey();
+ newidsbuf[parentid] = parent;
+ newnodesbuf[parent] = parentid;
+ }
+
+ if ( node != parent->firstChild() && parent != NULL ) {
+ ref = parent->firstChild();
+ while (ref->next() != node) {
+ ref = ref->next();
+ }
+ }
+ }
+
+ if (ref != NULL) {
+ refid = NodeUtilities::findNodeID(*ref, xmt, newnodesbuf);
+ if (refid.empty() && ref != NULL) {
+ g_warning("Ref %p is not being tracked, creating new ID", ref);
+ refid = xmt->generateKey();
+ newidsbuf[refid] = ref;
+ newnodesbuf[ref] = refid;
+ }
+ }
+
+ name = static_cast< gchar const* >(node->name());
+ }
+
+ // Generate an id for this object and append it onto the list, if
+ // it's not already in the tracker
+ if (!xmt->isSpecialNode(node->name())) {
+ if (!xmt->isTracking(*node)) {
+ id = xmt->generateKey();
+ newidsbuf[id] = node;
+ newnodesbuf[node] = id;
+ } else {
+ id = xmt->get(*node);
+ }
+ } else {
+ id = xmt->get(*node);
+ if (id.empty()) {
+ 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());
+ id = xmt->generateKey();
+ newidsbuf[id] = node;
+ newnodesbuf[node] = id;
+ }
+ only_add_children = true;
+ }
+
+ // If we're only adding children (i.e. this is a special node)
+ // don't process the given node.
+ if( !only_add_children && !id.empty() && msgbuf != NULL && !only_collect_nodes ) {
+ // <MESSAGE_NEWOBJ>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_NEWOBJ + ">";
+
+ // <MESSAGE_PARENT>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_PARENT + ">";
+
+ if(!parentid.empty()) {
+ (*msgbuf) += parentid;
+ }
+
+ // </MESSAGE_NEWOBJ><MESSAGE_CHILD>id</MESSAGE_CHILD>
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_PARENT + ">";
+
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_CHILD + ">";
+ (*msgbuf) += id;
+
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_CHILD + ">";
+
+ if(!refid.empty()) {
+ // <MESSAGE_REF>refid</MESSAGE_REF>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_REF + ">";
+
+ (*msgbuf) += refid;
+
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_REF + ">";
+ }
+
+ // <MESSAGE_NODETYPE>*node.type()</MESSAGE_NODETYPE>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_NODETYPE + ">" + NodeUtilities::nodeTypeToString(*node);
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_NODETYPE + ">";
+
+ if (node->content() != NULL) {
+ // <MESSAGE_CONTENT>node->content()</MESSAGE_CONTENT>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_CONTENT + ">" + node->content();
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_CONTENT + ">";
+ }
+
+ // <MESSAGE_NAME>name</MESSAGE_NAME>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_NAME + ">";
+
+ if( name != NULL ) {
+ (*msgbuf) += name;
+ }
+
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_NAME + ">";
+
+ // </MESSAGE_NEWOBJ>
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_NEWOBJ + ">";
+ } else if (id.empty()) {
+ // if ID is NULL, then we have a real problem -- we were not able to find a key
+ // nor generate one. The only thing we can really do here is abort, since we have
+ // no way to let the other client(s) uniquely identify this object.
+ /* FIXME: If this indicates a programming bug, then don't request translation with
+ * _(...): it is most useful in untranslated form so that developers may search for
+ * it when someone reports it in a bug report (as we want users to do for all bugs,
+ * as indicated by it being a g_warning string).
+ *
+ * Otherwise, if it is not a programming bug but a network error or a bug in the
+ * remote peer (perhaps running different software) or whatever, then present it in
+ * an alert box, and avoid use of technical jargon `NULL'.
+ */
+ 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!"));
+ return;
+ } else {
+
+ }
+
+
+ if (!only_collect_nodes && msgbuf != NULL && !id.empty()) {
+ // Collect new object's attributes and append them onto the msgbuf
+ Inkscape::Util::List<Inkscape::XML::AttributeRecord const> attrlist = node->attributeList();
+
+ for(; attrlist; attrlist++) {
+ MessageUtilities::objectChangeMessage(msgbuf, xmt, id, g_quark_to_string(attrlist->key), NULL, attrlist->value, false);
+ }
+ }
+
+ if (!only_collect_nodes) {
+ childmsgbuf.push_back(*msgbuf);
+ }
+
+ if (!id.empty() && collect_children) {
+ Glib::ustring childbuf;
+ // Collect any child objects of this new object
+ for ( Inkscape::XML::Node const *child = node->firstChild(); child != NULL; child = child->next() ) {
+ childbuf.clear();
+ MessageUtilities::newObjectMessage(&childbuf, newidsbuf, newnodesbuf, childmsgbuf, xmt, child, only_collect_nodes);
+ if (!only_collect_nodes) {
+ // we're recursing down the tree, so we're picking up child nodes first
+ // and parents afterwards
+// childmsgbuf.push_front(childbuf);
+ }
+
+ }
+ }
+}
+
+void
+MessageUtilities::objectChangeMessage(ustring* msgbuf, XMLNodeTracker* xmt, std::string const id, gchar const* key, gchar const* oldval, gchar const* newval, bool is_interactive)
+{
+ // Construct message
+
+ // <MESSAGE_CHANGE><MESSAGE_ID>id</MESSAGE_ID>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_CHANGE + ">";
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_ID + ">";
+ (*msgbuf) += id;
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_ID + ">";
+
+ // <MESSAGE_KEY>key</MESSAGE_KEY>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_KEY + ">";
+ if (key != NULL) {
+ (*msgbuf) += key;
+ }
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_KEY + ">";
+
+ // <MESSAGE_OLDVAL>oldval</MESSAGE_OLDVAL>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_OLDVAL + ">";
+ if (oldval != NULL) {
+ (*msgbuf) += oldval;
+ }
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_OLDVAL + ">";
+
+ // <MESSAGE_NEWVAL>newval</MESSAGE_NEWVAL>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_NEWVAL + ">";
+ if (newval != NULL) {
+ (*msgbuf) += newval;
+ }
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_NEWVAL + ">";
+
+ // <MESSAGE_ISINTERACTIVE>is_interactive</MESSAGE_ISINTERACTIVE>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_ISINTERACTIVE + ">";
+ if (is_interactive) {
+ (*msgbuf) += "true";
+ } else {
+ (*msgbuf) += "false";
+ }
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_ISINTERACTIVE + ">";
+
+ // </MESSAGE_CHANGE>
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_CHANGE + ">";
+}
+
+void
+MessageUtilities::objectDeleteMessage(Glib::ustring* msgbuf, XMLNodeTracker* xmt, Inkscape::XML::Node const& parent, Inkscape::XML::Node const& child, Inkscape::XML::Node const* prev)
+{
+ /*
+ gchar const* parentid = NULL;
+ gchar const* previd = NULL;
+ gchar const* childid = NULL;
+
+ childid = child.attribute("id");
+ parentid = parent.attribute("id");
+ if (prev != NULL) {
+ previd = prev->attribute("id");
+ }*/
+
+ std::string parentid, previd, childid;
+
+ childid = xmt->get(child);
+ parentid = xmt->get(parent);
+ previd = xmt->get(*prev);
+
+ if (!childid.empty()) {
+ // <MESSAGE_DELETE><MESSAGE_PARENT>parentid</MESSAGE_PARENT>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_DELETE + ">" + "<" + MESSAGE_PARENT + ">";
+ if (!parentid.empty()) {
+ (*msgbuf) += parentid;
+ }
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_PARENT + ">";
+
+ // <MESSAGE_CHILD>childid</MESSAGE_CHILD>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_CHILD + ">";
+ if (!childid.empty()) {
+ (*msgbuf) += childid;
+ }
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_CHILD + ">";
+
+ // <MESSAGE_REF>previd</MESSAGE_REF>
+ (*msgbuf) = (*msgbuf) + "<" + MESSAGE_REF + ">";
+ if (!previd.empty()) {
+ (*msgbuf) += previd;
+ }
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_REF + ">";
+
+ // </MESSAGE_DELETE>
+ (*msgbuf) = (*msgbuf) + "</" + MESSAGE_DELETE + ">";
+ }
+}
+
+void
+MessageUtilities::contentChangeMessage(Glib::ustring& msgbuf, std::string const nodeid, Util::SharedCStringPtr old_value, Util::SharedCStringPtr new_value)
+{
+ if (!nodeid.empty()) {
+ // <MESSAGE_NODECONTENT>
+ msgbuf = msgbuf + "<" + MESSAGE_NODECONTENT + ">";
+
+ // <MESSAGE_ID>nodeid</MESSAGE_ID>
+ msgbuf = msgbuf + "<" + MESSAGE_ID + ">";
+ msgbuf += nodeid;
+ msgbuf = msgbuf + "</" + MESSAGE_ID + ">";
+
+ // <MESSAGE_OLDVAL>old_value</MESSAGE_OLDVAL>
+ msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">";
+ msgbuf += old_value.cString();
+ msgbuf = msgbuf + "</" + MESSAGE_OLDVAL + ">";
+
+ // <MESSAGE_NEWVAL>new_value</MESSAGE_NEWVAL>
+ msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">";
+ msgbuf += new_value.cString();
+ msgbuf = msgbuf + "</" + MESSAGE_NEWVAL + ">";
+
+ // </MESSAGE_NODECONTENT>
+ msgbuf = msgbuf + "</" + MESSAGE_NODECONTENT + ">";
+ }
+}
+
+void
+MessageUtilities::childOrderChangeMessage(Glib::ustring& msgbuf, std::string const childid, std::string const oldprevid, std::string const newprevid)
+{
+ if (!childid.empty()) {
+ // <MESSAGE_ORDERCHANGE>
+ msgbuf = msgbuf + "<" + MESSAGE_ORDERCHANGE + ">";
+
+ // <MESSAGE_ID>nodeid</MESSAGE_ID>
+ msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">";
+ msgbuf += childid;
+ msgbuf = msgbuf + "</" + MESSAGE_CHILD + ">";
+
+ // <MESSAGE_OLDVAL>oldprevid</MESSAGE_OLDVAL>
+ /*
+ msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">";
+ msgbuf += (*oldprevid);
+ msgbuf = msgbuf + "</" + MESSAGE_OLDVAL + ">";
+ */
+
+ // <MESSAGE_NEWVAL>newprevid</MESSAGE_NEWVAL>
+ msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">";
+ msgbuf += newprevid;
+ msgbuf = msgbuf + "</" + MESSAGE_NEWVAL + ">";
+
+ // </MESSAGE_ORDERCHANGE>
+ msgbuf = msgbuf + "</" + MESSAGE_ORDERCHANGE + ">";
+ }
+}
+
+
+bool
+MessageUtilities::getFirstMessageTag(struct Node& buf, Glib::ustring const& msg)
+{
+ if (msg.empty()) {
+ return false;
+ }
+
+ // See if we have a valid start tag, i.e. < ... >. If we do,
+ // continue; if not, stop and return NULL.
+ //
+ // find_first_of returns ULONG_MAX when it cannot find the first
+ // instance of the given character.
+
+ Glib::ustring::size_type startDelim = msg.find_first_of('<');
+ if (startDelim != ULONG_MAX) {
+ Glib::ustring::size_type endDelim = msg.find_first_of('>');
+ if (endDelim != ULONG_MAX) {
+ if (endDelim > startDelim) {
+ buf.tag = msg.substr(startDelim+1, (endDelim-startDelim)-1);
+ if (buf.tag.find_first_of('/') == ULONG_MAX) { // start tags should not be end tags
+
+
+ // construct end tag (</buf.data>)
+ Glib::ustring endTag(buf.tag);
+ endTag.insert(0, "/");
+
+ Glib::ustring::size_type endTagLoc = msg.find(endTag, endDelim);
+ if (endTagLoc != ULONG_MAX) {
+ buf.data = msg.substr(endDelim+1, ((endTagLoc - 1) - (endDelim + 1)));
+ buf.next_pos = endTagLoc + endTag.length() + 1;
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+MessageUtilities::findTag(struct Node& buf, Glib::ustring const& msg)
+{
+ if (msg.empty()) {
+ return false;
+ }
+
+ // Read desired tag type out of buffer, and append
+ // < > to it
+
+ Glib::ustring searchterm("<");
+ searchterm += buf.tag;
+ searchterm + ">";
+
+ Glib::ustring::size_type tagStart = msg.find(searchterm, 0);
+ if (tagStart != ULONG_MAX) {
+ // Find ending tag starting at the point at the end of
+ // the start tag.
+ searchterm.insert(1, "/");
+ Glib::ustring::size_type tagEnd = msg.find(searchterm, tagStart + searchterm.length());
+ if (tagEnd != ULONG_MAX) {
+ Glib::ustring::size_type start = tagStart + searchterm.length();
+ buf.data = msg.substr(start, tagEnd - start);
+ return true;
+ }
+ }
+ return false;
+}
+
+Glib::ustring
+MessageUtilities::makeTagWithContent(Glib::ustring tagname, Glib::ustring content)
+{
+ Glib::ustring buf;
+ buf = "<" + tagname + ">";
+ buf += content;
+ buf += "</" + tagname + ">";
+ return buf;
+}
+
+
+}
+
+}
+
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :