]> git.sven.stormbind.net Git - sven/vym.git/blob - src/xml-freemind.cpp
Replace Pierre as the maintainer
[sven/vym.git] / src / xml-freemind.cpp
1 #include "xml-freemind.h"
2
3 #include <QDebug>
4 #include <QMessageBox>
5
6 #include "branchitem.h"
7 #include "misc.h"
8 #include "vymmodel.h"
9
10 extern Settings settings;
11 extern QString vymVersion;
12
13 bool parseFreemindHandler::nodeLikeState() 
14 {
15     if (state == StateCenter || state == StateMainNode || state == StateNode)
16         return true;
17     else
18         return false;
19 }
20
21 bool parseFreemindHandler::startDocument() // FIXME-3 import not complete yet
22 {
23     errorProt = "";
24     state = StateInit;
25     stateStack.clear();
26     stateStack.append(StateInit);
27     isVymPart = false;
28     return true;
29 }
30
31 QString parseFreemindHandler::parseHREF(QString href)
32 {
33     QString type = href.section(":", 0, 0);
34     QString path = href.section(":", 1, 1);
35     if (!tmpDir.endsWith("/"))
36         return tmpDir + "/" + path;
37     else
38         return tmpDir + path;
39 }
40
41 bool parseFreemindHandler::startElement(const QString &, const QString &,
42                                         const QString &eName,
43                                         const QXmlAttributes &atts)
44 {
45     QColor col;
46     /* Testing
47     if (eName.contains("node"))
48     qDebug() << "startElement: <" << eName
49              << ">     state=" << state
50              << "  laststate=" << stateStack.last();
51              //<< "   loadMode=" << loadMode
52              //<<"       line=" << QXmlDefaultHandler::lineNumber();
53     */
54
55     stateStack.append(state);
56     if (state == StateInit && (eName == "map")) {
57         state = StateMap;
58         if (!atts.value("version").isEmpty()) {
59             QString v = "0.9.0";
60             if (!versionLowerOrEqual(atts.value("version"), v))
61                 QMessageBox::warning(
62                     0, "Warning: Version Problem",
63                     "<h3>Freemind map is newer than version " + v +
64                         " </h3>"
65                         "<p>The map you are just trying to load was "
66                         "saved using freemind " +
67                         atts.value("version") +
68                         ". "
69                         "Your version of vym can parse freemind " +
70                         v + ".");
71         }
72         // Create mapcenter
73         model->clear();
74         mapCenter = model->createMapCenter();
75         lastBranch = mapCenter;
76
77         // Create two hidden branches, because Freemind has no relative
78         // positioning for mainbranches
79         mainBranchLeft = model->createBranch(lastBranch);
80         mainBranchRight = model->createBranch(lastBranch);
81
82         mainBranchLeft->setRelPos(QPointF(-200, 0));
83         mainBranchLeft->setHeadingPlainText(" ");
84         model->emitDataChanged(mainBranchLeft);
85
86         mainBranchRight->setRelPos(QPointF(200, 0));
87         mainBranchRight->setHeadingPlainText(" ");
88         model->emitDataChanged(mainBranchRight);
89     }
90     else if (eName == "attribute_registry" && state == StateMap) {
91         state = StateAttributeRegistry;
92     }
93     else if (eName == "attribute_name" && state == StateAttributeRegistry) {
94         state = StateAttributeName;
95     }
96     else if (eName == "attribute_value" && state == StateAttributeName) {
97         state = StateAttributeValue;
98     }
99     else if (eName == "node" && state == StateMap) {
100         state = StateCenter;
101         lastBranch = mapCenter;
102         readNodeAttr(atts);
103     }
104     else if (eName == "node" && state == StateCenter) {
105         state = StateMainNode;
106         lastBranch = model->createBranch(lastBranch);
107         readNodeAttr(atts);
108     }
109     else if (eName == "node" && (state == StateNode || state == StateMainNode)) {
110         state = StateNode;
111         lastBranch = model->createBranch(lastBranch);
112         readNodeAttr(atts);
113     }
114     else if (eName == "properties") {
115     }
116     else if (eName == "map_styles") {
117     }
118     else if (eName == "font" && nodeLikeState())
119     { 
120         // FIXME-3 not implemented
121         state = StateFont;
122     }
123     else if (eName == "edge" && nodeLikeState())
124     {
125          // FIXME-3 xlink not implemented
126         state = StateEdge;
127     }
128     else if (eName == "hook" && nodeLikeState()) {
129         state = StateHook;
130     }
131     else if (eName == "icon" && nodeLikeState()) {
132         state = StateIcon;
133         if (!atts.value("BUILTIN").isEmpty()) {
134             QString f = atts.value("BUILTIN");
135             QString v;
136             if (f == "help")
137                 v = "questionmark";
138             else if (f == "messagebox_warning")
139                 v = "freemind-warning";
140             else if (f == "idea")
141                 v = "lamp";
142             else if (f == "button_ok")
143                 v = "hook-green";
144             else if (f == "button_cancel")
145                 v = "cross-red";
146             else if (f.contains("full-"))
147                 v = f.replace("full-", "freemind-priority-");
148             else if (f == "back")
149                 v = "freemind-back";
150             else if (f == "forward")
151                 v = "freemind-forward";
152             else if (f == "attach")
153                 v = "freemind-attach";
154             else if (f == "ksmiletris")
155                 v = "smiley-good"; //
156             else if (f == "clanbomber")
157                 v = "freemind-clanbomber";
158             else if (f == "desktop_new")
159                 v = "freemind-desktopnew";
160             else if (f == "flag")
161                 v = "freemind-flag";
162             else if (f == "gohome")
163                 v = "freemind-gohome";
164             else if (f == "kaddressbook")
165                 v = "freemind-kaddressbook";
166             else if (f == "knotify")
167                 v = "freemind-knotify";
168             else if (f == "korn")
169                 v = "freemind-korn";
170             else if (f == "Mail")
171                 v = "freemind-mail";
172             else if (f == "password")
173                 v = "freemind-password";
174             else if (f == "pencil")
175                 v = "freemind-pencil";
176             else if (f == "stop")
177                 v = "freemind-stop";
178             else if (f == "wizard")
179                 v = "freemind-wizard";
180             else if (f == "xmag")
181                 v = "freemind-xmag";
182             else if (f == "bell")
183                 v = "freemind-bell";
184             else if (f == "bookmark")
185                 v = "freemind-bookmark";
186             else if (f == "penguin")
187                 v = "freemind-penguin";
188             else if (f == "licq")
189                 v = "freemind-licq";
190             else
191                 qWarning() << "parseFreemindHandler: Unknown icon found: " << f;
192
193             lastBranch->activateStandardFlagByName(v);
194         }
195     }
196     else if (eName == "arrowlink" && nodeLikeState()) {
197         state = StateArrowLink;
198     }
199     else if (eName == "cloud" && nodeLikeState()) {
200         state = StateCloud;
201     }
202     else if (eName == "richcontent" && nodeLikeState()) {
203         state = StateRichContent;
204         return readRichContentAttr(atts);
205     }
206     else if (eName == "html" && state == StateRichContent) {
207         state = StateHtml;
208         htmldata = "<" + eName;
209         readHtmlAttr(atts);
210         htmldata += ">";
211     }
212     else if (eName == "text" && state == StateHook) {
213         state = StateText;
214     }
215     else if (state == StateHtml) {
216         // accept all while in html mode,
217         htmldata += "<" + eName;
218         readHtmlAttr(atts);
219         htmldata += ">";
220     }
221     else {
222         // Usually we would return an error here
223         // In order to not break with every new element in FreeMind or
224         // FreePlane, better ignore the new element for now
225         state = StateUnknown;
226         qWarning()
227             << "parseFreemindHandler: Unknown element found and ignoring:: "
228             << eName;
229     }
230     return true;
231 }
232
233 bool parseFreemindHandler::endElement(const QString &, const QString &,
234                                       const QString &eName)
235 {
236     /* Testing
237     QString h;
238     lastBranch ? h = lastBranch->getHeadingPlain() : h = "";
239     if (eName.contains("node"))
240     qDebug() << "endElement </" << eName << ">  state=" << state << " lastBranch=" << h;
241     */
242
243     switch (state) {
244         case StateMap:
245             // Freemind does not have the two "extra" mainbranches used here,
246             // so we have to update mapcenter
247             model->emitDataChanged(mapCenter);
248
249             // Remove helper branches, if not needed
250             if (mainBranchLeft->childCount() == 0)
251                 model->deleteItem(mainBranchLeft);
252             if (mainBranchRight->childCount() == 0)
253                 model->deleteItem(mainBranchRight);
254             break;
255         case StateCenter:
256         case StateMainNode:
257         case StateNode:
258             model->emitDataChanged(lastBranch);
259             lastBranch = (BranchItem *)lastBranch->parent();
260             if (lastBranch) 
261                 lastBranch->setLastSelectedBranch(0);
262             else
263                 qWarning() << "xml-vym:  lastBranch == nullptr";
264             break;
265         case StateRichContent:
266             if (!htmldata.isEmpty()) {
267                 vymtext.setAutoText(htmldata);
268                 if (htmlPurpose == Node)
269                     lastBranch->setHeading(vymtext);
270                 else if (htmlPurpose == Note)
271                     lastBranch->setNote(vymtext);
272             }
273             break;
274         case StateHtml:
275             htmldata += "</" + eName + ">";
276             if (eName == "html") {
277                 htmldata = htmldata.replace("<br></br>", "<br />");
278                 htmldata = htmldata.replace("\\n</p>", "</p>");
279             }
280             break;
281         default:
282             break;
283     }
284     state = stateStack.takeLast();
285     return true;
286 }
287
288 bool parseFreemindHandler::characters(const QString &ch)
289 {
290     //qDebug() << "characters \"" << qPrintable(ch) << "\"  state=" << state;
291
292     QString ch_org = quoteMeta(ch);
293     QString ch_simplified = ch.simplified();
294     if (ch_simplified.isEmpty())
295         return true;
296
297     switch (state) {
298     case StateInit:
299         break;
300     case StateMap:
301         break;
302     case StateNode:
303         break;
304     case StateCloud:
305         break;
306     case StateEdge:
307         break;
308     case StateIcon:
309         break;
310     case StateArrowLink:
311         break;
312     case StateFont:
313         break;
314     case StateHook:
315         break;
316     case StateText:
317         lastBranch->setNote(ch_simplified);
318         break;
319     case StateHtml:
320         htmldata += ch_org;
321         break;
322     case StateUnknown:
323         break;
324     default:
325         return false;
326     }
327     return true;
328 }
329
330 QString parseFreemindHandler::errorString()
331 {
332     return "the document is not in the Freemind file format";
333 }
334
335 bool parseFreemindHandler::readNodeAttr(const QXmlAttributes &a)
336 {
337     if (state == StateMainNode)
338     {
339         // Freemind has a different concept for mainbranches
340         // Move either to left or right side of mapcenter
341         if (!a.value("POSITION").isEmpty()) {
342             if (a.value("POSITION") == "left")
343                 model->relinkBranch(lastBranch, mainBranchLeft);
344             else if (a.value("POSITION") == "right")
345                 model->relinkBranch(lastBranch, mainBranchRight);
346         }
347     }
348
349     if (a.value("FOLDED") == "true")
350         lastBranch->toggleScroll();
351
352     if (!a.value("TEXT").isEmpty()) {
353         lastBranch->setHeadingPlainText(
354             a.value("TEXT")); // FIXME-3 what about RT?
355         // model->setHeading (a.value ("TEXT"), lastBranch);
356     }
357
358     if (!a.value("COLOR").isEmpty())
359         lastBranch->setHeadingColor(QColor(a.value("COLOR")));
360
361     if (!a.value("LINK").isEmpty())
362         lastBranch->setURL(a.value("LINK"));
363     return true;
364 }
365
366 bool parseFreemindHandler::readRichContentAttr(const QXmlAttributes &a)
367 {
368     if (a.value("TYPE") == "NODE")
369         htmlPurpose = Node;
370     else if (a.value("TYPE") == "NOTE")
371         htmlPurpose = Note;
372     else {
373         htmlPurpose = Unknown;
374         qWarning()
375             << "parseFreemindHandler: Unknown purpose of richContent found: "
376             << a.value("TYPE");
377         ;
378         // FIXME-3 Usually we would stop here, ignore for now
379         // return false;
380     }
381     return true;
382 }