Logo Search packages:      
Sourcecode: inkscape version File versions

message-utilities.cpp

/**
 * 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/share.h"
#include "util/list.h"
#include "util/ucompose.hpp"

#include "xml/node.h"
#include "xml/attribute-record.h"
#include "xml/repr.h"

#include "jabber_whiteboard/defines.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.

Glib::ustring
MessageUtilities::objectToString(Inkscape::XML::Node *element)
{
    if(element->type() == Inkscape::XML::TEXT_NODE)
        return String::ucompose("<text>%1</text>",element->content());

    Glib::ustring attributes;

    for ( Inkscape::Util::List<Inkscape::XML::AttributeRecord const> 
        iter = element->attributeList() ; iter ; ++iter )
    {
        attributes.append(g_quark_to_string(iter->key));
        attributes.append("=\"");
        attributes.append(iter->value);
        attributes.append("\" ");
    }

    return String::ucompose("<%1 %2/>",element->name(),attributes);
}
/*
void
MessageUtilities::newObjectMessage(Glib::ustring &msgbuf, 
                       KeyNodeTable& newnodesbuf,
                       NewChildObjectMessageList& childmsgbuf, 
                       XMLNodeTracker* xmt, 
                       Inkscape::XML::Node const* node,
                       bool only_collect_nodes,
                       bool collect_children)
{
      // Initialize pointers
      Glib::ustring id, refid, parentid;

      gchar const* name = NULL;
      XML::Node* parent = NULL;
      XML::Node* ref = NULL;

      bool only_add_children = false;

        //g_log(NULL, G_LOG_LEVEL_DEBUG, "newObjectMessage: processing node %p of type %s", node, NodeUtilities::nodeTypeToString(*node).data());

      if (node != NULL) {
            parent = sp_repr_parent(node);
            if (parent != NULL) {
                        //g_log(NULL, G_LOG_LEVEL_DEBUG, "Attempting to find ID for parent node %p (on node %p)", parent, node);
                  parentid = NodeUtilities::findNodeID(*parent, xmt, newnodesbuf);
                  if (parentid.empty()) {
                        g_warning("Parent %p is not being tracked, creating new ID", parent);
                        parentid = xmt->generateKey();
                        newnodesbuf.put(parentid, parent);
                  }

                  if ( node != parent->firstChild() && parent != NULL ) {
                        ref = parent->firstChild();
                        while (ref->next() != node) {
                              ref = ref->next();
                        }
                  }     
            }

            if (ref != NULL) {
                        //g_log(NULL, G_LOG_LEVEL_DEBUG, "Attempting to find ID for ref node %p (on %p)", ref, node);
                  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();
                        newnodesbuf.put(refid, ref);
                  }
            }

            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();      
                        //g_log(NULL, G_LOG_LEVEL_DEBUG, "Inserting %p with id %s", node, id.c_str());
                  newnodesbuf.put(id, node);
            } else {
                  id = xmt->get(*node);
                //g_log(NULL, G_LOG_LEVEL_DEBUG, "Found id %s for node %p; not inserting into new nodes buffers.", id.c_str(), node);
            }
      } else {
                //g_log(NULL, G_LOG_LEVEL_DEBUG, "Processing special node; not generating key");
            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();
                  newnodesbuf.put(id, node);
            }
            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.
            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 {

      }

        //g_log(NULL, G_LOG_LEVEL_DEBUG, "Generated message");

      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,
                        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(Glib::ustring &msgbuf, 
                                    XMLNodeTracker* xmt, 
                                    const Glib::ustring &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");
    }

    Glib::ustring parentid, previd, childid;

    childid = xmt->get(child);
    parentid = xmt->get(parent);
    previd = xmt->get(*prev);

    if (childid.empty())
        return;
            
 
     // <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, 
                       const Glib::ustring &nodeid, 
                       Util::ptr_shared<char> old_value,
                       Util::ptr_shared<char> new_value)
{
    if (nodeid.empty())
        return;
        
     // <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.pointer();
     msgbuf = msgbuf + "</" + MESSAGE_OLDVAL + ">";

     // <MESSAGE_NEWVAL>new_value</MESSAGE_NEWVAL>
     msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">";
     msgbuf += new_value.pointer();
     msgbuf = msgbuf + "</" + MESSAGE_NEWVAL + ">";

     // </MESSAGE_NODECONTENT>
     msgbuf = msgbuf + "</" + MESSAGE_NODECONTENT + ">";
}

void
MessageUtilities::childOrderChangeMessage(Glib::ustring& msgbuf, 
                          const Glib::ustring &childid, 
                          const Glib::ustring &oldprevid, 
                          const Glib::ustring &newprevid)
{
    if (childid.empty())
        return;
        
    // <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, const Glib::ustring &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, const Glib::ustring &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(const Glib::ustring &tagname,
                                     const Glib::ustring &content)
{
    Glib::ustring buf = "<" + tagname + ">";
    buf += content;
    buf += "</" + tagname + ">";
    return buf;
}
*/

}

}



/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :

Generated by  Doxygen 1.6.0   Back to index