X-Git-Url: https://git.sven.stormbind.net/?a=blobdiff_plain;f=src%2Fxml-vym.cpp;fp=src%2Fxml-vym.cpp;h=d4f922847aff1a9e5d829bb08adf12616136e99a;hb=d483bd8e6523c23c6f1d8908a2e0611c2bc9ff4f;hp=0000000000000000000000000000000000000000;hpb=7dfa3fe589d1722d49681f42cdb0bf1e6efb5223;p=sven%2Fvym.git diff --git a/src/xml-vym.cpp b/src/xml-vym.cpp new file mode 100644 index 0000000..d4f9228 --- /dev/null +++ b/src/xml-vym.cpp @@ -0,0 +1,1147 @@ +#include "xml-vym.h" + +#include +#include +#include +#include + +#include "attributeitem.h" +#include "branchitem.h" +#include "flag.h" +#include "linkablemapobj.h" +#include "mainwindow.h" +#include "misc.h" +#include "settings.h" +#include "slideitem.h" +#include "task.h" +#include "taskmodel.h" +#include "xlinkitem.h" + +extern Main *mainWindow; +extern Settings settings; +extern TaskModel *taskModel; +extern QString vymVersion; + +parseVYMHandler::parseVYMHandler() +{ + // Default is to load everything + contentFilter = 0x0000; // TODO use filters for all content types below +} + +void parseVYMHandler::setContentFilter(const int &c) { contentFilter = c; } + +bool parseVYMHandler::startDocument() +{ + errorProt = ""; + state = StateInit; + stateStack.clear(); + stateStack.append(StateInit); + htmldata = ""; + isVymPart = false; + useProgress = false; + return true; +} + +bool parseVYMHandler::startElement(const QString &, const QString &, + const QString &eName, + const QXmlAttributes &atts) +{ + QColor col; + /* Testing + qDebug() << "startElement: <" << eName + << "> state=" << state + << " laststate=" << stateStack.last() + << " loadMode=" << loadMode + //<<" line=" << QXmlDefaultHandler::lineNumber(); + << "contentFilter=" << contentFilter; + */ + + stateStack.append(state); + if (state == StateInit && (eName == "vymmap")) { + state = StateMap; + branchesTotal = 0; + branchesCounter = 0; + + if (loadMode == NewMap || loadMode == DefaultMap) { + // Create mapCenter + model->clear(); + lastBranch = NULL; + + readMapAttr(atts); + } + // Check version + if (!atts.value("version").isEmpty()) { + version = atts.value("version"); + if (!versionLowerOrEqualThanVym(version)) { + QMessageBox::warning( + 0, QObject::tr("Warning: Version Problem"), + QObject::tr( + "

Map is newer than VYM

" + "

The map you are just trying to load was " + "saved using vym %1. " + "The version of this vym is %2. " + "If you run into problems after pressing " + "the ok-button below, updating vym should help.

") + .arg(version) + .arg(vymVersion) + + QObject::tr( + "

