Code

Extensions. Check element now search in the extension directory (see Bug #668895...
[inkscape.git] / src / jabber_whiteboard / inkboard-document.cpp
1 /**
2  * Inkscape::Whiteboard::InkboardDocument - Inkboard document implementation
3  *
4  * Authors:
5  * David Yip <yipdw@rose-hulman.edu>
6  *
7  * Copyright (c) 2005 Authors
8  *
9  * Released under GNU GPL, read the file 'COPYING' for more information
10  */
12 #include <glib.h>
13 #include <glibmm.h>
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"
24 #include <glibmm.h>
25 #include <glib/gmessages.h>
26 #include <glib/gquark.h>
28 #include "jabber_whiteboard/inkboard-document.h"
29 #include "jabber_whiteboard/defines.h"
31 #include "xml/node.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"
41 namespace Inkscape {
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)
49 {
50     _initBindings();
51 }
53 void
54 InkboardDocument::_initBindings()
55 {
56     this->sm = &SessionManager::instance();
57     this->state = State::INITIAL;
58     this->tracker = new KeyNodeTable();
59 }
61 void
62 InkboardDocument::setRecipient(Glib::ustring const& val)
63 {
64     this->recipient = val;
65 }
67 Glib::ustring 
68 InkboardDocument::getRecipient() const
69 {
70     return this->recipient;
71 }
73 void
74 InkboardDocument::setSessionId(Glib::ustring const& val)
75 {
76     this->sessionId = val;
77 }
79 Glib::ustring 
80 InkboardDocument::getSessionId() const
81 {
82     return this->sessionId;
83 }
85 void
86 InkboardDocument::startSessionNegotiation()
87 {
88     if(this->sessionType == State::WHITEBOARD_PEER)
89         this->send(recipient, Message::PROTOCOL,Message::CONNECT_REQUEST);
91     else if(this->sessionType == State::WHITEBOARD_MUC)
92     {
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
95     }
96 }
98 void
99 InkboardDocument::terminateSession()
104 void
105 InkboardDocument::recieve(Message::Wrapper &wrapper, Pedro::Element* data)
107     if(this->handleIncomingState(wrapper,data))
108     {
109         if(wrapper == Message::PROTOCOL)
110         {
111             Glib::ustring message = data->getFirstChild()->getFirstChild()->getFirstChild()->getName();
113             if(message == Message::CONNECT_REQUEST)
114             {
115                 // An MUC member requesting document
117             }else if(message == Message::ACCEPT_INVITATION)
118             {
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);
124                 // Send Document
125                 this->sendDocument(this->root());
127                 this->send(getRecipient(),Message::PROTOCOL, Message::DOCUMENT_END);
129             }else if(message == Message::DECLINE_INVITATION)
130             {
131                 this->sm->terminateSession(this->getSessionId());
132             }
133         }else if(wrapper == Message::NEW || wrapper == Message::CONFIGURE
134                     || wrapper == Message::MOVE || wrapper == Message::REMOVE )
135         {
136             handleChange(wrapper,data->getFirstChild()->getFirstChild());
137         }
138     }else{
139         g_warning("Recieved Message in invalid state = %d", this->state);
140         data->print();
141     }
144 bool
145 InkboardDocument::send(const Glib::ustring &destJid, Message::Wrapper &wrapper, Message::Message &message)
147     if(this->handleOutgoingState(wrapper,message))
148     {
149         Glib::ustring mes;
150         if(wrapper == Message::PROTOCOL)
151             mes = String::ucompose(Vars::PROTOCOL_MESSAGE,wrapper,message);
152         else
153             mes = 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)) 
160             { return false; }
161         else 
162             { return true; }
164     }else 
165     { 
166         g_warning("Sending Message in invalid state message=%s , state=%d",message.c_str(),this->state);
167         return false; 
168     }
171 void
172 InkboardDocument::sendDocument(Inkscape::XML::Node* root)
174     for(Inkscape::XML::Node *child = root->firstChild();child!=NULL;child=child->next())
175     {
176         Glib::ustring name(child->name());
178         if(name != "svg:metadata" && name != "svg:defs" && name != "sodipodi:namedview")
179         {
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)
188             {
189                 sendDocument(child);
190             }
191         }
192     }
195 bool
196 InkboardDocument::handleOutgoingState(Message::Wrapper &wrapper, Glib::ustring const& message)
198     if(wrapper == Message::PROTOCOL) 
199     {
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);
214         }
216         else 
217             return false;
219     } else 
220         if(this->state == State::SYNCHRONISING && wrapper == Message::NEW)
221             return true;
223     return this->state == State::IN_WHITEBOARD;
226 bool
227 InkboardDocument::handleIncomingState(Message::Wrapper &wrapper, Pedro::Element* data)
229     if(wrapper == Message::PROTOCOL) 
230     {
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);
247         else 
248             return false;
250     } else 
251         if(this->state == State::SYNCHRONISING && wrapper == Message::NEW)
252             return true;
254     return this->state == State::IN_WHITEBOARD;
257 bool 
258 InkboardDocument::handleState(State::SessionState expectedState, State::SessionState newState)
260     if(this->state == expectedState)
261     {
262         this->state = newState;
263         return true;
264     }
266     return false;
270 void
271 InkboardDocument::handleChange(Message::Wrapper &wrapper, Pedro::Element* data)
273     if(wrapper == Message::NEW)
274     {
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)
287     {
288         if(data->exists("text"))
289         {
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);
299         }else 
300         {
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);
310         }
311     }else if(wrapper == Message::MOVE)
312     {
313     }else if(wrapper == Message::REMOVE) 
314     {
315     }
318 void
319 InkboardDocument::beginTransaction()
321     g_assert(!_in_transaction);
322     _in_transaction = true;
325 void
326 InkboardDocument::rollback()
328     g_assert(_in_transaction);
329     _in_transaction = false;
332 void 
333 InkboardDocument::commit()
335     g_assert(_in_transaction);
336     _in_transaction = false;
339 XML::Event*
340 InkboardDocument::commitUndoable()
342     g_assert(_in_transaction);
343     _in_transaction = false;
344     return NULL;
347 XML::Node*
348 InkboardDocument::createElement(char const* name)
350     return new XML::ElementNode(g_quark_from_string(name), this);
353 XML::Node*
354 InkboardDocument::createTextNode(char const* content)
356     return new XML::TextNode(Util::share_string(content), this);
359 XML::Node*
360 InkboardDocument::createComment(char const* content)
362     return new XML::CommentNode(Util::share_string(content), this);
365 XML::Node*
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*/,
374                                         XML::Node &child,
375                                         XML::Node */*prev*/)
377     if (_in_transaction && state == State::IN_WHITEBOARD) {
379         XML::Node *node = (XML::Node *)&child;
381         if(tracker->get(node) == "")
382         {
383             addNodeToTracker(node);
384             Message::Message message = composeNewMessage(node);
386             send(getRecipient(),Message::NEW,message);
387         }
388     }
391 void InkboardDocument::notifyChildRemoved(XML::Node &/*parent*/,
392                                           XML::Node &child,
393                                           XML::Node */*prev*/)
395     if (_in_transaction && state == State::IN_WHITEBOARD) 
396     {
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);
403    }
406 void InkboardDocument::notifyChildOrderChanged(XML::Node &parent,
407                                                XML::Node &child,
408                                                XML::Node */*old_prev*/,
409                                                XML::Node */*new_prev*/)
411     if (_in_transaction && state == State::IN_WHITEBOARD) 
412     {
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);
419     }
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) 
427     {
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)
435             return;
437         if(new_content.pointer())
438         {
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);
445         }
446     }
449 void InkboardDocument::notifyAttributeChanged(XML::Node &node,
450                                               GQuark name,
451                                               Util::ptr_shared<char> /*old_value*/,
452                                               Util::ptr_shared<char> new_value)
454     if (_in_transaction && state == State::IN_WHITEBOARD) 
455     {
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)
464             return;
466         if(attribute.size() > 0 && value.size() > 0)
467         {
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);
474         }
475     }