]> matita.cs.unibo.it Git - helm.git/blob - helm/gtkmathview-bonobo/src/aux.cc
* completed implementation of View interface
[helm.git] / helm / gtkmathview-bonobo / src / aux.cc
1 // Copyright (C) 2000-2002, Luca Padovani <luca.padovani@cs.unibo.it>.
2 //
3 // This file is part of GtkMathView, a Gtk widget for MathML.
4 // 
5 // GtkMathView is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // GtkMathView is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with GtkMathView; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 // 
19 // For details, see the GtkMathView World-Wide-Web page,
20 // http://www.cs.unibo.it/helm/mml-widget, or send a mail to
21 // <luca.padovani@cs.unibo.it>
22
23 #include <config.h>
24
25 #include <cassert>
26
27 #include <sstream>
28
29 #include <gdome.h>
30 #include <gdome-util.h>
31
32 #include <GdomeSmartDOM.hh>
33
34 #include "aux.h"
35
36 #define MATHML_NS_URI "http://www.w3.org/1998/Math/MathML"
37
38 namespace DOM = GdomeSmartDOM;
39
40 static DOM::Element
41 findElementById(const DOM::Element& el,
42                 const DOM::GdomeString& ns, const DOM::GdomeString& name,
43                 const DOM::GdomeString& id)
44 {
45   assert(el);
46   if (el.getAttributeNS(ns, name) == id)
47     return el;
48   else
49     for (DOM::Node p = el.get_firstChild(); p; p = p.get_nextSibling())
50       if (p.get_nodeType() == DOM::Node::ELEMENT_NODE)
51         if (DOM::Element res = findElementById(p, ns, name, id))
52           return res;
53   return DOM::Element();
54 }
55
56 static unsigned
57 getDepth(const DOM::Element& elem)
58 {
59   unsigned length = 0;
60   DOM::Element p = elem;
61
62   while (p)
63     {
64       p = p.get_parentNode();
65       length++;
66     }
67
68   return length;
69 }
70
71 static DOM::Element
72 findCommonAncestor(const DOM::Element& first, const DOM::Element& last)
73 {
74   if (!first || !last) return DOM::Element(0);
75
76   DOM::Element p(first);
77   DOM::Element q(last);
78
79   if (p != q)
80     {
81       unsigned pDepth = getDepth(p);
82       unsigned qDepth  = getDepth(q);
83
84       while (p && pDepth > qDepth)
85         {
86           p = p.get_parentNode();
87           pDepth--;
88         }
89
90       while (q && qDepth > pDepth)
91         {
92           q = q.get_parentNode();
93           qDepth--;
94         }
95
96       assert(pDepth == qDepth);
97
98       while (p && q && p != q)
99         {
100           p = p.get_parentNode();
101           q = q.get_parentNode();
102         }
103     }
104   
105   return p;
106 }
107
108 static void
109 findCommonSiblings(const DOM::Element& first, const DOM::Element& last,
110                    DOM::Element& firstS, DOM::Element& lastS)
111 {
112   DOM::Element p(first);
113   DOM::Element q(last);
114
115   if (p != q)
116     {
117       unsigned pDepth = getDepth(p);
118       unsigned qDepth  = getDepth(q);
119
120       while (p && pDepth > qDepth)
121         {
122           p = p.get_parentNode();
123           pDepth--;
124         }
125
126       while (q && qDepth > pDepth)
127         {
128           q = q.get_parentNode();
129           qDepth--;
130         }
131
132       assert(pDepth == qDepth);
133
134       while (p && q && p.get_parentNode() != q.get_parentNode())
135         {
136           p = p.get_parentNode();
137           q = q.get_parentNode();
138         }
139     }
140
141   firstS = p;
142   lastS = q;
143 }
144
145 static DOM::Node
146 leftmostChild(const DOM::Node& node)
147 {
148   if (!node) return node;
149
150   DOM::Node firstChild = node.get_firstChild();
151   if (!firstChild) return node;
152
153   return leftmostChild(firstChild);
154 }
155
156 static DOM::Node
157 rightmostChild(const DOM::Node& node)
158 {
159   if (!node) return node;
160
161   DOM::Node lastChild = node.get_lastChild();
162   if (!lastChild) return node;
163
164   return rightmostChild(lastChild);
165 }
166
167 static DOM::Node
168 leftSibling(const DOM::Node& node)
169 {
170   DOM::Node p = node;
171
172   if (!p) return p;
173
174   while (p.get_parentNode() && p.get_parentNode().get_firstChild() == p)
175     p = p.get_parentNode();
176
177   if (!p.get_parentNode()) return DOM::Node(0);
178
179   DOM::Node prevSibling = p.get_previousSibling();
180   assert(prevSibling);
181
182   return rightmostChild(prevSibling);
183 }
184
185 static DOM::Node
186 rightSibling(const DOM::Node& node)
187 {
188   DOM::Node p = node;
189
190   if (!p) return p;
191
192   DOM::Node firstChild = p.get_firstChild();
193   if (firstChild) return firstChild;
194
195   while (p.get_parentNode() && p.get_parentNode().get_lastChild() == p)
196     p = p.get_parentNode();
197
198   if (!p.get_parentNode()) return DOM::Node(0);
199
200   DOM::Node nextSibling = p.get_nextSibling();
201   assert(nextSibling);
202
203   return leftmostChild(nextSibling);
204 }
205
206 extern "C" GdomeElement*
207 find_common_ancestor(GdomeElement* first, GdomeElement* last)
208 {
209   DOM::Element p(first);
210   DOM::Element q(last);
211   return gdome_cast_el(findCommonAncestor(p, q).gdome_object());
212 }
213
214 extern "C" GdomeElement*
215 find_self_or_ancestor(GdomeElement* elem, const char* uri, const char* name)
216 {
217   DOM::Element el(elem);
218
219   while (el && (el.get_namespaceURI() != uri || el.get_localName() != name))
220     el = el.get_parentNode();
221
222   return gdome_cast_el(el.gdome_object());
223 }
224
225 extern "C" void
226 action_toggle(GdomeElement* elem)
227 {
228   DOM::Element el(elem);
229   if (el.get_namespaceURI() != MATHML_NS_URI || el.get_localName() != "maction") return;
230
231   guint idx;
232   if (el.hasAttribute("selection"))
233     idx = atoi(std::string(el.getAttribute("selection")).c_str());
234   else idx = 1;
235
236   idx++;
237
238   std::ostringstream os;
239   os << idx;
240   el.setAttribute("selection", os.str());
241 }
242
243 extern "C" void
244 find_common_siblings(GdomeElement* first, GdomeElement* last,
245                      GdomeElement** firstS, GdomeElement** lastS)
246 {
247   DOM::Element fs(0);
248   DOM::Element ls(0);
249
250   findCommonSiblings(DOM::Element(first), DOM::Element(last), fs, ls);
251
252   if (firstS != NULL) *firstS = gdome_cast_el(fs.gdome_object());
253   if (lastS != NULL) *lastS = gdome_cast_el(ls.gdome_object());
254 }
255
256 static DOM::Element
257 findElementWithAttribute(const DOM::Element& elem, const std::string& name)
258 {
259   DOM::Element el(elem);
260   while (el && !el.hasAttribute(name)) el = el.get_parentNode();
261   return el;
262 }
263
264 static DOM::Element
265 findElementWithAttributeNS(const DOM::Element& elem, const std::string& ns_uri, const std::string& name)
266 {
267   DOM::Element el(elem);
268   while (el && !el.hasAttributeNS(ns_uri, name)) el = el.get_parentNode();
269   return el;
270 }
271
272 extern "C" GdomeElement*
273 find_element_with_id(GdomeElement* elem, GdomeDOMString* ns_uri, GdomeDOMString* name)
274 {
275   assert(name != NULL);
276   DOM::Element el;
277   if (ns_uri != NULL)
278     el = findElementWithAttributeNS(DOM::Element(elem), DOM::GdomeString(ns_uri), DOM::GdomeString(name));
279   else
280     el = findElementWithAttribute(DOM::Element(elem), DOM::GdomeString(name));
281   return gdome_cast_el(el.gdome_object());
282 }
283
284 extern "C" GdomeDOMString*
285 find_hyperlink(GdomeElement* elem)
286 {
287   DOM::Element el = findElementWithAttribute(DOM::Element(elem),"href");
288   if (el) return el.getAttribute("href").gdome_str();
289   else return NULL;
290 }
291
292 extern "C" GdomeElement*
293 find_element_by_id(GdomeElement* root, GdomeDOMString* ns_uri, GdomeDOMString* name,
294                    const char* id)
295 {
296   DOM::Element el = findElementById(DOM::Element(root),
297                                     DOM::GdomeString(ns_uri), DOM::GdomeString(name),
298                                     DOM::GdomeString(id));
299   return gdome_cast_el(el.gdome_object());
300 }