2
* Inkscape::Whiteboard::InkboardDocument - Inkboard document implementation
5
* David Yip <yipdw@rose-hulman.edu>
7
* Copyright (c) 2005 Authors
9
* Released under GNU GPL, read the file 'COPYING' for more information
15
#include "jabber_whiteboard/inkboard-document.h"
17
#include "util/ucompose.hpp"
19
#include "jabber_whiteboard/message-utilities.h"
20
#include "jabber_whiteboard/defines.h"
21
#include "jabber_whiteboard/session-manager.h"
22
#include "jabber_whiteboard/node-tracker.h"
25
#include <glib/gmessages.h>
26
#include <glib/gquark.h>
28
#include "jabber_whiteboard/inkboard-document.h"
29
#include "jabber_whiteboard/defines.h"
32
#include "xml/event.h"
33
#include "xml/element-node.h"
34
#include "xml/text-node.h"
35
#include "xml/comment-node.h"
36
#include "xml/pi-node.h"
38
#include "util/share.h"
39
#include "util/ucompose.hpp"
43
namespace Whiteboard {
45
InkboardDocument::InkboardDocument(int code, State::SessionType sessionType,
46
Glib::ustring const& to)
47
: XML::SimpleNode(code, this), sessionType(sessionType), recipient(to),
48
_in_transaction(false)
54
InkboardDocument::_initBindings()
56
this->sm = &SessionManager::instance();
57
this->state = State::INITIAL;
58
this->tracker = new KeyNodeTable();
62
InkboardDocument::setRecipient(Glib::ustring const& val)
64
this->recipient = val;
68
InkboardDocument::getRecipient() const
70
return this->recipient;
74
InkboardDocument::setSessionId(Glib::ustring const& val)
76
this->sessionId = val;
80
InkboardDocument::getSessionId() const
82
return this->sessionId;
86
InkboardDocument::startSessionNegotiation()
88
if(this->sessionType == State::WHITEBOARD_PEER)
89
this->send(recipient, Message::PROTOCOL,Message::CONNECT_REQUEST);
91
else if(this->sessionType == State::WHITEBOARD_MUC)
93
// Check that the MUC room is whiteboard enabled, if not no need to send
94
// anything, just set the room to be whiteboard enabled
99
InkboardDocument::terminateSession()
105
InkboardDocument::recieve(Message::Wrapper &wrapper, Pedro::Element* data)
107
if(this->handleIncomingState(wrapper,data))
109
if(wrapper == Message::PROTOCOL)
111
Glib::ustring message = data->getFirstChild()->getFirstChild()->getFirstChild()->getName();
113
if(message == Message::CONNECT_REQUEST)
115
// An MUC member requesting document
117
}else if(message == Message::ACCEPT_INVITATION)
119
// TODO : Would be nice to create the desktop here
121
this->send(getRecipient(),Message::PROTOCOL, Message::CONNECTED);
122
this->send(getRecipient(),Message::PROTOCOL, Message::DOCUMENT_BEGIN);
125
this->sendDocument(this->root());
127
this->send(getRecipient(),Message::PROTOCOL, Message::DOCUMENT_END);
129
}else if(message == Message::DECLINE_INVITATION)
131
this->sm->terminateSession(this->getSessionId());
133
}else if(wrapper == Message::NEW || wrapper == Message::CONFIGURE
134
|| wrapper == Message::MOVE || wrapper == Message::REMOVE )
136
handleChange(wrapper,data->getFirstChild()->getFirstChild());
139
g_warning("Recieved Message in invalid state = %d", this->state);
145
InkboardDocument::send(const Glib::ustring &destJid, Message::Wrapper &wrapper, Message::Message &message)
147
if(this->handleOutgoingState(wrapper,message))
150
if(wrapper == Message::PROTOCOL)
151
mes = String::ucompose(Vars::PROTOCOL_MESSAGE,wrapper,message);
155
char *finalmessage = const_cast<char* >(String::ucompose(
156
Vars::WHITEBOARD_MESSAGE, this->sessionType, this->sm->getClient().getJid(),
157
destJid, Vars::INKBOARD_XMLNS, this->getSessionId(), mes).c_str());
159
if (!this->sm->getClient().write("%s",finalmessage))
166
g_warning("Sending Message in invalid state message=%s , state=%d",message.c_str(),this->state);
172
InkboardDocument::sendDocument(Inkscape::XML::Node* root)
174
for(Inkscape::XML::Node *child = root->firstChild();child!=NULL;child=child->next())
176
Glib::ustring name(child->name());
178
if(name != "svg:metadata" && name != "svg:defs" && name != "sodipodi:namedview")
180
Glib::ustring parentKey,tempParentKey,key;
182
this->addNodeToTracker(child);
183
Message::Message message = this->composeNewMessage(child);
185
this->send(this->getRecipient(),Message::NEW,message);
187
if(child->childCount() != 0)
196
InkboardDocument::handleOutgoingState(Message::Wrapper &wrapper, Glib::ustring const& message)
198
if(wrapper == Message::PROTOCOL)
200
if(message == Message::CONNECT_REQUEST)
201
return this->handleState(State::INITIAL,State::AWAITING_INVITATION_REPLY);
203
else if(message == Message::ACCEPT_INVITATION)
204
return this->handleState(State::CONNECTING,State::AWAITING_CONNECTED);
206
else if(message == Message::CONNECTED)
207
return this->handleState(State::INVITATION_RECIEVED,State::CONNECTED);
209
else if(message == Message::DOCUMENT_BEGIN)
210
return this->handleState(State::CONNECTED,State::SYNCHRONISING);
212
else if(message == Message::DOCUMENT_END) {
213
return this->handleState(State::SYNCHRONISING,State::IN_WHITEBOARD);
220
if(this->state == State::SYNCHRONISING && wrapper == Message::NEW)
223
return this->state == State::IN_WHITEBOARD;
227
InkboardDocument::handleIncomingState(Message::Wrapper &wrapper, Pedro::Element* data)
229
if(wrapper == Message::PROTOCOL)
231
Glib::ustring message = data->getFirstChild()->getFirstChild()->getFirstChild()->getName();
233
if(message == Message::CONNECT_REQUEST)
234
return this->handleState(State::INITIAL,State::CONNECTING);
235
if(message == Message::ACCEPT_INVITATION)
236
return this->handleState(State::AWAITING_INVITATION_REPLY,State::INVITATION_RECIEVED);
238
else if(message == Message::CONNECTED)
239
return this->handleState(State::AWAITING_CONNECTED,State::AWAITING_DOCUMENT_BEGIN);
241
else if(message == Message::DOCUMENT_BEGIN)
242
return this->handleState(State::AWAITING_DOCUMENT_BEGIN,State::SYNCHRONISING);
244
else if(message == Message::DOCUMENT_END)
245
return this->handleState(State::SYNCHRONISING,State::IN_WHITEBOARD);
251
if(this->state == State::SYNCHRONISING && wrapper == Message::NEW)
254
return this->state == State::IN_WHITEBOARD;
258
InkboardDocument::handleState(State::SessionState expectedState, State::SessionState newState)
260
if(this->state == expectedState)
262
this->state = newState;
271
InkboardDocument::handleChange(Message::Wrapper &wrapper, Pedro::Element* data)
273
if(wrapper == Message::NEW)
275
Glib::ustring parent = data->getTagAttribute("new","parent");
276
Glib::ustring id = data->getTagAttribute("new","id");
278
signed int index = atoi
279
(data->getTagAttribute("new","index").c_str());
281
Pedro::Element* element = data->getFirstChild();
283
if(parent.size() > 0 && id.size() > 0)
284
this->changeNew(parent,id,index,element);
286
}else if(wrapper == Message::CONFIGURE)
288
if(data->exists("text"))
290
Glib::ustring text = data->getFirstChild()->getValue();
291
Glib::ustring target = data->getTagAttribute("configure","target");
293
unsigned int version = atoi
294
(data->getTagAttribute("configure","version").c_str());
296
if(text.size() > 0 && target.size() > 0)
297
this->changeConfigureText(target,version,text);
301
Glib::ustring target = data->getTagAttribute("configure","target");
302
Glib::ustring attribute = data->getTagAttribute("configure","attribute");
303
Glib::ustring value = data->getTagAttribute("configure","value");
305
unsigned int version = atoi
306
(data->getTagAttribute("configure","version").c_str());
308
if(target.size() > 0 && attribute.size() > 0 && value.size() > 0)
309
this->changeConfigure(target,version,attribute,value);
311
}else if(wrapper == Message::MOVE)
313
}else if(wrapper == Message::REMOVE)
319
InkboardDocument::beginTransaction()
321
g_assert(!_in_transaction);
322
_in_transaction = true;
326
InkboardDocument::rollback()
328
g_assert(_in_transaction);
329
_in_transaction = false;
333
InkboardDocument::commit()
335
g_assert(_in_transaction);
336
_in_transaction = false;
340
InkboardDocument::commitUndoable()
342
g_assert(_in_transaction);
343
_in_transaction = false;
348
InkboardDocument::createElement(char const* name)
350
return new XML::ElementNode(g_quark_from_string(name), this);
354
InkboardDocument::createTextNode(char const* content)
356
return new XML::TextNode(Util::share_string(content), this);
360
InkboardDocument::createComment(char const* content)
362
return new XML::CommentNode(Util::share_string(content), this);
366
InkboardDocument::createPI(char const *target, char const* content)
368
return new XML::PINode(g_quark_from_string(target), Util::share_string(content), this);
373
void InkboardDocument::notifyChildAdded(XML::Node &/*parent*/,
377
if (_in_transaction && state == State::IN_WHITEBOARD) {
379
XML::Node *node = (XML::Node *)&child;
381
if(tracker->get(node) == "")
383
addNodeToTracker(node);
384
Message::Message message = composeNewMessage(node);
386
send(getRecipient(),Message::NEW,message);
391
void InkboardDocument::notifyChildRemoved(XML::Node &/*parent*/,
395
if (_in_transaction && state == State::IN_WHITEBOARD)
397
XML::Node *element = (XML::Node *)&child;
399
Message::Message message = String::ucompose(Vars::REMOVE_MESSAGE,
400
tracker->get(element));
402
send(getRecipient(),Message::REMOVE,message);
406
void InkboardDocument::notifyChildOrderChanged(XML::Node &parent,
408
XML::Node */*old_prev*/,
409
XML::Node */*new_prev*/)
411
if (_in_transaction && state == State::IN_WHITEBOARD)
413
unsigned int index = child.position();
415
Message::Message message = String::ucompose(Vars::MOVE_MESSAGE,
416
tracker->get(&child),index);
418
send(getRecipient(),Message::MOVE,message);
422
void InkboardDocument::notifyContentChanged(XML::Node &node,
423
Util::ptr_shared<char> /*old_content*/,
424
Util::ptr_shared<char> new_content)
426
if (_in_transaction && state == State::IN_WHITEBOARD)
428
XML::Node *element = (XML::Node *)&node;
430
Glib::ustring value(new_content.pointer());
432
Glib::ustring change = tracker->getLastHistory(element,"text");
434
if(change.size() > 0 && change == value)
437
if(new_content.pointer())
439
unsigned int version = tracker->incrementVersion(element);
441
Message::Message message = String::ucompose(Vars::CONFIGURE_TEXT_MESSAGE,
442
tracker->get(element),version,new_content.pointer());
444
send(getRecipient(),Message::CONFIGURE,message);
449
void InkboardDocument::notifyAttributeChanged(XML::Node &node,
451
Util::ptr_shared<char> /*old_value*/,
452
Util::ptr_shared<char> new_value)
454
if (_in_transaction && state == State::IN_WHITEBOARD)
456
XML::Node *element = (XML::Node *)&node;
458
Glib::ustring value(new_value.pointer());
459
Glib::ustring attribute(g_quark_to_string(name));
461
Glib::ustring change = tracker->getLastHistory(element,attribute);
463
if(change.size() > 0 && change == value)
466
if(attribute.size() > 0 && value.size() > 0)
468
unsigned int version = tracker->incrementVersion(element);
470
Message::Message message = String::ucompose(Vars::CONFIGURE_MESSAGE,
471
tracker->get(element),version,attribute.c_str(),value.c_str());
473
send(getRecipient(),Message::CONFIGURE,message);