The map will be opened readonly, because not " + "all information from new maps can be saved with this " + "version of vym. Please be careful!")); + model->setReadOnly(true); + } + else + model->setVersion(version); + } + } + else if (eName == "mapdesign" && state == StateMap) { + state = StateMapDesign; + } + else if (eName == "md" && state == StateMapDesign) { + state = StateMD; + readMapDesignCompatibleAttr(atts); + } + else if (eName == "select" && state == StateMap) { + state = StateMapSelect; + } + else if (eName == "setting" && state == StateMap) { + state = StateMapSetting; + if (loadMode == NewMap) { + htmldata.clear(); + readSettingAttr(atts); + } + } + else if (eName == "slide" && state == StateMap) { + state = StateMapSlide; + if (!(contentFilter & SlideContent)) { + // Ignore slides during paste + lastSlide = model->addSlide(); + if (insertPos >= 0) + model->relinkSlide(lastSlide, insertPos); + + readSlideAttr(atts); + } + } + else if (eName == "mapcenter" && state == StateMap) { + state = StateMapCenter; + if (loadMode == NewMap) { + // Really use the found mapcenter as MCO in a new map + lastBranch = model->createMapCenter(); + } + else { + // Treat the found mapcenter as a branch + // in an existing map + BranchItem *bi = model->getSelectedBranch(); + if (bi) { + lastBranch = bi; + if (loadMode == ImportAdd) { + // Import Add + if (insertPos < 0) + lastBranch = model->createBranch(lastBranch); + else { + lastBranch = model->addNewBranch(lastBranch, insertPos); + insertPos++; + } + } + else { + // Import Replace + if (insertPos < 0) { + insertPos = lastBranch->num() + 1; + model->clearItem(lastBranch); + } + else { + BranchItem *pi = bi->parentBranch(); + lastBranch = model->addNewBranch(pi, insertPos); + insertPos++; + } + } + } + else + // if nothing selected, add mapCenter without parent + lastBranch = model->createMapCenter(); + } + readBranchAttr(atts); + } + else if ((eName == "standardflag" || eName == "standardFlag") && + (state == StateMapCenter || state == StateBranch)) { + state = StateStandardFlag; + } + else if (eName == "userflagdef" && state == StateMap) { + state = StateUserFlagDef; + return (readUserFlagDefAttr(atts)); + } + else if (eName == "userflag" && + (state == StateMapCenter || state == StateBranch)) { + state = StateUserFlag; + return (readUserFlagAttr(atts)); + } + else if (eName == "heading" && + (state == StateMapCenter || state == StateBranch || + state == StateInit)) { + if (state == StateInit) { + // Only read some stuff like VymNote or Heading + // e.g. for undo/redo + lastBranch = model->getSelectedBranch(); + if (version.isEmpty()) + version = "0.0.0"; + } + if (!lastBranch) + return false; + + state = StateHeading; + htmldata.clear(); + vymtext.clear(); + if (!atts.value("fonthint").isEmpty()) + vymtext.setFontHint(atts.value("fonthint")); + if (!atts.value("textMode").isEmpty()) { + if (atts.value("textMode") == "richText") + vymtext.setRichText(true); + else + vymtext.setRichText(false); + } + if (!atts.value("textColor").isEmpty()) { + // For compatibility with <= 2.4.0 set both branch and + // heading color + col.setNamedColor(atts.value("textColor")); + lastBranch->setHeadingColor(col); + vymtext.setColor(col); + } + if (!atts.value("text").isEmpty()) + vymtext.setText(unquoteQuotes(atts.value("text"))); + } + else if (eName == "task" && + (state == StateMapCenter || state == StateBranch)) { + state = StateTask; + lastTask = taskModel->createTask(lastBranch); + if (!readTaskAttr(atts)) + return false; + } + else if (eName == "note" && + (state == StateMapCenter || + state == StateBranch)) { // only for backward compatibility + // (<1.4.6). Use htmlnote now. + state = StateNote; + htmldata.clear(); + vymtext.clear(); + if (!readNoteAttr(atts)) + return false; + } + else if (eName == "htmlnote" && + state == StateMapCenter) { // only for backward compatibility. Use + // vymnote now + state = StateHtmlNote; + vymtext.clear(); + if (!atts.value("fonthint").isEmpty()) + vymtext.setFontHint(atts.value("fonthint")); + } + else if (eName == "vymnote" && + (state == StateMapCenter || state == StateBranch || + state == StateInit)) { + if (state == StateInit) + // Only read some stuff like VymNote or Heading + // e.g. for undo/redo + { + lastBranch = model->getSelectedBranch(); + if (version.isEmpty()) + version = "0.0.0"; + } + state = StateVymNote; + htmldata.clear(); + vymtext.clear(); + if (!atts.value("fonthint").isEmpty()) + vymtext.setFontHint(atts.value("fonthint")); + if (!atts.value("textMode").isEmpty()) { + if (atts.value("textMode") == "richText") + vymtext.setRichText(true); + else + vymtext.setRichText(false); + } + if (!atts.value("text").isEmpty()) + vymtext.setText(unquoteQuotes(atts.value("text"))); + } + else if (eName == "floatimage" && + (state == StateMapCenter || state == StateBranch)) { + state = StateImage; + lastImage = model->createImage(lastBranch); + if (!readImageAttr(atts)) + return false; + } + else if ((eName == "branch" || eName == "floatimage") && + state == StateMap) { + // This is used in vymparts, which have no mapcenter or for undo + isVymPart = true; + TreeItem *ti = model->getSelectedItem(); + if (!ti) { + // If a vym part is _loaded_ (not imported), + // selection==lmo==NULL + // Treat it like ImportAdd then... + loadMode = ImportAdd; + // we really have no MCO at this time + lastBranch = model->createMapCenter(); + model->select(lastBranch); + model->setHeadingPlainText("Import"); + ti = lastBranch; + } + if (ti && ti->isBranchLikeType()) { + lastBranch = (BranchItem *)ti; + if (eName == "branch") { + state = StateBranch; + if (loadMode == ImportAdd) { + lastBranch = model->createBranch(lastBranch); + model->setLatestAddedItem(lastBranch); + if (insertPos >= 0) + model->relinkBranch(lastBranch, (BranchItem *)ti, + insertPos); + } + else + model->clearItem(lastBranch); + readBranchAttr(atts); + } + else if (eName == "floatimage") { + state = StateImage; + lastImage = model->createImage(lastBranch); + model->setLatestAddedItem(lastImage); + if (!readImageAttr(atts)) + return false; + } + else + return false; + } + else + return false; + } + else if (eName == "branch" && state == StateMapCenter) { + state = StateBranch; + lastBranch = model->createBranch(lastBranch); + readBranchAttr(atts); + } + else if (eName == "htmlnote" && + state == StateBranch) { // only for backward compatibility. Use + // vymnote now + state = StateHtmlNote; + vymtext.clear(); + if (!atts.value("fonthint").isEmpty()) + vymtext.setFontHint(atts.value("fonthint")); + } + else if (eName == "frame" && + (state == StateBranch || state == StateMapCenter)) { + state = StateFrame; + if (!readFrameAttr(atts)) + return false; + } + else if (eName == "xlink" && state == StateBranch) { + // Obsolete after 1.13.2 + state = StateBranchXLink; + if (!readXLinkAttr(atts)) + return false; + } + else if (eName == "xlink" && state == StateMap) { + state = StateLink; + if (!readLinkNewAttr(atts)) + return false; + } + else if (eName == "branch" && state == StateBranch) { + lastBranch = model->createBranch(lastBranch); + readBranchAttr(atts); + } + else if (eName == "html" && + (state == StateHtmlNote || + state == StateNote || + state == StateVymNote)) { // Only for backward compatibility + state = StateHtml; + htmldata = "<" + eName; + readHtmlAttr(atts); + htmldata += ">"; + } + else if (eName == "attribute" && + (state == StateBranch || state == StateMapCenter)) { + state = StateAttribute; + AttributeItem *ai = new AttributeItem(lastBranch); + if (ai) { + if (!atts.value("key").isEmpty()) + ai->setKey(atts.value("key")); + + QString type = atts.value("type"); + QString val = atts.value("value"); + if (!type.isEmpty()) { + if (type == "Integer") + ai->setValue(val.toInt()); + else if (type == "String") + ai->setValue(val); + else if (type == "Undefined") { + ai->setValue(val); + ai->setAttributeType(AttributeItem::Undefined); + qWarning() << "Found attribute type 'Undefined'"; + } else if (type == "DateTime") { + ai->setValue(QDateTime::fromString(val, Qt::ISODate)); + } else + qWarning() << "Found unknown attribute type: " << type; + } else { + if (!atts.value("value").isEmpty()) + ai->setValue(atts.value("value")); + } + } + model->setAttribute(lastBranch, ai); + } + else if (state == StateHtml) { + // Only for backward compatibility + // accept all while in html mode, + htmldata += "<" + eName; + readHtmlAttr(atts); + htmldata += ">"; + } + else + return false; // Error + return true; +} + +bool parseVYMHandler::endElement(const QString &, const QString &, + const QString &eName) +{ + /* Testing + QString h; + lastBranch ? h = lastBranch->getHeadingPlain() : h = ""; + qDebug() << "endElement state=" << state << " lastBranch=" << h; + */ + + switch (state) { + case StateMap: + case StateMapDesign: + case StateMD: + break; + case StateMapCenter: + model->emitDataChanged(lastBranch); + lastBranch = (BranchItem *)(lastBranch->parent()); + break; + case StateBranch: + // Empty branches may not be scrolled + // (happens if bookmarks are imported) + if (lastBranch->isScrolled() && lastBranch->branchCount() == 0) + lastBranch->unScroll(); + + model->emitDataChanged(lastBranch); + lastBranch = (BranchItem *)(lastBranch->parent()); + lastBranch->setLastSelectedBranch(0); + break; + case StateTask: + break; + case StateHeading: + if (versionLowerOrEqual(version, "2.4.99") && + htmldata.contains("")) + // versions before 2.5.0 didn't use CDATA to save richtext + vymtext.setAutoText(htmldata); + else { + // Versions 2.5.0 to 2.7.562 had HTML data encoded as CDATA + // Later versions use the attribute, + // which is set already in begin element + // If both htmldata and vymtext are already available, use the + // vymtext + if (vymtext.isEmpty()) + vymtext.setText(htmldata); + } + lastBranch->setHeading(vymtext); + break; + case StateHtmlNote: // Richtext note, needed anyway for backward + // compatibility + if (htmldata.contains("setNote(vymtext); + break; + case StateMapSlide: + lastSlide = NULL; + break; + case StateNote: + // version < 1.4.6 + if (!htmldata.isEmpty()) { + if (htmldata.contains("setNote(vymtext); + break; + case StateMapSetting: + // version >= 2.5.0 previously value only as attribut + settings.setLocalValue(model->getDestPath(), lastSetting, htmldata); + break; + case StateVymNote: // Might be richtext or plaintext with + // version >= 1.13.8 + if (versionLowerOrEqual(version, "2.4.99") && + htmldata.contains("")) + // versions before 2.5.0 didn't use CDATA to save richtext + vymtext.setAutoText(htmldata); + else { + // Versions 2.5.0 to 2.7.562 had HTML data encoded as CDATA + // Later versions use the attribute, + // which is set already in begin element + // If both htmldata and vymtext are already available, use the + // vymtext + if (vymtext.isEmpty()) + vymtext.setText(htmldata); + } + lastBranch->setNote(vymtext); + break; + case StateHtml: + htmldata += ""; + if (eName == "html") + htmldata.replace("

