diff options
| author | MenTaLguY <mental@rydia.net> | 2006-01-16 02:36:01 +0000 |
|---|---|---|
| committer | mental <mental@users.sourceforge.net> | 2006-01-16 02:36:01 +0000 |
| commit | 179fa413b047bede6e32109e2ce82437c5fb8d34 (patch) | |
| tree | a5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/jabber_whiteboard/message-utilities.cpp | |
| download | inkscape-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.cpp | 452 |
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 : |
