1 /**
2 * Whiteboard session manager
3 * XML node tracking facility
4 *
5 * Authors:
6 * David Yip <yipdw@rose-hulman.edu>
7 *
8 * Copyright (c) 2005 Authors
9 *
10 * Released under GNU GPL, read the file 'COPYING' for more information
11 */
13 #include "sp-object.h"
14 #include "sp-item-group.h"
15 #include "document.h"
16 #include "document-private.h"
18 #include "xml/node.h"
20 #include "util/compose.hpp"
22 #include "jabber_whiteboard/session-manager.h"
23 #include "jabber_whiteboard/node-tracker.h"
26 // TODO: remove redundant calls to isTracking(); it's a rather unnecessary
27 // performance burden.
28 namespace Inkscape {
30 namespace Whiteboard {
32 // Lookup tables
34 /**
35 * Keys for special nodes.
36 *
37 * A special node is a node that can only appear once in a document.
38 */
39 char const* specialnodekeys[] = {
40 DOCUMENT_ROOT_NODE,
41 DOCUMENT_NAMEDVIEW_NODE,
42 };
44 /**
45 * Names of special nodes.
46 *
47 * A special node is a node that can only appear once in a document.
48 */
49 char const* specialnodenames[] = {
50 DOCUMENT_ROOT_NAME,
51 DOCUMENT_NAMEDVIEW_NAME,
52 };
54 XMLNodeTracker::XMLNodeTracker(SessionManager* sm) :
55 _rootKey(DOCUMENT_ROOT_NODE),
56 _namedviewKey(DOCUMENT_NAMEDVIEW_NODE)
57 {
58 _sm = sm;
59 init();
60 }
62 XMLNodeTracker::XMLNodeTracker() :
63 _rootKey(DOCUMENT_ROOT_NODE),
64 _namedviewKey(DOCUMENT_NAMEDVIEW_NODE)
65 {
66 _sm = NULL;
67 init();
68 }
70 XMLNodeTracker::~XMLNodeTracker()
71 {
72 _clear();
73 }
76 void
77 XMLNodeTracker::init()
78 {
79 _counter = 0;
81 // Construct special node maps
82 createSpecialNodeTables();
83 if (_sm)
84 reset();
85 }
87 void
88 XMLNodeTracker::setSessionManager(const SessionManager *val)
89 {
90 _sm = (SessionManager *)val;
91 if (_sm)
92 reset();
93 }
95 void
96 XMLNodeTracker::put(const Glib::ustring &key, const XML::Node &nodeArg)
97 {
98 keyNodeTable.put(key, &nodeArg);
99 }
102 void
103 XMLNodeTracker::process(const KeyToNodeActionList &actions)
104 {
105 KeyToNodeActionList::const_iterator iter = actions.begin();
106 for(; iter != actions.end(); iter++) {
107 // Get the action to perform.
108 SerializedEventNodeAction action = *iter;
109 switch(action.second) {
110 case NODE_ADD:
111 //g_log(NULL, G_LOG_LEVEL_DEBUG,
112 //"NODE_ADD event: key %s, node %p",
113 //action.first.first.c_str(), action.first.second);
114 put(action.first.key, *action.first.node);
115 break;
116 case NODE_REMOVE:
117 //g_log(NULL, G_LOG_LEVEL_DEBUG,
118 //"NODE_REMOVE event: key %s, node %p",
119 // action.first.first.c_str(), action.first.second);
120 //remove(const_cast< XML::Node& >(*action.first.second));
121 break;
122 default:
123 break;
124 }
125 }
126 }
128 XML::Node*
129 XMLNodeTracker::get(const Glib::ustring &key)
130 {
131 XML::Node *node = keyNodeTable.get(key);
132 if (node)
133 return node;
135 g_warning("Key %s is not being tracked!", key.c_str());
136 return NULL;
137 }
139 Glib::ustring
140 XMLNodeTracker::get(const XML::Node &nodeArg)
141 {
142 Glib::ustring key = keyNodeTable.get((XML::Node *)&nodeArg);
143 return key;
144 }
146 bool
147 XMLNodeTracker::isTracking(const Glib::ustring &key)
148 {
149 return (get(key)!=NULL);
150 }
152 bool
153 XMLNodeTracker::isTracking(const XML::Node &node)
154 {
155 return (get(node).size()>0);
156 }
159 bool
160 XMLNodeTracker::isRootNode(const XML::Node &node)
161 {
162 XML::Node* docroot = sp_document_repr_root(_sm->getDocument());
163 return (docroot == &node);
164 }
167 void
168 XMLNodeTracker::remove(const Glib::ustring& key)
169 {
170 g_log(NULL, G_LOG_LEVEL_DEBUG, "Removing node with key %s", key.c_str());
171 keyNodeTable.remove(key);
172 }
174 void
175 XMLNodeTracker::remove(const XML::Node &nodeArg)
176 {
177 //g_log(NULL, G_LOG_LEVEL_DEBUG, "Removing node %p", &node);
178 keyNodeTable.remove((XML::Node *)&nodeArg);
179 }
182 bool
183 XMLNodeTracker::isSpecialNode(const Glib::ustring &name)
184 {
185 return (_specialnodes.find(name.data()) != _specialnodes.end());
186 }
188 Glib::ustring
189 XMLNodeTracker::getSpecialNodeKeyFromName(Glib::ustring const& name)
190 {
191 return _specialnodes[name.data()];
192 }
194 Glib::ustring
195 XMLNodeTracker::generateKey(gchar const* JID)
196 {
197 return String::compose("%1;%2", _counter++, JID);
198 }
200 Glib::ustring
201 XMLNodeTracker::generateKey()
202 {
203 std::bitset< NUM_FLAGS >& status = _sm->getStatus();
204 Glib::ustring ret;
205 if (status[IN_CHATROOM]) {
206 // This is not strictly required for chatrooms: chatrooms will
207 // function just fine with the user-to-user ID scheme. However,
208 // the user-to-user scheme can lead to loss of anonymity
209 // in anonymous chat rooms, since it contains the real JID
210 // of a user.
211 /*
212 ret = String::compose("%1;%2@%3/%4",
213 _counter++,
214 _sm->getClient().getUsername(),
215 _sm->getClient().getHost(),
216 sd->chat_handle);
217 */
218 //We need to work on this since Pedro allows multiple chatrooms
219 ret = String::compose("%1;%2",
220 _counter++,
221 _sm->getClient().getJid());
222 } else {
223 ret = String::compose("%1;%2",
224 _counter++,
225 _sm->getClient().getJid());
226 }
227 return ret;
228 }
230 void
231 XMLNodeTracker::createSpecialNodeTables()
232 {
233 int const sz = sizeof(specialnodekeys) / sizeof(char const*);
234 for(int i = 0; i < sz; i++)
235 _specialnodes[specialnodenames[i]] = specialnodekeys[i];
236 }
239 // rather nasty and crufty debugging function
240 void
241 XMLNodeTracker::dump()
242 {
243 g_log(NULL, G_LOG_LEVEL_DEBUG, "XMLNodeTracker dump for %s",
244 _sm->getClient().getJid().c_str());
248 g_log(NULL, G_LOG_LEVEL_DEBUG, "%u entries in keyNodeTable",
249 keyNodeTable.size());
251 g_log(NULL, G_LOG_LEVEL_DEBUG, "XMLNodeTracker keyNodeTable dump");
252 for (unsigned int i=0 ; i<keyNodeTable.size() ; i++)
253 {
254 KeyNodePair pair = keyNodeTable.item(i);
255 Glib::ustring key = pair.key;
256 XML::Node *node = pair.node;
257 char *name = "none";
258 char *content = "none";
259 if (node)
260 {
261 name = (char *)node->name();
262 content = (char *)node->content();
263 }
264 g_log(NULL, G_LOG_LEVEL_DEBUG, "%s\t->\t%p (%s) (%s)",
265 key.c_str(), node, name, content);
266 }
268 g_log(NULL, G_LOG_LEVEL_DEBUG, "_specialnodes dump");
269 std::map< char const*, char const* >::iterator k = _specialnodes.begin();
270 while(k != _specialnodes.end()) {
271 g_log(NULL, G_LOG_LEVEL_DEBUG, "%s\t->\t%s", (*k).first, (*k).second);
272 k++;
273 }
274 }
276 void
277 XMLNodeTracker::reset()
278 {
279 _clear();
281 // Find and insert special nodes
282 // root node
283 put(_rootKey, *(sp_document_repr_root(_sm->getDocument())));
285 // namedview node
286 SPObject* namedview = sp_item_group_get_child_by_name(
287 (SPGroup *)_sm->getDocument()->root,
288 NULL, DOCUMENT_NAMEDVIEW_NAME);
289 if (!namedview) {
290 g_warning("namedview node does not exist; it will be created during synchronization");
291 } else {
292 put(_namedviewKey, *(SP_OBJECT_REPR(namedview)));
293 }
294 }
296 void
297 XMLNodeTracker::_clear()
298 {
299 // Remove all keys in both trackers, and delete each key.
300 keyNodeTable.clear();
301 }
303 } // namespace Whiteboard
305 } // namespace Inkscape
309 /*
310 Local Variables:
311 mode:c++
312 c-file-style:"stroustrup"
313 c-file-offsets:((innamespace . 0)(inline-open . 0))
314 indent-tabs-mode:nil
315 fill-column:99
316 End:
317 */
318 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :