inkboard-document.cpp revision 4527f6c136612e318804db902fa46d53238c7648
/**
* Inkscape::Whiteboard::InkboardDocument - Inkboard document implementation
*
* Authors:
* David Yip <yipdw@rose-hulman.edu>
*
* Copyright (c) 2005 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <glib.h>
#include <glibmm.h>
#include "jabber_whiteboard/inkboard-document.h"
#include "util/ucompose.hpp"
#include "jabber_whiteboard/message-utilities.h"
#include "jabber_whiteboard/defines.h"
#include "jabber_whiteboard/session-manager.h"
#include "jabber_whiteboard/node-tracker.h"
#include <glibmm.h>
#include <glib/gmessages.h>
#include <glib/gquark.h>
#include "jabber_whiteboard/inkboard-document.h"
#include "jabber_whiteboard/defines.h"
#include "xml/node.h"
#include "xml/event.h"
#include "xml/element-node.h"
#include "xml/text-node.h"
#include "xml/comment-node.h"
#include "xml/pi-node.h"
#include "util/share.h"
#include "util/ucompose.hpp"
namespace Inkscape {
namespace Whiteboard {
InkboardDocument::InkboardDocument(int code, State::SessionType sessionType,
Glib::ustring const& to)
: XML::SimpleNode(code), sessionType(sessionType), recipient(to),
_in_transaction(false)
{
_initBindings();
}
void
InkboardDocument::_initBindings()
{
this->sm = &SessionManager::instance();
this->state = State::INITIAL;
this->tracker = new KeyNodeTable();
_bindDocument(*this);
}
void
InkboardDocument::setRecipient(Glib::ustring const& val)
{
this->recipient = val;
}
Glib::ustring
InkboardDocument::getRecipient() const
{
return this->recipient;
}
void
InkboardDocument::setSessionId(Glib::ustring const& val)
{
this->sessionId = val;
}
Glib::ustring
InkboardDocument::getSessionId() const
{
return this->sessionId;
}
void
InkboardDocument::startSessionNegotiation()
{
if(this->sessionType == State::WHITEBOARD_PEER)
this->send(recipient, Message::PROTOCOL,Message::CONNECT_REQUEST);
else if(this->sessionType == State::WHITEBOARD_MUC)
{
// Check that the MUC room is whiteboard enabled, if not no need to send
// anything, just set the room to be whiteboard enabled
}
}
void
InkboardDocument::terminateSession()
{
}
void
InkboardDocument::recieve(Message::Wrapper &wrapper, Pedro::Element* data)
{
if(this->handleIncomingState(wrapper,data))
{
if(wrapper == Message::PROTOCOL)
{
Glib::ustring message = data->getFirstChild()->getFirstChild()->getFirstChild()->getName();
if(message == Message::CONNECT_REQUEST)
{
// An MUC member requesting document
}else if(message == Message::ACCEPT_INVITATION)
{
// TODO : Would be nice to create the desktop here
this->send(getRecipient(),Message::PROTOCOL, Message::CONNECTED);
this->send(getRecipient(),Message::PROTOCOL, Message::DOCUMENT_BEGIN);
// Send Document
this->sendDocument(this->root());
this->send(getRecipient(),Message::PROTOCOL, Message::DOCUMENT_END);
}else if(message == Message::DECLINE_INVITATION)
{
this->sm->terminateSession(this->getSessionId());
}
}else if(wrapper == Message::NEW || wrapper == Message::CONFIGURE
|| wrapper == Message::MOVE || wrapper == Message::REMOVE )
{
handleChange(wrapper,data->getFirstChild()->getFirstChild());
}
}else{
g_warning("Recieved Message in invalid state = %d", this->state);
data->print();
}
}
bool
InkboardDocument::send(const Glib::ustring &destJid, Message::Wrapper &wrapper, Message::Message &message)
{
if(this->handleOutgoingState(wrapper,message))
{
Glib::ustring mes;
if(wrapper == Message::PROTOCOL)
mes = String::ucompose(Vars::PROTOCOL_MESSAGE,wrapper,message);
else
mes = message;
char *finalmessage = const_cast<char* >(String::ucompose(
Vars::WHITEBOARD_MESSAGE, this->sessionType, this->sm->getClient().getJid(),
destJid, Vars::INKBOARD_XMLNS, this->getSessionId(), mes).c_str());
if (!this->sm->getClient().write("%s",finalmessage))
{ return false; }
else
{ return true; }
}else
{
g_warning("Sending Message in invalid state message=%s , state=%d",message.c_str(),this->state);
return false;
}
}
void
InkboardDocument::sendDocument(Inkscape::XML::Node* root)
{
for(Inkscape::XML::Node *child = root->firstChild();child!=NULL;child=child->next())
{
Glib::ustring name(child->name());
if(name != "svg:metadata" && name != "svg:defs" && name != "sodipodi:namedview")
{
Glib::ustring parentKey,tempParentKey,key;
this->addNodeToTracker(child);
Message::Message message = this->composeNewMessage(child);
this->send(this->getRecipient(),Message::NEW,message);
if(child->childCount() != 0)
{
sendDocument(child);
}
}
}
}
bool
InkboardDocument::handleOutgoingState(Message::Wrapper &wrapper, Glib::ustring const& message)
{
if(wrapper == Message::PROTOCOL)
{
if(message == Message::CONNECT_REQUEST)
return this->handleState(State::INITIAL,State::AWAITING_INVITATION_REPLY);
else if(message == Message::ACCEPT_INVITATION)
return this->handleState(State::CONNECTING,State::AWAITING_CONNECTED);
else if(message == Message::CONNECTED)
return this->handleState(State::INVITATION_RECIEVED,State::CONNECTED);
else if(message == Message::DOCUMENT_BEGIN)
return this->handleState(State::CONNECTED,State::SYNCHRONISING);
else if(message == Message::DOCUMENT_END) {
return this->handleState(State::SYNCHRONISING,State::IN_WHITEBOARD);
}
else
return false;
} else
if(this->state == State::SYNCHRONISING && wrapper == Message::NEW)
return true;
return this->state == State::IN_WHITEBOARD;
}
bool
InkboardDocument::handleIncomingState(Message::Wrapper &wrapper, Pedro::Element* data)
{
if(wrapper == Message::PROTOCOL)
{
Glib::ustring message = data->getFirstChild()->getFirstChild()->getFirstChild()->getName();
if(message == Message::CONNECT_REQUEST)
return this->handleState(State::INITIAL,State::CONNECTING);
if(message == Message::ACCEPT_INVITATION)
return this->handleState(State::AWAITING_INVITATION_REPLY,State::INVITATION_RECIEVED);
else if(message == Message::CONNECTED)
return this->handleState(State::AWAITING_CONNECTED,State::AWAITING_DOCUMENT_BEGIN);
else if(message == Message::DOCUMENT_BEGIN)
return this->handleState(State::AWAITING_DOCUMENT_BEGIN,State::SYNCHRONISING);
else if(message == Message::DOCUMENT_END)
return this->handleState(State::SYNCHRONISING,State::IN_WHITEBOARD);
else
return false;
} else
if(this->state == State::SYNCHRONISING && wrapper == Message::NEW)
return true;
return this->state == State::IN_WHITEBOARD;
}
bool
InkboardDocument::handleState(State::SessionState expectedState, State::SessionState newState)
{
if(this->state == expectedState)
{
this->state = newState;
return true;
}
return false;
}
void
InkboardDocument::handleChange(Message::Wrapper &wrapper, Pedro::Element* data)
{
if(wrapper == Message::NEW)
{
Glib::ustring parent = data->getTagAttribute("new","parent");
Glib::ustring id = data->getTagAttribute("new","id");
signed int index = atoi
(data->getTagAttribute("new","index").c_str());
Pedro::Element* element = data->getFirstChild();
if(parent.size() > 0 && id.size() > 0)
this->changeNew(parent,id,index,element);
}else if(wrapper == Message::CONFIGURE)
{
if(data->exists("text"))
{
Glib::ustring text = data->getFirstChild()->getValue();
Glib::ustring target = data->getTagAttribute("configure","target");
unsigned int version = atoi
(data->getTagAttribute("configure","version").c_str());
if(text.size() > 0 && target.size() > 0)
this->changeConfigureText(target,version,text);
}else
{
Glib::ustring target = data->getTagAttribute("configure","target");
Glib::ustring attribute = data->getTagAttribute("configure","attribute");
Glib::ustring value = data->getTagAttribute("configure","value");
unsigned int version = atoi
(data->getTagAttribute("configure","version").c_str());
if(target.size() > 0 && attribute.size() > 0 && value.size() > 0)
this->changeConfigure(target,version,attribute,value);
}
}else if(wrapper == Message::MOVE)
{
}else if(wrapper == Message::REMOVE)
{
}
}
void
InkboardDocument::beginTransaction()
{
g_assert(!_in_transaction);
_in_transaction = true;
}
void
InkboardDocument::rollback()
{
g_assert(_in_transaction);
_in_transaction = false;
}
void
InkboardDocument::commit()
{
g_assert(_in_transaction);
_in_transaction = false;
}
XML::Event*
InkboardDocument::commitUndoable()
{
g_assert(_in_transaction);
_in_transaction = false;
return NULL;
}
XML::Node*
InkboardDocument::createElement(char const* name)
{
return new XML::ElementNode(g_quark_from_string(name));
}
XML::Node*
InkboardDocument::createTextNode(char const* content)
{
return new XML::TextNode(Util::share_string(content));
}
XML::Node*
InkboardDocument::createComment(char const* content)
{
return new XML::CommentNode(Util::share_string(content));
}
XML::Node*
InkboardDocument::createPI(char const *target, char const* content)
{
return new XML::PINode(g_quark_from_string(target), Util::share_string(content));
}
void InkboardDocument::notifyChildAdded(XML::Node &parent,
XML::Node &child,
XML::Node *prev)
{
if (_in_transaction && state == State::IN_WHITEBOARD) {
XML::Node *node = (XML::Node *)&child;
if(tracker->get(node) == "")
{
addNodeToTracker(node);
Message::Message message = composeNewMessage(node);
send(getRecipient(),Message::NEW,message);
}
}
}
void InkboardDocument::notifyChildRemoved(XML::Node &parent,
XML::Node &child,
XML::Node *prev)
{
if (_in_transaction && state == State::IN_WHITEBOARD)
{
XML::Node *element = (XML::Node *)&child;
Message::Message message = String::ucompose(Vars::REMOVE_MESSAGE,
tracker->get(element));
send(getRecipient(),Message::REMOVE,message);
}
}
void InkboardDocument::notifyChildOrderChanged(XML::Node &parent,
XML::Node &child,
XML::Node *old_prev,
XML::Node *new_prev)
{
if (_in_transaction && state == State::IN_WHITEBOARD)
{
XML::Node *element = (XML::Node *)&child;
XML::Node *parentElement = (XML::Node *)&parent;
unsigned int index = parentElement->_childPosition(*element);
Message::Message message = String::ucompose(Vars::MOVE_MESSAGE,
tracker->get(element),index);
send(getRecipient(),Message::MOVE,message);
}
}
void InkboardDocument::notifyContentChanged(XML::Node &node,
Util::ptr_shared<char> old_content,
Util::ptr_shared<char> new_content)
{
if (_in_transaction && state == State::IN_WHITEBOARD)
{
XML::Node *element = (XML::Node *)&node;
Glib::ustring value(new_content.pointer());
Glib::ustring change = tracker->getLastHistory(element,"text");
if(change.size() > 0 && change == value)
return;
if(new_content.pointer())
{
unsigned int version = tracker->incrementVersion(element);
Message::Message message = String::ucompose(Vars::CONFIGURE_TEXT_MESSAGE,
tracker->get(element),version,new_content.pointer());
send(getRecipient(),Message::CONFIGURE,message);
}
}
}
void InkboardDocument::notifyAttributeChanged(XML::Node &node,
GQuark name,
Util::ptr_shared<char> old_value,
Util::ptr_shared<char> new_value)
{
if (_in_transaction && state == State::IN_WHITEBOARD)
{
XML::Node *element = (XML::Node *)&node;
Glib::ustring value(new_value.pointer());
Glib::ustring attribute(g_quark_to_string(name));
Glib::ustring change = tracker->getLastHistory(element,attribute);
if(change.size() > 0 && change == value)
return;
if(attribute.size() > 0 && value.size() > 0)
{
unsigned int version = tracker->incrementVersion(element);
Message::Message message = String::ucompose(Vars::CONFIGURE_MESSAGE,
tracker->get(element),version,attribute.c_str(),value.c_str());
send(getRecipient(),Message::CONFIGURE,message);
}
}
}
}
}