1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/xml.cpp Wed Feb 25 12:44:10 2009 +0000
1.3 @@ -0,0 +1,519 @@
1.4 +#include "xml.h"
1.5 +
1.6 +#include <qmessagebox.h>
1.7 +#include <qcolor.h>
1.8 +#include <qstylesheet.h>
1.9 +#include <iostream>
1.10 +
1.11 +#include "misc.h"
1.12 +#include "settings.h"
1.13 +
1.14 +#include "version.h"
1.15 +
1.16 +static BranchObj *lastBranch;
1.17 +static FloatObj *lastFloat;
1.18 +
1.19 +extern Settings settings;
1.20 +
1.21 +mapBuilderHandler::mapBuilderHandler() {}
1.22 +
1.23 +mapBuilderHandler::~mapBuilderHandler() {}
1.24 +
1.25 +QString mapBuilderHandler::errorProtocol() { return errorProt; }
1.26 +
1.27 +bool mapBuilderHandler::startDocument()
1.28 +{
1.29 + errorProt = "";
1.30 + state = StateInit;
1.31 + laststate = StateInit;
1.32 + branchDepth=0;
1.33 + htmldata="";
1.34 + isVymPart=false;
1.35 + return true;
1.36 +}
1.37 +
1.38 +
1.39 +QString mapBuilderHandler::parseHREF(QString href)
1.40 +{
1.41 + QString type=href.section(":",0,0);
1.42 + QString path=href.section(":",1,1);
1.43 + if (!tmpDir.endsWith("/"))
1.44 + return tmpDir + "/" + path;
1.45 + else
1.46 + return tmpDir + path;
1.47 +}
1.48 +
1.49 +bool mapBuilderHandler::startElement ( const QString&, const QString&,
1.50 + const QString& eName, const QXmlAttributes& atts )
1.51 +{
1.52 + QColor col;
1.53 +// cout << "startElement <"<<eName<<"> state="<<state <<" laststate="<<laststate<<endl;
1.54 + if ( state == StateInit && (eName == "vymmap") )
1.55 + {
1.56 + state = StateMap;
1.57 + if (!atts.value( "version").isEmpty() )
1.58 + {
1.59 + mc->setVersion(atts.value( "version" ));
1.60 + if (!mc->checkVersion())
1.61 + QMessageBox::warning( 0, "Warning: Version Problem" ,
1.62 + "<h3>Map is newer than VYM</h3>"
1.63 + "<p>The map you are just trying to load was "
1.64 + "saved using vym " +atts.value("version")+". "
1.65 + "The version of this vym is " __VYM_VERSION__
1.66 + ". If you run into problems after pressing "
1.67 + "the ok-button below, updating vym should help.");
1.68 +
1.69 + }
1.70 + if (loadMode==NewMap)
1.71 + {
1.72 + if (!atts.value( "author").isEmpty() )
1.73 + {
1.74 + mc->setAuthor(atts.value( "author" ) );
1.75 + }
1.76 + if (!atts.value( "comment").isEmpty() )
1.77 + {
1.78 + mc->setComment (atts.value( "comment" ) );
1.79 + }
1.80 + if (!atts.value( "backgroundColor").isEmpty() )
1.81 + {
1.82 + col.setNamedColor(atts.value("backgroundColor"));
1.83 + mc->getCanvas()->setBackgroundColor(col);
1.84 + }
1.85 + if (!atts.value( "linkColorHint").isEmpty() )
1.86 + {
1.87 + if (atts.value("linkColorHint")=="HeadingColor")
1.88 + me->setLinkColorHint(HeadingColor);
1.89 + else
1.90 + me->setLinkColorHint(DefaultColor);
1.91 + }
1.92 + if (!atts.value( "linkStyle").isEmpty() )
1.93 + {
1.94 + QString s=atts.value("linkStyle");
1.95 + if (s=="StyleLine")
1.96 + me->setLinkStyle(StyleLine);
1.97 + else
1.98 + if (s=="StyleParabel")
1.99 + me->setLinkStyle(StyleParabel);
1.100 + else
1.101 + if (s=="StylePolyLine")
1.102 + me->setLinkStyle(StylePolyLine);
1.103 + else
1.104 + me->setLinkStyle(StylePolyParabel);
1.105 + }
1.106 + if (!atts.value( "linkColor").isEmpty() )
1.107 + {
1.108 + col.setNamedColor(atts.value("linkColor"));
1.109 + me->setLinkColor(col);
1.110 + }
1.111 + }
1.112 + } else if ( eName == "select" && state == StateMap )
1.113 + {
1.114 + state=StateMapSelect;
1.115 + } else if ( eName == "setting" && state == StateMap )
1.116 + {
1.117 + state=StateMapSetting;
1.118 + if (loadMode==NewMap)
1.119 + readSettingAttr (atts);
1.120 + } else if ( eName == "mapcenter" && state == StateMap )
1.121 + {
1.122 + state=StateMapCenter;
1.123 + if (loadMode==NewMap)
1.124 + {
1.125 + // Really use the found mapcenter as MCO in a new map
1.126 + lastBranch=mc; // avoid empty pointer
1.127 + } else
1.128 + {
1.129 + // Treat the found mapcenter as a branch
1.130 + // in an existing map
1.131 + LinkableMapObj* lmo=me->getSelection();
1.132 + if (lmo && (typeid(*lmo) == typeid(BranchObj) )
1.133 + || (typeid(*lmo) == typeid(MapCenterObj) ) )
1.134 + {
1.135 + lastBranch=(BranchObj*)(lmo);
1.136 + if (loadMode==ImportAdd)
1.137 + {
1.138 + lastBranch->addBranch();
1.139 + lastBranch=lastBranch->getLastBranch();
1.140 + } else
1.141 + lastBranch->clear();
1.142 + } else
1.143 + return false;
1.144 + }
1.145 + readBranchAttr (atts);
1.146 + } else if ( (eName == "standardflag" ||eName == "standardFlag") && state == StateMapCenter)
1.147 + {
1.148 + state=StateMapCenterStandardFlag;
1.149 + } else if ( eName == "heading" && state == StateMapCenter)
1.150 + {
1.151 + state=StateMapCenterHeading;
1.152 + if (!atts.value( "textColor").isEmpty() )
1.153 + {
1.154 + col.setNamedColor(atts.value("textColor"));
1.155 + lastBranch->setColor(col ,false );
1.156 + }
1.157 + } else if ( eName == "note" && state == StateMapCenter)
1.158 + { // only for backward compatibility (<1.4.6). Use htmlnote now.
1.159 + state=StateMapCenterNote;
1.160 + if (!readNoteAttr (atts) ) return false;
1.161 + } else if ( eName == "htmlnote" && state == StateMapCenter)
1.162 + {
1.163 + laststate=state;
1.164 + state=StateHtmlNote;
1.165 + } else if ( eName == "floatimage" && state == StateMapCenter )
1.166 + {
1.167 + state=StateMapCenterFloatImage;
1.168 + lastBranch->addFloatImage();
1.169 + lastFloat=lastBranch->getLastFloatImage();
1.170 + if (!readFloatImageAttr(atts)) return false;
1.171 + } else if ( eName == "branch" && state == StateMap)
1.172 + {
1.173 + // This is used in vymparts, which have no mapcenter!
1.174 + isVymPart=true;
1.175 + state=StateBranch;
1.176 + LinkableMapObj* lmo=me->getSelection();
1.177 + if (lmo && (typeid(*lmo) == typeid(BranchObj) )
1.178 + || (typeid(*lmo) == typeid(MapCenterObj) ) )
1.179 + {
1.180 + lastBranch=(BranchObj*)(lmo);
1.181 + if (loadMode==ImportAdd)
1.182 + {
1.183 + lastBranch->addBranch();
1.184 + lastBranch=lastBranch->getLastBranch();
1.185 + } else
1.186 + lastBranch->clear();
1.187 + } else
1.188 + return false;
1.189 + branchDepth=1;
1.190 + readBranchAttr (atts);
1.191 + } else if ( eName == "branch" && state == StateMapCenter)
1.192 + {
1.193 + state=StateBranch;
1.194 + branchDepth=1;
1.195 + lastBranch->addBranch();
1.196 + lastBranch=lastBranch->getLastBranch();
1.197 + readBranchAttr (atts);
1.198 + } else if ( (eName=="standardflag" ||eName == "standardFlag") && state == StateBranch)
1.199 + {
1.200 + state=StateBranchStandardFlag;
1.201 + } else if ( eName == "heading" && state == StateBranch)
1.202 + {
1.203 + state=StateBranchHeading;
1.204 + if (!atts.value( "textColor").isEmpty() )
1.205 + {
1.206 + col.setNamedColor(atts.value("textColor"));
1.207 + lastBranch->setColor(col ,false );
1.208 + }
1.209 + } else if ( eName == "note" && state == StateBranch)
1.210 + {
1.211 + state=StateBranchNote;
1.212 + if (!readNoteAttr (atts) ) return false;
1.213 + } else if ( eName == "htmlnote" && state == StateBranch)
1.214 + {
1.215 + laststate=state;
1.216 + state=StateHtmlNote;
1.217 + no.clear();
1.218 + if (!atts.value( "fonthint").isEmpty() )
1.219 + no.setFontHint(atts.value ("fonthint") );
1.220 + } else if ( eName == "floatimage" && state == StateBranch )
1.221 + {
1.222 + state=StateBranchFloatImage;
1.223 + lastBranch->addFloatImage();
1.224 + lastFloat=lastBranch->getLastFloatImage();
1.225 + if (!readFloatImageAttr(atts)) return false;
1.226 + } else if ( eName == "branch" && state == StateBranch )
1.227 + {
1.228 + lastBranch->addBranch();
1.229 + lastBranch=lastBranch->getLastBranch();
1.230 + branchDepth++;
1.231 + readBranchAttr (atts);
1.232 + } else if ( eName == "html" && state == StateHtmlNote )
1.233 + {
1.234 + state=StateHtml;
1.235 + htmldata="<"+eName;
1.236 + readHtmlAttr(atts);
1.237 + htmldata+=">";
1.238 + } else if ( state == StateHtml )
1.239 + {
1.240 + // accept all while in html mode,
1.241 + htmldata+="<"+eName;
1.242 + readHtmlAttr(atts);
1.243 + htmldata+=">";
1.244 + } else
1.245 + return false; // Error
1.246 + return true;
1.247 +}
1.248 +
1.249 +bool mapBuilderHandler::endElement ( const QString&, const QString&, const QString &eName)
1.250 +{
1.251 +// cout << "endElement </"<<eName<<"> state="<<state <<" laststate="<<laststate<<endl;
1.252 + switch ( state )
1.253 + {
1.254 + case StateMapSelect: state=StateMap; return true;
1.255 + case StateMapSetting: state=StateMap; return true;
1.256 + case StateMapCenter: state=StateMap; return true;
1.257 + case StateMapCenterStandardFlag: state=StateMapCenter; return true;
1.258 + case StateMapCenterHeading: state=StateMapCenter; return true;
1.259 + case StateMapCenterNote: state=StateMapCenter; return true;
1.260 + case StateMapCenterFloatImage: state=StateMapCenter; return true;
1.261 + case StateBranch:
1.262 + if (branchDepth>1)
1.263 + {
1.264 + branchDepth--;
1.265 + state=StateBranch;
1.266 + } else
1.267 + {
1.268 + branchDepth=0;
1.269 + if (isVymPart)
1.270 + state=StateMap;
1.271 + else
1.272 + state=StateMapCenter;
1.273 + }
1.274 + lastBranch=(BranchObj*)(lastBranch->getParObj());
1.275 + return true;
1.276 + case StateBranchStandardFlag: state=StateBranch; return true;
1.277 + case StateBranchHeading: state=StateBranch; return true;
1.278 + case StateBranchNote: state=StateBranch; return true;
1.279 + case StateBranchFloatImage: state=StateBranch; return true;
1.280 + case StateHtmlNote: state=laststate; return true;
1.281 + case StateHtml:
1.282 + htmldata+="</"+eName+">";
1.283 + if (eName=="html")
1.284 + {
1.285 + state=StateHtmlNote;
1.286 + htmldata.replace ("<br></br>","<br />");
1.287 + no.setNote (htmldata);
1.288 + lastBranch->setNote (no);
1.289 + return true;
1.290 + } else
1.291 + {
1.292 + return true;
1.293 + }
1.294 + case StateMap: state=StateInit; return true;
1.295 + default :
1.296 + // even for HTML includes, this should never be reached
1.297 + return false;
1.298 + }
1.299 +}
1.300 +
1.301 +bool mapBuilderHandler::characters ( const QString& ch)
1.302 +{
1.303 + //cout << "characters \""<<ch<<"\" state="<<state <<" laststate="<<laststate<<endl;
1.304 +
1.305 + QString ch_org=quotemeta (ch);
1.306 + QString ch_simplified=ch.simplifyWhiteSpace();
1.307 + if ( ch_simplified.isEmpty() ) return true;
1.308 +
1.309 + switch ( state )
1.310 + {
1.311 + case StateInit: break;
1.312 + case StateMap: break;
1.313 + case StateMapSelect:
1.314 + me->select(ch_simplified);
1.315 + break;
1.316 + case StateMapSetting:break;
1.317 + case StateMapCenter: break;
1.318 + case StateMapCenterStandardFlag:
1.319 + lastBranch->activateStandardFlag(ch_simplified);
1.320 + break;
1.321 + case StateMapCenterHeading:
1.322 + lastBranch->setHeading(ch_simplified);
1.323 + break;
1.324 + case StateMapCenterNote:
1.325 + lastBranch->setNote(ch_simplified);
1.326 + break;
1.327 + case StateBranch: break;
1.328 + case StateBranchStandardFlag:
1.329 + lastBranch->activateStandardFlag(ch_simplified);
1.330 + break;
1.331 + case StateBranchHeading:
1.332 + lastBranch->setHeading(ch_simplified);
1.333 + break;
1.334 + case StateBranchNote:
1.335 + lastBranch->setNote(ch_simplified);
1.336 + break;
1.337 + case StateBranchFloatImage: break;
1.338 + case StateHtmlNote: break;
1.339 + case StateHtml:
1.340 + htmldata+=ch_org;
1.341 + break;
1.342 + default:
1.343 + return false;
1.344 + }
1.345 + return true;
1.346 +}
1.347 +
1.348 +QString mapBuilderHandler::errorString()
1.349 +{
1.350 + return "the document is not in the VYM file format";
1.351 +}
1.352 +
1.353 +bool mapBuilderHandler::fatalError( const QXmlParseException& exception )
1.354 +{
1.355 + errorProt += QString( "fatal parsing error: %1 in line %2, column %3\n")
1.356 + .arg( exception.message() )
1.357 + .arg( exception.lineNumber() )
1.358 + .arg( exception.columnNumber() );
1.359 +
1.360 + return QXmlDefaultHandler::fatalError( exception );
1.361 +}
1.362 +
1.363 +void mapBuilderHandler::setMapEditor (MapEditor* e)
1.364 +{
1.365 + me=e;
1.366 + mc=me->getMapCenter();
1.367 +}
1.368 +
1.369 +void mapBuilderHandler::setTmpDir (QString tp)
1.370 +{
1.371 + tmpDir=tp;
1.372 +}
1.373 +
1.374 +void mapBuilderHandler::setLoadMode (const LoadMode &lm)
1.375 +{
1.376 + loadMode=lm;
1.377 +}
1.378 +
1.379 +bool mapBuilderHandler::readBranchAttr (const QXmlAttributes& a)
1.380 +{
1.381 + bool okx,oky;
1.382 + int x,y;
1.383 + if (!a.value( "absPosX").isEmpty() && loadMode==NewMap && branchDepth<2)
1.384 + {
1.385 + if (!a.value( "absPosY").isEmpty() )
1.386 + {
1.387 + x=a.value("absPosX").toInt (&okx, 10);
1.388 + y=a.value("absPosY").toInt (&oky, 10);
1.389 + if (okx && oky)
1.390 + lastBranch->move(x,y);
1.391 + else
1.392 + return false; // Couldn't read absPos
1.393 + }
1.394 + }
1.395 + if (!a.value( "scrolled").isEmpty() )
1.396 + lastBranch->toggleScroll();
1.397 + if (!a.value( "url").isEmpty() )
1.398 + lastBranch->setURL (a.value ("url"));
1.399 + if (!a.value( "vymLink").isEmpty() )
1.400 + lastBranch->setVymLink (a.value ("vymLink"));
1.401 + if (!a.value( "frameType").isEmpty() )
1.402 + lastBranch->setFrameType (a.value("frameType"));
1.403 + return true;
1.404 +}
1.405 +
1.406 +bool mapBuilderHandler::readNoteAttr (const QXmlAttributes& a)
1.407 +{ // only for backward compatibility (<1.4.6). Use htmlnote now.
1.408 + no.clear();
1.409 + QString fn;
1.410 + if (!a.value( "href").isEmpty() )
1.411 + {
1.412 + // Load note
1.413 + fn=parseHREF(a.value ("href") );
1.414 + QFile file (fn);
1.415 + QString s; // Reading a note
1.416 +
1.417 + if ( !file.open( IO_ReadOnly) )
1.418 + {
1.419 + qWarning ("mapBuilderHandler::readNoteAttr: Couldn't load "+fn);
1.420 + return false;
1.421 + }
1.422 + QTextStream stream( &file );
1.423 + QString lines;
1.424 + while ( !stream.eof() ) {
1.425 + lines += stream.readLine()+"\n";
1.426 + }
1.427 + file.close();
1.428 + // Convert to richtext
1.429 + if ( !QStyleSheet::mightBeRichText( lines ) )
1.430 + {
1.431 + // Here we are workarounding the QT conversion method:
1.432 + // convertFromPlainText does not generate valid xml, needed
1.433 + // for the parser, but just <p> and <br> without closing tags.
1.434 + // So we have to add those by ourselves
1.435 + //lines=quotemeta (lines);
1.436 + lines = QStyleSheet::convertFromPlainText( lines, QStyleSheetItem::WhiteSpaceNormal );
1.437 + lines.replace ("<br>","<br />");
1.438 + }
1.439 +
1.440 + lines ="<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body>"+lines + "</p></body></html>";
1.441 + no.setNote (lines);
1.442 + }
1.443 + if (!a.value( "fonthint").isEmpty() )
1.444 + no.setFontHint(a.value ("fonthint") );
1.445 + if (state == StateMapCenterNote)
1.446 + mc->setNote(no);
1.447 + else
1.448 + lastBranch->setNote(no);
1.449 + return true;
1.450 +}
1.451 +
1.452 +bool mapBuilderHandler::readFloatImageAttr (const QXmlAttributes& a)
1.453 +{
1.454 + if (!a.value( "useOrientation").isEmpty() )
1.455 + {
1.456 + if (a.value ("useOrientation") =="true")
1.457 + lastFloat->setUseOrientation (true);
1.458 + else
1.459 + lastFloat->setUseOrientation (false);
1.460 + }
1.461 + if (!a.value( "href").isEmpty() )
1.462 + {
1.463 + // Load FloatImage
1.464 + if (!lastFloat->load (parseHREF(a.value ("href") ) ))
1.465 + {
1.466 + QMessageBox::warning( 0, "Warning: " ,
1.467 + "Couldn't load float image\n"+parseHREF(a.value ("href") ));
1.468 + lastBranch->removeFloatImage(((FloatImageObj*)(lastFloat)));
1.469 + lastFloat=NULL;
1.470 + return true;
1.471 + }
1.472 +
1.473 + }
1.474 + if (!a.value( "floatExport").isEmpty() )
1.475 + {
1.476 + if (a.value ("floatExpofrt") =="true")
1.477 + lastFloat->setFloatExport (true);
1.478 + else
1.479 + lastFloat->setFloatExport (false);
1.480 + }
1.481 + if (!a.value( "zPlane").isEmpty() )
1.482 + lastFloat->setZ (a.value("zPlane").toInt ());
1.483 + int x,y;
1.484 + bool okx,oky;
1.485 + if (!a.value( "relPosX").isEmpty() )
1.486 + {
1.487 + if (!a.value( "relPosY").isEmpty() )
1.488 + {
1.489 + // read relPos
1.490 + x=a.value("relPosX").toInt (&okx, 10);
1.491 + y=a.value("relPosY").toInt (&oky, 10);
1.492 + if (okx && oky)
1.493 + lastFloat->setRelPos (QPoint (x,y) );
1.494 + else
1.495 + // Couldn't read relPos
1.496 + return false;
1.497 + }
1.498 + }
1.499 + return true;
1.500 +}
1.501 +
1.502 +bool mapBuilderHandler::readHtmlAttr (const QXmlAttributes& a)
1.503 +{
1.504 + for (int i=1; i<=a.count(); i++)
1.505 + htmldata+=" "+a.localName(i-1)+"=\""+a.value(i-1)+"\"";
1.506 + return true;
1.507 +}
1.508 +
1.509 +bool mapBuilderHandler::readSettingAttr (const QXmlAttributes& a)
1.510 +{
1.511 + if (!a.value( "key").isEmpty() )
1.512 + {
1.513 + if (!a.value( "value").isEmpty() )
1.514 + settings.setLocalEntry (me->getDestPath(), a.value ("key"), a.value ("value"));
1.515 + else
1.516 + return false;
1.517 +
1.518 + } else
1.519 + return false;
1.520 +
1.521 + return true;
1.522 +}