", "
"); + break; + default: + break; + } + state = stateStack.takeLast(); + return true; +} + +bool parseVYMHandler::characters(const QString &ch) +{ + // qDebug()<< "xml-vym: characters " << ch << " state=" << state; + + QString ch_org = quoteMeta(ch); + QString ch_simplified = ch.simplified(); + + switch (state) { + case StateInit: + case StateMap: + case StateMapDesign: + case StateMD: + break; + case StateMapSelect: + model->select(ch_simplified); + break; + case StateMapSetting: + htmldata += ch; + break; + case StateMapCenter: + break; + case StateNote: // only in vym <1.4.6 + htmldata += ch_simplified; + break; + case StateBranch: + break; + case StateStandardFlag: + lastBranch->activateStandardFlagByName(ch_simplified); + break; + case StateImage: + break; + case StateVymNote: + htmldata += ch; + break; + case StateHtmlNote: // Only for compatibility + htmldata += ch; + break; + case StateHtml: + htmldata += ch_simplified; + break; + case StateHeading: + htmldata += ch; + break; + default: + return false; + } + return true; +} + +QString parseVYMHandler::errorString() +{ + return "the document is not in the VYM file format"; +} + +bool parseVYMHandler::readMapAttr( const QXmlAttributes &a) +{ + if (!a.value("author").isEmpty()) + model->setAuthor(a.value("author")); + if (!a.value("title").isEmpty()) + model->setTitle(a.value("title")); + if (!a.value("comment").isEmpty()) + model->setComment(unquoteMeta(a.value("comment"))); + if (!a.value("branchCount").isEmpty()) { + branchesTotal = a.value("branchCount").toInt(); + if (branchesTotal > 10) { + useProgress = true; + mainWindow->setProgressMaximum(branchesTotal); + } + } + + if (!a.value("mapZoomFactor").isEmpty()) + model->setMapZoomFactor(a.value("mapZoomFactor").toDouble()); + if (!a.value("mapRotationAngle").isEmpty()) + model->setMapRotationAngle(a.value("mapRotationAngle").toDouble()); + + return readMapDesignCompatibleAttr(a); +} + +bool parseVYMHandler::readMapDesignCompatibleAttr( const QXmlAttributes &a) +{ + // Some attributes moved in version 2.9.514 from + // to and + // This code here will allow to parse also newer maps. + // Some elements though are not available in older versions, especially + // + // + + QColor col; + if (!a.value("backgroundColor").isEmpty()) { + col.setNamedColor(a.value("backgroundColor")); + model->setMapBackgroundColor(col); + } + if (!a.value("defaultFont").isEmpty()) { + QFont font; + font.fromString(a.value("defaultFont")); + model->setMapDefaultFont(font); + } + if (!a.value("selectionColor").isEmpty()) { + // Only for compatibility + col.setNamedColor(a.value("selectionColor")); + model->setSelectionBrushColor(col); + model->setSelectionPenColor(col); + model->setSelectionPenWidth(1); + } + if (!a.value("selectionPenColor").isEmpty()) { + // Introduced in 2.9.12 + col.setNamedColor(a.value("selectionPenColor")); + model->setSelectionPenColor(col); + } + if (!a.value("selectionPenWidth").isEmpty()) { + // Introduced in 2.9.12 + bool ok; + qreal w = a.value("selectionPenWidth").toFloat(&ok); + if (ok) + model->setSelectionPenWidth(w); + } + if (!a.value("selectionBrushColor").isEmpty()) { + // Introduced in 2.9.12 + col.setNamedColor(a.value("selectionBrushColor")); + model->setSelectionBrushColor(col); + } + if (!a.value("linkColorHint").isEmpty()) { + if (a.value("linkColorHint") == "HeadingColor") + model->setMapLinkColorHint(LinkableMapObj::HeadingColor); + else + model->setMapLinkColorHint(LinkableMapObj::DefaultColor); + } + if (!a.value("linkStyle").isEmpty()) + model->setMapLinkStyle(a.value("linkStyle")); + if (!a.value("linkColor").isEmpty()) { + col.setNamedColor(a.value("linkColor")); + model->setMapDefLinkColor(col); + } + + QPen pen(model->getMapDefXLinkPen()); + if (!a.value("defXLinkColor").isEmpty()) { + col.setNamedColor(a.value("defXLinkColor")); + pen.setColor(col); + } + if (!a.value("defXLinkWidth").isEmpty()) + pen.setWidth(a.value("defXLinkWidth").toInt()); + if (!a.value("defXLinkPenStyle").isEmpty()) { + bool ok; + Qt::PenStyle ps = penStyle(a.value("defXLinkPenStyle"), ok); + if (!ok) + return false; + pen.setStyle(ps); + } + model->setMapDefXLinkPen(pen); + + if (!a.value("defXLinkStyleBegin").isEmpty()) + model->setMapDefXLinkStyleBegin(a.value("defXLinkStyleBegin")); + if (!a.value("defXLinkStyleEnd").isEmpty()) + model->setMapDefXLinkStyleEnd(a.value("defXLinkStyleEnd")); + return true; +} + +bool parseVYMHandler::readBranchAttr(const QXmlAttributes &a) +{ + branchesCounter++; + if (useProgress) + mainWindow->addProgressValue((float)branchesCounter / branchesTotal); + + lastMI = lastBranch; + + if (!readOOAttr(a)) + return false; + + if (!a.value("scrolled").isEmpty()) + lastBranch->toggleScroll(); + + if (!a.value("incImgV").isEmpty()) { + if (a.value("incImgV") == "true") + lastBranch->setIncludeImagesVer(true); + else + lastBranch->setIncludeImagesVer(false); + } + if (!a.value("incImgH").isEmpty()) { + if (a.value("incImgH") == "true") + lastBranch->setIncludeImagesHor(true); + else + lastBranch->setIncludeImagesHor(false); + } + if (a.value("childrenFreePos") == "true") + lastBranch->setChildrenLayout(BranchItem::FreePositioning); + + return true; +} + +bool parseVYMHandler::readFrameAttr(const QXmlAttributes &a) +{ + if (lastMI) { + OrnamentedObj *oo = (OrnamentedObj *)(lastMI->getLMO()); + if (oo) { + bool ok; + int x; + { + if (!a.value("frameType").isEmpty()) + oo->setFrameType(a.value("frameType")); + if (!a.value("penColor").isEmpty()) + oo->setFramePenColor(a.value("penColor")); + if (!a.value("brushColor").isEmpty()) { + oo->setFrameBrushColor(a.value("brushColor")); + lastMI->setBackgroundColor(a.value("brushColor")); + } + if (!a.value("padding").isEmpty()) { + x = a.value("padding").toInt(&ok); + if (ok) + oo->setFramePadding(x); + } + if (!a.value("borderWidth").isEmpty()) { + x = a.value("borderWidth").toInt(&ok); + if (ok) + oo->setFrameBorderWidth(x); + } + if (!a.value("includeChildren").isEmpty()) { + if (a.value("includeChildren") == "true") + oo->setFrameIncludeChildren(true); + else + oo->setFrameIncludeChildren(false); + } + } + return true; + } + } + return false; +} + +bool parseVYMHandler::readOOAttr(const QXmlAttributes &a) +{ + if (lastMI) { + bool okx, oky; + float x, y; + if (!a.value("posX").isEmpty()) { // Introduced in 2.9.501, added here for file compatibility + if (!a.value("posY").isEmpty()) { + x = a.value("posX").toFloat(&okx); + y = a.value("posY").toFloat(&oky); + if (okx && oky) + lastMI->setRelPos(QPointF(x, y)); + else + return false; // Couldn't read relPos + } + } + if (!a.value("relPosX").isEmpty()) { + if (!a.value("relPosY").isEmpty()) { + x = a.value("relPosX").toFloat(&okx); + y = a.value("relPosY").toFloat(&oky); + if (okx && oky) + lastMI->setRelPos(QPointF(x, y)); + else + return false; // Couldn't read relPos + } + } + if (!a.value("absPosX").isEmpty()) { + if (!a.value("absPosY").isEmpty()) { + x = a.value("absPosX").toFloat(&okx); + y = a.value("absPosY").toFloat(&oky); + if (okx && oky) + lastMI->setAbsPos(QPointF(x, y)); + else + return false; // Couldn't read absPos + } + } + if (!a.value("url").isEmpty()) + lastMI->setURL(a.value("url")); + if (!a.value("vymLink").isEmpty()) + lastMI->setVymLink(a.value("vymLink")); + if (!a.value("hideInExport").isEmpty()) + if (a.value("hideInExport") == "true") + lastMI->setHideInExport(true); + + if (!a.value("hideLink").isEmpty()) { + if (a.value("hideLink") == "true") + lastMI->setHideLinkUnselected(true); + else + lastMI->setHideLinkUnselected(false); + } + + if (!a.value("localTarget").isEmpty()) + if (a.value("localTarget") == "true") + lastMI->toggleTarget(); + if (!a.value("rotation").isEmpty()) { + x = a.value("rotation").toFloat(&okx); + if (okx) + lastMI->setRotation(x); + else + return false; // Couldn't read rotation + } + + if (!a.value("uuid").isEmpty()) { + // While pasting, check for existing UUID + if (loadMode != ImportAdd && !model->findUuid(a.value("uuid"))) + lastMI->setUuid(a.value("uuid")); + } + } + return true; +} + +bool parseVYMHandler::readNoteAttr(const QXmlAttributes &a) +{ // only for backward compatibility (<1.4.6). Use htmlnote now. + vymtext.clear(); + QString fn; + if (!a.value("href").isEmpty()) { + // Load note + fn = parseHREF(a.value("href")); + QFile file(fn); + QString s; // Reading a note + + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "parseVYMHandler::readNoteAttr: Couldn't load " + fn; + return false; + } + QTextStream stream(&file); + stream.setCodec("UTF-8"); + QString lines; + while (!stream.atEnd()) { + lines += stream.readLine() + "\n"; + } + file.close(); + + if (lines.contains("load(parseHREF(a.value("href")))) { + QMessageBox::warning(0, "Warning: ", + "Couldn't load image\n" + + parseHREF(a.value("href"))); + lastImage = NULL; + return true; + } + } + if (!a.value("zPlane").isEmpty()) + lastImage->setZValue(a.value("zPlane").toInt()); + float x, y; + bool okx, oky; + if (!a.value("posX").isEmpty()) { // Introduced in 2.9.501, added here for file compatibility + if (!a.value("posY").isEmpty()) { + x = a.value("posX").toFloat(&okx); + y = a.value("posY").toFloat(&oky); + if (okx && oky) + lastImage->setRelPos(QPointF(x, y)); + else + return false; // Couldn't read relPos + } + } + if (!a.value("relPosX").isEmpty()) { + if (!a.value("relPosY").isEmpty()) { + // read relPos + x = a.value("relPosX").toFloat(&okx); + y = a.value("relPosY").toFloat(&oky); + if (okx && oky) + lastImage->setRelPos(QPointF(x, y)); + else + // Couldn't read relPos + return false; + } + } + + // Scale image + // scaleX and scaleY are no longer used since 2.7.509 and replaced by + // scaleFactor + x = y = 1; + if (!a.value("scaleX").isEmpty()) { + x = a.value("scaleX").toFloat(&okx); + if (!okx) + return false; + } + + if (!a.value("scaleY").isEmpty()) { + x = a.value("scaleY").toFloat(&oky); + if (!oky) + return false; + } + + if (!a.value("scaleFactor").isEmpty()) { + x = a.value("scaleFactor").toFloat(&okx); + if (!okx) + return false; + } + + if (x != 1) + lastImage->setScaleFactor(x); + + if (!readOOAttr(a)) + return false; + + if (!a.value("originalName").isEmpty()) + { + lastImage->setOriginalFilename(a.value("originalName")); + } + return true; +} + +bool parseVYMHandler::readXLinkAttr(const QXmlAttributes &a) +{ + // Obsolete, see also readLinkAttr + + if (!a.value("beginID").isEmpty()) { + if (!a.value("endID").isEmpty()) { + TreeItem *beginBI = model->findBySelectString(a.value("beginID")); + TreeItem *endBI = model->findBySelectString(a.value("endID")); + if (beginBI && endBI && beginBI->isBranchLikeType() && + endBI->isBranchLikeType()) { + Link *li = new Link(model); + li->setBeginBranch((BranchItem *)beginBI); + li->setEndBranch((BranchItem *)endBI); + QPen pen = li->getPen(); + + if (!a.value("color").isEmpty()) { + QColor col; + col.setNamedColor(a.value("color")); + pen.setColor(col); + } + + if (!a.value("width").isEmpty()) { + bool okx; + pen.setWidth(a.value("width").toInt(&okx, 10)); + } + li->setPen(pen); + model->createLink(li); + } + } + } + return true; +} + +bool parseVYMHandler::readLinkNewAttr(const QXmlAttributes &a) +{ + // object ID is used starting in version 1.8.76 + // (before there was beginBranch and endBranch) + // + // Starting in 1.13.2 xlinks are no longer subitems of branches, + // but listed at the end of the data in a map. This makes handling + // of links much safer and easier + + if (!a.value("beginID").isEmpty()) { + if (!a.value("endID").isEmpty()) { + TreeItem *beginBI = model->findBySelectString(a.value("beginID")); + TreeItem *endBI = model->findBySelectString(a.value("endID")); + if (beginBI && endBI && beginBI->isBranchLikeType() && + endBI->isBranchLikeType()) { + Link *li = new Link(model); + li->setBeginBranch((BranchItem *)beginBI); + li->setEndBranch((BranchItem *)endBI); + + model->createLink(li); + + bool okx; + QPen pen = li->getPen(); + if (!a.value("type").isEmpty()) { + li->setLinkType(a.value("type")); + } + if (!a.value("color").isEmpty()) { + QColor col; + col.setNamedColor(a.value("color")); + pen.setColor(col); + } + if (!a.value("width").isEmpty()) { + pen.setWidth(a.value("width").toInt(&okx, 10)); + } + if (!a.value("penstyle").isEmpty()) { + pen.setStyle(penStyle(a.value("penstyle"), okx)); + } + li->setPen(pen); + + if (!a.value("styleBegin").isEmpty()) + li->setStyleBegin(a.value("styleBegin")); + if (!a.value("styleEnd").isEmpty()) + li->setStyleEnd(a.value("styleEnd")); + + XLinkObj *xlo = (XLinkObj *)(li->getMO()); + if (xlo && !a.value("c0").isEmpty()) { + QPointF p = point(a.value("c0"), okx); + if (okx) + xlo->setC0(p); + } + if (xlo && !a.value("c1").isEmpty()) { + QPointF p = point(a.value("c1"), okx); + if (okx) + xlo->setC1(p); + } + } + } + } + return true; +} + +bool parseVYMHandler::readSettingAttr(const QXmlAttributes &a) +{ + if (!a.value("key").isEmpty()) { + lastSetting = a.value("key"); + if (!a.value("value").isEmpty()) + settings.setLocalValue( + model->getDestPath(), a.value("key"), + a.value("value")); + else + return false; + } + else + return false; + + return true; +} + +bool parseVYMHandler::readSlideAttr(const QXmlAttributes &a) +{ + QStringList scriptlines; // FIXME-3 needed for switching to inScript + // Most attributes are obsolete with inScript + if (!lastSlide) + return false; + { + if (!a.value("name").isEmpty()) + lastSlide->setName(a.value("name")); + if (!a.value("zoom").isEmpty()) { + bool ok; + qreal z = a.value("zoom").toDouble(&ok); + if (!ok) + return false; + scriptlines.append(QString("setMapZoom(%1)").arg(z)); + } + if (!a.value("rotation").isEmpty()) { + bool ok; + qreal z = a.value("rotation").toDouble(&ok); + if (!ok) + return false; + scriptlines.append(QString("setMapRotation(%1)").arg(z)); + } + if (!a.value("duration").isEmpty()) { + bool ok; + int d = a.value("duration").toInt(&ok); + if (!ok) + return false; + scriptlines.append(QString("setMapAnimDuration(%1)").arg(d)); + } + if (!a.value("curve").isEmpty()) { + bool ok; + int i = a.value("curve").toInt(&ok); + if (!ok) + return false; + if (i < 0 || i > QEasingCurve::OutInBounce) + return false; + scriptlines.append(QString("setMapAnimCurve(%1)").arg(i)); + } + if (!a.value("mapitem").isEmpty()) { + TreeItem *ti = model->findBySelectString(a.value("mapitem")); + if (!ti) + return false; + scriptlines.append( + QString("centerOnID(\"%1\")").arg(ti->getUuid().toString())); + } + if (!a.value("inScript").isEmpty()) { + lastSlide->setInScript(unquoteMeta(a.value("inScript"))); + } + else + lastSlide->setInScript(unquoteMeta(scriptlines.join(";\n"))); + + if (!a.value("outScript").isEmpty()) { + lastSlide->setOutScript(unquoteMeta(a.value("outScript"))); + } + } + return true; +} + +bool parseVYMHandler::readTaskAttr(const QXmlAttributes &a) +{ + if (!lastTask) + return false; + { + if (!a.value("status").isEmpty()) + lastTask->setStatus(a.value("status")); + if (!a.value("awake").isEmpty()) + lastTask->setAwake(a.value("awake")); + if (!a.value("date_creation").isEmpty()) + lastTask->setDateCreation(a.value("date_creation")); + if (!a.value("date_modification").isEmpty()) + lastTask->setDateModification(a.value("date_modification")); + if (!a.value("date_sleep").isEmpty()) { + if (!lastTask->setDateSleep(a.value("date_sleep"))) + return false; + } + if (!a.value("prio_delta").isEmpty()) { + lastTask->setPriorityDelta(a.value("prio_delta").toInt()); + } + } + return true; +} + +bool parseVYMHandler::readUserFlagDefAttr(const QXmlAttributes &a) +{ + QString name; + QString path; + QString tooltip; + QUuid uid; + + if (!a.value("name").isEmpty()) + name = a.value("name"); + if (!a.value("tooltip").isEmpty()) + tooltip = a.value("tooltip"); + if (!a.value("uuid").isEmpty()) + uid = QUuid(a.value("uuid")); + + Flag *flag; + + if (!a.value("href").isEmpty()) { + // Setup flag with image + flag = mainWindow->setupFlag(parseHREF(a.value("href")), Flag::UserFlag, + name, tooltip, uid); + } + else { + qWarning() << "readUserFlagDefAttr: Couldn't read href of flag " + << a.value("name"); + return false; + } + + if (!a.value("group").isEmpty()) + flag->setGroup(a.value("group")); + + return true; +} + +bool parseVYMHandler::readUserFlagAttr(const QXmlAttributes &a) +{ + QString name; + QString uuid; + + if (!a.value("name").isEmpty()) + name = a.value("name"); + if (!a.value("uuid").isEmpty()) + uuid = a.value("uuid"); + + lastBranch->toggleFlagByUid(QUuid(uuid)); + + return true; +}