/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "UBSvgSubsetAdaptor.h" #include #include #include "domain/UBGraphicsSvgItem.h" #include "domain/UBGraphicsPixmapItem.h" #include "domain/UBGraphicsProxyWidget.h" #include "domain/UBGraphicsPolygonItem.h" #include "domain/UBGraphicsVideoItem.h" #include "domain/UBGraphicsAudioItem.h" #include "domain/UBGraphicsWidgetItem.h" #include "domain/UBGraphicsPDFItem.h" #include "domain/UBGraphicsTextItem.h" #include "domain/UBAbstractWidget.h" #include "domain/UBGraphicsStroke.h" #include "domain/UBGraphicsStrokesGroup.h" #include "domain/UBItem.h" #include "tools/UBGraphicsRuler.h" #include "tools/UBGraphicsCompass.h" #include "tools/UBGraphicsProtractor.h" #include "tools/UBGraphicsCurtainItem.h" #include "tools/UBGraphicsTriangle.h" #include "tools/UBGraphicsCache.h" #include "document/UBDocumentProxy.h" #include "board/UBBoardView.h" #include "board/UBBoardController.h" #include "board/UBDrawingController.h" #include "frameworks/UBFileSystemUtils.h" #include "frameworks/UBStringUtils.h" #include "core/UBSettings.h" #include "core/UBSetting.h" #include "core/UBPersistenceManager.h" #include "core/UBApplication.h" #include "interfaces/IDataStorage.h" #include "pdf/PDFRenderer.h" #include "core/memcheck.h" //#include "qtlogger.h" const QString UBSvgSubsetAdaptor::nsSvg = "http://www.w3.org/2000/svg"; const QString UBSvgSubsetAdaptor::nsXHtml = "http://www.w3.org/1999/xhtml"; const QString UBSvgSubsetAdaptor::nsXLink = "http://www.w3.org/1999/xlink"; const QString UBSvgSubsetAdaptor::xmlTrue = "true"; const QString UBSvgSubsetAdaptor::xmlFalse = "false"; const QString UBSvgSubsetAdaptor::sFontSizePrefix = "font-size:"; const QString UBSvgSubsetAdaptor::sPixelUnit = "px"; const QString UBSvgSubsetAdaptor::sFontWeightPrefix = "font-weight:"; const QString UBSvgSubsetAdaptor::sFontStylePrefix = "font-style:"; const QString UBSvgSubsetAdaptor::sFormerUniboardDocumentNamespaceUri = "http://www.mnemis.com/uniboard"; QMap UBSvgSubsetAdaptor::additionalElementToStore; // Why using such a string? // Media file path are relative to the current document. So if we are reading the // first page of a document the document path has not been updated. // Concatenate relative media path with the old document path leads to mess // This string is so used only for activeDocumentChanged signal QString UBSvgSubsetAdaptor::sTeacherGuideNode = ""; QString UBSvgSubsetAdaptor::toSvgTransform(const QMatrix& matrix) { return QString("matrix(%1, %2, %3, %4, %5, %6)") .arg(matrix.m11(), 0 , 'g') .arg(matrix.m12(), 0 , 'g') .arg(matrix.m21(), 0 , 'g') .arg(matrix.m22(), 0 , 'g') .arg(matrix.dx(), 0 , 'g') .arg(matrix.dy(), 0 , 'g'); } QMatrix UBSvgSubsetAdaptor::fromSvgTransform(const QString& transform) { QMatrix matrix; QString ts = transform; ts.replace("matrix(", ""); ts.replace(")", ""); QStringList sl = ts.split(","); if (sl.size() >= 6) { matrix.setMatrix( sl.at(0).toFloat(), sl.at(1).toFloat(), sl.at(2).toFloat(), sl.at(3).toFloat(), sl.at(4).toFloat(), sl.at(5).toFloat()); } return matrix; } static bool itemZIndexComp(const QGraphicsItem* item1, const QGraphicsItem* item2) { return item1->data(UBGraphicsItemData::ItemOwnZValue).toReal() < item2->data(UBGraphicsItemData::ItemOwnZValue).toReal(); } void UBSvgSubsetAdaptor::upgradeScene(UBDocumentProxy* proxy, const int pageIndex) { //4.2 QDomDocument doc = loadSceneDocument(proxy, pageIndex); QDomElement elSvg = doc.documentElement(); // SVG tag QString ubVersion = elSvg.attributeNS(UBSettings::uniboardDocumentNamespaceUri, "version", "4.1"); // default to 4.1 if (ubVersion.startsWith("4.1") || ubVersion.startsWith("4.2") || ubVersion.startsWith("4.3")) { // migrate to 4.2.1 (or latter) UBGraphicsScene *scene = loadScene(proxy, pageIndex); scene->setModified(true); persistScene(proxy, scene, pageIndex); } } QDomDocument UBSvgSubsetAdaptor::loadSceneDocument(UBDocumentProxy* proxy, const int pPageIndex) { QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", UBApplication::boardController->pageFromSceneIndex(pPageIndex)); QFile file(fileName); QDomDocument doc("page"); if (file.exists()) { if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Cannot open file " << fileName << " for reading ..."; return doc; } doc.setContent(&file, true); file.close(); } return doc; } void UBSvgSubsetAdaptor::setSceneUuid(UBDocumentProxy* proxy, const int pageIndex, QUuid pUuid) { QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", UBApplication::boardController->pageFromSceneIndex(pageIndex)); QFile file(fileName); if (!file.exists() || !file.open(QIODevice::ReadOnly)) return; QTextStream textReadStream(&file); QString xmlContent = textReadStream.readAll(); int uuidIndex = xmlContent.indexOf("uuid"); if (-1 == uuidIndex) { qWarning() << "Cannot read UUID from file" << fileName << "to set new UUID"; file.close(); return; } int quoteStartIndex = xmlContent.indexOf('"', uuidIndex); if (-1 == quoteStartIndex) { qWarning() << "Cannot read UUID from file" << fileName << "to set new UUID"; file.close(); return; } int quoteEndIndex = xmlContent.indexOf('"', quoteStartIndex + 1); if (-1 == quoteEndIndex) { qWarning() << "Cannot read UUID from file" << fileName << "to set new UUID"; file.close(); return; } file.close(); QString newXmlContent = xmlContent.left(quoteStartIndex + 1); newXmlContent.append(UBStringUtils::toCanonicalUuid(pUuid)); newXmlContent.append(xmlContent.right(xmlContent.length() - quoteEndIndex)); if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream textWriteStream(&file); textWriteStream << newXmlContent; file.close(); } else { qWarning() << "Cannot open file" << fileName << "to write UUID"; } } bool UBSvgSubsetAdaptor::addElementToBeStored(QString domName, IDataStorage *dataStorageClass) { if(domName.isEmpty() || additionalElementToStore.contains(domName)){ qWarning() << "Error adding the element that should persist"; return false; } additionalElementToStore.insert(domName,dataStorageClass); return true; } QString UBSvgSubsetAdaptor::uniboardDocumentNamespaceUriFromVersion(int mFileVersion) { return mFileVersion >= 40200 ? UBSettings::uniboardDocumentNamespaceUri : sFormerUniboardDocumentNamespaceUri; } UBGraphicsScene* UBSvgSubsetAdaptor::loadScene(UBDocumentProxy* proxy, const int pageIndex) { QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", UBApplication::boardController->pageFromSceneIndex(pageIndex)); QFile file(fileName); if (file.exists()) { if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Cannot open file " << fileName << " for reading ..."; return 0; } UBGraphicsScene* scene = loadScene(proxy, file.readAll()); file.close(); return scene; } return 0; } QUuid UBSvgSubsetAdaptor::sceneUuid(UBDocumentProxy* proxy, const int pageIndex) { QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", UBApplication::boardController->pageFromSceneIndex(pageIndex)); QFile file(fileName); QUuid uuid; if (file.exists()) { if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Cannot open file " << fileName << " for reading ..."; return 0; } QXmlStreamReader xml(file.readAll()); bool foundSvg = false; while (!xml.atEnd() && !foundSvg) { xml.readNext(); if (xml.isStartElement()) { if (xml.name() == "svg") { QStringRef svgSceneUuid = xml.attributes().value(UBSettings::uniboardDocumentNamespaceUri, "uuid"); if (svgSceneUuid.isNull()) svgSceneUuid = xml.attributes().value("http://www.mnemis.com/uniboard", "uuid"); if (!svgSceneUuid.isNull()) uuid = QUuid(svgSceneUuid.toString()); foundSvg = true; } } } file.close(); } return uuid; } UBGraphicsScene* UBSvgSubsetAdaptor::loadScene(UBDocumentProxy* proxy, const QByteArray& pArray) { UBSvgSubsetReader reader(proxy, pArray); return reader.loadScene(); } UBSvgSubsetAdaptor::UBSvgSubsetReader::UBSvgSubsetReader(UBDocumentProxy* pProxy, const QByteArray& pXmlData) : mXmlReader(pXmlData) , mProxy(pProxy) , mDocumentPath(pProxy->persistencePath()) , mGroupHasInfo(false) { // NOOP } UBGraphicsScene* UBSvgSubsetAdaptor::UBSvgSubsetReader::loadScene() { UBGraphicsScene *scene = 0; UBGraphicsWidgetItem *currentWidget = 0; mFileVersion = 40100; // default to 4.1.0 UBGraphicsStroke* annotationGroup = 0; UBGraphicsStrokesGroup* strokesGroup = 0; UBDrawingController* dc = UBDrawingController::drawingController(); sTeacherGuideNode = ""; while (!mXmlReader.atEnd()) { mXmlReader.readNext(); if (mXmlReader.isStartElement()) { qreal zFromSvg = getZValueFromSvg(); if (mXmlReader.name() == "svg") { if (!scene) { scene = new UBGraphicsScene(mProxy); } // introduced in UB 4.2 QStringRef svgUbVersion = mXmlReader.attributes().value(UBSettings::uniboardDocumentNamespaceUri, "version"); if (!svgUbVersion.isNull()) { QString ubVersion = svgUbVersion.toString(); //may look like : 4 or 4.1 or 4.2 or 4.2.1, etc QStringList parts = ubVersion.split("."); if (parts.length() > 0) { mFileVersion = parts.at(0).toInt() * 10000; } if (parts.length() > 1) { mFileVersion += parts.at(1).toInt() * 100; } if (parts.length() > 2) { mFileVersion += parts.at(2).toInt(); } } mNamespaceUri = uniboardDocumentNamespaceUriFromVersion(mFileVersion); QStringRef svgSceneUuid = mXmlReader.attributes().value(mNamespaceUri, "uuid"); if (!svgSceneUuid.isNull()) { scene->setUuid(QUuid(svgSceneUuid.toString())); } // introduced in UB 4.0 QStringRef svgViewBox = mXmlReader.attributes().value(nsSvg, "viewBox"); if (!svgViewBox.isNull()) { QStringList ts = svgViewBox.toString().split(QLatin1Char(' '), QString::SkipEmptyParts); QRectF sceneRect; if (ts.size() >= 4) { sceneRect.setX(ts.at(0).toFloat()); sceneRect.setY(ts.at(1).toFloat()); sceneRect.setWidth(ts.at(2).toFloat()); sceneRect.setHeight(ts.at(3).toFloat()); scene->setSceneRect(sceneRect); } else { qWarning() << "cannot make sense of 'viewBox' value " << svgViewBox.toString(); } } bool darkBackground = false; bool crossedBackground = false; QStringRef ubDarkBackground = mXmlReader.attributes().value(mNamespaceUri, "dark-background"); if (!ubDarkBackground.isNull()) darkBackground = (ubDarkBackground.toString() == xmlTrue); QStringRef ubCrossedBackground = mXmlReader.attributes().value(mNamespaceUri, "crossed-background"); if (!ubDarkBackground.isNull()) crossedBackground = (ubCrossedBackground.toString() == xmlTrue); scene->setBackground(darkBackground, crossedBackground); QStringRef pageNominalSize = mXmlReader.attributes().value(mNamespaceUri, "nominal-size"); if (!pageNominalSize.isNull()) { QStringList ts = pageNominalSize.toString().split(QLatin1Char('x'), QString::SkipEmptyParts); QSize sceneSize; if (ts.size() >= 2) { sceneSize.setWidth(ts.at(0).toInt()); sceneSize.setHeight(ts.at(1).toInt()); scene->setNominalSize(sceneSize); } else { qWarning() << "cannot make sense of 'nominal-size' value " << pageNominalSize.toString(); } } } else if (mXmlReader.name() == "g") { // Create new stroke, if its NULL or already has polygons if (annotationGroup) { if (!annotationGroup->polygons().empty()) annotationGroup = new UBGraphicsStroke(); } else annotationGroup = new UBGraphicsStroke(); if(eDrawingMode_Vector == dc->drawingMode()){ strokesGroup = new UBGraphicsStrokesGroup(); graphicsItemFromSvg(strokesGroup); } QStringRef ubZValue = mXmlReader.attributes().value(mNamespaceUri, "z-value"); if (!ubZValue.isNull()) { mGroupZIndex = ubZValue.toString().toFloat(); mGroupHasInfo = true; } QStringRef ubFillOnDarkBackground = mXmlReader.attributes().value(mNamespaceUri, "fill-on-dark-background"); if (!ubFillOnDarkBackground.isNull()) { mGroupDarkBackgroundColor.setNamedColor(ubFillOnDarkBackground.toString()); } QStringRef ubFillOnLightBackground = mXmlReader.attributes().value(mNamespaceUri, "fill-on-light-background"); if (!ubFillOnLightBackground.isNull()) { mGroupLightBackgroundColor.setNamedColor(ubFillOnLightBackground.toString()); } } else if (mXmlReader.name() == "polygon" || mXmlReader.name() == "line") { UBGraphicsPolygonItem* polygonItem = 0; if (mXmlReader.name() == "polygon") { polygonItem = polygonItemFromPolygonSvg(scene->isDarkBackground() ? Qt::white : Qt::black); } else if (mXmlReader.name() == "line") { polygonItem = polygonItemFromLineSvg(scene->isDarkBackground() ? Qt::white : Qt::black); } if (polygonItem) { if (annotationGroup) { polygonItem->setStroke(annotationGroup); } if(eDrawingMode_Vector == dc->drawingMode()){ if(strokesGroup){ polygonItem->setTransform(strokesGroup->transform()); strokesGroup->addToGroup(polygonItem); } }else{ scene->addItem(polygonItem); } polygonItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Graphic)); polygonItem->show(); } } else if (mXmlReader.name() == "polyline") { QList polygonItems = polygonItemsFromPolylineSvg(scene->isDarkBackground() ? Qt::white : Qt::black); foreach(UBGraphicsPolygonItem* polygonItem, polygonItems) { if (annotationGroup) { polygonItem->setStroke(annotationGroup); } if(eDrawingMode_Vector == dc->drawingMode()){ if(strokesGroup){ polygonItem->setTransform(strokesGroup->transform()); strokesGroup->addToGroup(polygonItem); } }else{ scene->addItem(polygonItem); } polygonItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Graphic)); polygonItem->show(); } } else if (mXmlReader.name() == "image") { QStringRef imageHref = mXmlReader.attributes().value(nsXLink, "href"); if (!imageHref.isNull()) { QString href = imageHref.toString(); QStringRef ubBackground = mXmlReader.attributes().value(mNamespaceUri, "background"); bool isBackground = (!ubBackground.isNull() && ubBackground.toString() == xmlTrue); if (href.contains("png")) { QGraphicsPixmapItem* pixmapItem = pixmapItemFromSvg(); if (pixmapItem) { pixmapItem->setFlag(QGraphicsItem::ItemIsMovable, true); pixmapItem->setFlag(QGraphicsItem::ItemIsSelectable, true); scene->addItem(pixmapItem); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(pixmapItem, zFromSvg); if (isBackground) scene->setAsBackgroundObject(pixmapItem); pixmapItem->show(); } } else if (href.contains("svg")) { UBGraphicsSvgItem* svgItem = svgItemFromSvg(); if (svgItem) { svgItem->setFlag(QGraphicsItem::ItemIsMovable, true); svgItem->setFlag(QGraphicsItem::ItemIsSelectable, true); scene->addItem(svgItem); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(svgItem, zFromSvg); if (isBackground) scene->setAsBackgroundObject(svgItem); svgItem->show(); } } else { qWarning() << "don't know what to do with href value " << href; } } } else if (mXmlReader.name() == "audio") { UBGraphicsAudioItem* audioItem = audioItemFromSvg(); if (audioItem) { audioItem->setFlag(QGraphicsItem::ItemIsMovable, true); audioItem->setFlag(QGraphicsItem::ItemIsSelectable, true); scene->addItem(audioItem); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(audioItem, zFromSvg); audioItem->show(); //force start to load the video and display the first frame audioItem->mediaObject()->play(); audioItem->mediaObject()->pause(); } } else if (mXmlReader.name() == "video") { UBGraphicsVideoItem* videoItem = videoItemFromSvg(); if (videoItem) { videoItem->setFlag(QGraphicsItem::ItemIsMovable, true); videoItem->setFlag(QGraphicsItem::ItemIsSelectable, true); scene->addItem(videoItem); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(videoItem, zFromSvg); videoItem->show(); //force start to load the video and display the first frame videoItem->mediaObject()->play(); videoItem->mediaObject()->pause(); } } else if (mXmlReader.name() == "text")//This is for backward compatibility with proto text field prior to version 4.3 { UBGraphicsTextItem* textItem = textItemFromSvg(); if (textItem) { textItem->setFlag(QGraphicsItem::ItemIsMovable, true); textItem->setFlag(QGraphicsItem::ItemIsSelectable, true); scene->addItem(textItem); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(textItem, zFromSvg); textItem->show(); } } else if (mXmlReader.name() == "curtain") { UBGraphicsCurtainItem* mask = curtainItemFromSvg(); if (mask) { scene->addItem(mask); scene->registerTool(mask); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(mask, zFromSvg); } } else if (mXmlReader.name() == "ruler") { QString ubZValue = mXmlReader.attributes().value(mNamespaceUri, "z-value").toString(); UBGraphicsRuler *ruler = rulerFromSvg(); ubZValue = mXmlReader.attributes().value(mNamespaceUri, "z-value").toString(); if (ruler) { scene->addItem(ruler); scene->registerTool(ruler); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(ruler, zFromSvg); } } else if (mXmlReader.name() == "compass") { UBGraphicsCompass *compass = compassFromSvg(); if (compass) { scene->addItem(compass); scene->registerTool(compass); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(compass, zFromSvg); } } else if (mXmlReader.name() == "protractor") { UBGraphicsProtractor *protractor = protractorFromSvg(); if (protractor) { scene->addItem(protractor); scene->registerTool(protractor); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(protractor, zFromSvg); } } else if (mXmlReader.name() == "triangle") { UBGraphicsTriangle *triangle = triangleFromSvg(); if (triangle) { scene->addItem(triangle); scene->registerTool(triangle); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(triangle, zFromSvg); } } else if (mXmlReader.name() == "cache") { UBGraphicsCache* cache = cacheFromSvg(); if(cache) { scene->addItem(cache); scene->registerTool(cache); UBApplication::boardController->notifyCache(true); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(cache, zFromSvg); } } else if (mXmlReader.name() == "foreignObject") { QString href = mXmlReader.attributes().value(nsXLink, "href").toString(); QString src = mXmlReader.attributes().value(mNamespaceUri, "src").toString(); QString type = mXmlReader.attributes().value(mNamespaceUri, "type").toString(); bool isBackground = mXmlReader.attributes().value(mNamespaceUri, "background").toString() == xmlTrue; qreal foreignObjectWidth = mXmlReader.attributes().value("width").toString().toFloat(); qreal foreignObjectHeight = mXmlReader.attributes().value("height").toString().toFloat(); if (href.contains(".pdf")) { UBGraphicsPDFItem* pdfItem = pdfItemFromPDF(); if (pdfItem) { pdfItem->setFlag(QGraphicsItem::ItemIsMovable, true); pdfItem->setFlag(QGraphicsItem::ItemIsSelectable, true); scene->addItem(pdfItem); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(pdfItem, zFromSvg); if (isBackground) scene->setAsBackgroundObject(pdfItem); pdfItem->show(); currentWidget = 0; } } else if (src.contains(".wdgt")) { UBGraphicsAppleWidgetItem* appleWidgetItem = graphicsAppleWidgetFromSvg(); if (appleWidgetItem) { appleWidgetItem->setFlag(QGraphicsItem::ItemIsMovable, true); appleWidgetItem->setFlag(QGraphicsItem::ItemIsSelectable, true); appleWidgetItem->resize(foreignObjectWidth, foreignObjectHeight); scene->addItem(appleWidgetItem); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(appleWidgetItem, zFromSvg); appleWidgetItem->show(); currentWidget = appleWidgetItem; } } else if (src.contains(".wgt")) { UBGraphicsW3CWidgetItem* w3cWidgetItem = graphicsW3CWidgetFromSvg(); if (w3cWidgetItem) { w3cWidgetItem->setFlag(QGraphicsItem::ItemIsMovable, true); w3cWidgetItem->setFlag(QGraphicsItem::ItemIsSelectable, true); w3cWidgetItem->resize(foreignObjectWidth, foreignObjectHeight); scene->addItem(w3cWidgetItem); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(w3cWidgetItem, zFromSvg); w3cWidgetItem->show(); currentWidget = w3cWidgetItem; } } else if (type == "text") { UBGraphicsTextItem* textItem = textItemFromSvg(); if (textItem) { textItem->setFlag(QGraphicsItem::ItemIsMovable, true); textItem->setFlag(QGraphicsItem::ItemIsSelectable, true); scene->addItem(textItem); if (zFromSvg != UBZLayerController::errorNum()) UBGraphicsItem::assignZValue(textItem, zFromSvg); textItem->show(); } } else { qWarning() << "Ignoring unknown foreignObject:" << href; } } else if (currentWidget && (mXmlReader.name() == "preference")) { QString key = mXmlReader.attributes().value("key").toString(); QString value = mXmlReader.attributes().value("value").toString(); currentWidget->setPreference(key, value); } else if (currentWidget && (mXmlReader.name() == "datastoreEntry")) { QString key = mXmlReader.attributes().value("key").toString(); QString value = mXmlReader.attributes().value("value").toString(); currentWidget->setDatastoreEntry(key, value); } else if (mXmlReader.name() == "teacherBar" || mXmlReader.name() == "teacherGuide"){ sTeacherGuideNode.clear(); sTeacherGuideNode += ""; sTeacherGuideNode += "\n"; } else if (mXmlReader.name() == "media" || mXmlReader.name() == "link" || mXmlReader.name() == "title" || mXmlReader.name() == "comment" || mXmlReader.name() == "action") { sTeacherGuideNode += "<" + mXmlReader.name().toString() + " "; foreach(QXmlStreamAttribute attribute, mXmlReader.attributes()) sTeacherGuideNode += attribute.name().toString() + "=\"" + attribute.value().toString() + "\" "; sTeacherGuideNode += " />\n"; } else { // NOOP } } else if (mXmlReader.isEndElement()) { if (mXmlReader.name() == "g") { if(strokesGroup && scene){ scene->addItem(strokesGroup); //graphicsItemFromSvg(strokesGroup); } if (annotationGroup) { if (!annotationGroup->polygons().empty()) annotationGroup = 0; } mGroupHasInfo = false; mGroupDarkBackgroundColor = QColor(); mGroupLightBackgroundColor = QColor(); } else if (mXmlReader.name() == "teacherBar" || mXmlReader.name() == "teacherGuide"){ sTeacherGuideNode += ""; QMap elements = getAdditionalElementToStore(); IDataStorage* storageClass = elements.value("teacherGuide"); if(storageClass){ storageClass->load(sTeacherGuideNode); } } } } if (mXmlReader.hasError()) { qWarning() << "error parsing Sankore file " << mXmlReader.errorString(); } if (scene) { scene->setModified(false); } if (annotationGroup) { if (annotationGroup->polygons().empty()) delete annotationGroup; } return scene; } void UBSvgSubsetAdaptor::persistScene(UBDocumentProxy* proxy, UBGraphicsScene* pScene, const int pageIndex) { UBSvgSubsetWriter writer(proxy, pScene, pageIndex); writer.persistScene(pageIndex); } UBSvgSubsetAdaptor::UBSvgSubsetWriter::UBSvgSubsetWriter(UBDocumentProxy* proxy, UBGraphicsScene* pScene, const int pageIndex) : mScene(pScene) , mDocumentPath(proxy->persistencePath()) , mPageIndex(pageIndex) { // NOOP } void UBSvgSubsetAdaptor::UBSvgSubsetWriter::writeSvgElement() { mXmlWriter.writeStartElement("svg"); mXmlWriter.writeAttribute("version", "1.1"); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "version", UBSettings::currentFileVersion); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "uuid", UBStringUtils::toCanonicalUuid(mScene->uuid())); int margin = UBSettings::settings()->svgViewBoxMargin->get().toInt(); QRect normalized = mScene->normalizedSceneRect().toRect(); normalized.translate(margin * -1, margin * -1); normalized.setWidth(normalized.width() + (margin * 2)); normalized.setHeight(normalized.height() + (margin * 2)); mXmlWriter.writeAttribute("viewBox", QString("%1 %2 %3 %4").arg(normalized.x()).arg(normalized.y()).arg(normalized.width()).arg(normalized.height())); QSize pageNominalSize = mScene->nominalSize(); if (pageNominalSize.isValid()) { mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "nominal-size", QString("%1x%2").arg(pageNominalSize.width()).arg(pageNominalSize.height())); } mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "dark-background", mScene->isDarkBackground() ? xmlTrue : xmlFalse); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "crossed-background", mScene->isCrossedBackground() ? xmlTrue : xmlFalse); mXmlWriter.writeStartElement("rect"); mXmlWriter.writeAttribute("fill", mScene->isDarkBackground() ? "black" : "white"); mXmlWriter.writeAttribute("x", QString::number(normalized.x())); mXmlWriter.writeAttribute("y", QString::number(normalized.y())); mXmlWriter.writeAttribute("width", QString::number(normalized.width())); mXmlWriter.writeAttribute("height", QString::number(normalized.height())); mXmlWriter.writeEndElement(); } bool UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistScene(int pageIndex) { sTeacherGuideNode = ""; if (mScene->isModified()) { QBuffer buffer; buffer.open(QBuffer::WriteOnly); mXmlWriter.setDevice(&buffer); //Unused variable //QTime timer = QTime::currentTime(); mXmlWriter.setAutoFormatting(true); mXmlWriter.writeStartDocument(); mXmlWriter.writeDefaultNamespace(nsSvg); mXmlWriter.writeNamespace(nsXLink, "xlink"); mXmlWriter.writeNamespace(UBSettings::uniboardDocumentNamespaceUri, "ub"); mXmlWriter.writeNamespace(nsXHtml, "xhtml"); writeSvgElement(); QList items = mScene->items(); qSort(items.begin(), items.end(), itemZIndexComp); UBGraphicsStroke *openStroke = 0; bool groupHoldsInfo = false; while (!items.empty()) { QGraphicsItem *item = items.takeFirst(); UBGraphicsPolygonItem *polygonItem = qgraphicsitem_cast (item); if (polygonItem && polygonItem->isVisible()) { UBGraphicsStroke* currentStroke = polygonItem->stroke(); if (openStroke && (currentStroke != openStroke)) { mXmlWriter.writeEndElement(); //g openStroke = 0; groupHoldsInfo = false; } bool firstPolygonInStroke = currentStroke && !openStroke; if (firstPolygonInStroke) { mXmlWriter.writeStartElement("g"); openStroke = currentStroke; QMatrix matrix = item->sceneMatrix(); if (!matrix.isIdentity()) mXmlWriter.writeAttribute("transform", toSvgTransform(matrix)); UBGraphicsStroke* stroke = dynamic_cast(currentStroke); if (stroke) { QColor colorOnDarkBackground = polygonItem->colorOnDarkBackground(); QColor colorOnLightBackground = polygonItem->colorOnLightBackground(); if (colorOnDarkBackground.isValid() && colorOnLightBackground.isValid()) { mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "z-value" , QString("%1").arg(polygonItem->zValue())); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri , "fill-on-dark-background", colorOnDarkBackground.name()); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri , "fill-on-light-background", colorOnLightBackground.name()); groupHoldsInfo = true; } } if (stroke && !stroke->hasPressure()) { strokeToSvgPolyline(stroke, groupHoldsInfo); //we can dequeue all polygons belonging to that stroke foreach(UBGraphicsPolygonItem* gi, stroke->polygons()) { items.removeOne(gi); } continue; } } if (polygonItem->isNominalLine()) polygonItemToSvgLine(polygonItem, groupHoldsInfo); else polygonItemToSvgPolygon(polygonItem, groupHoldsInfo); continue; } if (openStroke) { mXmlWriter.writeEndElement(); //g groupHoldsInfo = false; openStroke = 0; } UBGraphicsPixmapItem *pixmapItem = qgraphicsitem_cast (item); if (pixmapItem && pixmapItem->isVisible()) { pixmapItemToLinkedImage(pixmapItem); continue; } UBGraphicsSvgItem *svgItem = qgraphicsitem_cast (item); if (svgItem && svgItem->isVisible()) { svgItemToLinkedSvg(svgItem); continue; } UBGraphicsVideoItem *videoItem = qgraphicsitem_cast (item); if (videoItem && videoItem->isVisible()) { videoItemToLinkedVideo(videoItem); continue; } UBGraphicsAudioItem* audioItem = qgraphicsitem_cast (item); if (audioItem && audioItem->isVisible()) { audioItemToLinkedAudio(audioItem); continue; } UBGraphicsAppleWidgetItem *appleWidgetItem = qgraphicsitem_cast (item); if (appleWidgetItem && appleWidgetItem->isVisible()) { graphicsAppleWidgetToSvg(appleWidgetItem); continue; } UBGraphicsW3CWidgetItem *w3cWidgetItem = qgraphicsitem_cast (item); if (w3cWidgetItem && w3cWidgetItem->isVisible()) { graphicsW3CWidgetToSvg(w3cWidgetItem); continue; } UBGraphicsPDFItem *pdfItem = qgraphicsitem_cast (item); if (pdfItem && pdfItem->isVisible()) { pdfItemToLinkedPDF(pdfItem); continue; } UBGraphicsTextItem *textItem = qgraphicsitem_cast (item); if (textItem && textItem->isVisible()) { textItemToSvg(textItem); continue; } UBGraphicsCurtainItem *curtainItem = qgraphicsitem_cast (item); if (curtainItem && curtainItem->isVisible()) { curtainItemToSvg(curtainItem); continue; } UBGraphicsRuler *ruler = qgraphicsitem_cast (item); if (ruler && ruler->isVisible()) { rulerToSvg(ruler); continue; } UBGraphicsCache* cache = qgraphicsitem_cast(item); if(cache && cache->isVisible()) { cacheToSvg(cache); continue; } UBGraphicsCompass *compass = qgraphicsitem_cast (item); if (compass && compass->isVisible()) { compassToSvg(compass); continue; } UBGraphicsProtractor *protractor = qgraphicsitem_cast (item); if (protractor && protractor->isVisible()) { protractorToSvg(protractor); continue; } UBGraphicsTriangle *triangle = qgraphicsitem_cast (item); if (triangle && triangle->isVisible()) { triangleToSvg(triangle); continue; } } if (openStroke) { mXmlWriter.writeEndElement(); groupHoldsInfo = false; openStroke = 0; } QMap elements = getAdditionalElementToStore(); QVector dataStorageItems = elements.value("teacherGuide")->save(pageIndex); foreach(tIDataStorage* eachItem, dataStorageItems){ if(eachItem->type == eElementType_START){ mXmlWriter.writeStartElement(eachItem->name); foreach(QString key,eachItem->attributes.keys()) mXmlWriter.writeAttribute(key,eachItem->attributes.value(key)); } else if (eachItem->type == eElementType_END) mXmlWriter.writeEndElement(); else if (eachItem->type == eElementType_UNIQUE){ mXmlWriter.writeStartElement(eachItem->name); foreach(QString key,eachItem->attributes.keys()) mXmlWriter.writeAttribute(key,eachItem->attributes.value(key)); mXmlWriter.writeEndElement(); } else qWarning() << "unknown type"; } mXmlWriter.writeEndDocument(); QString fileName = mDocumentPath + UBFileSystemUtils::digitFileFormat("/page%1.svg", UBApplication::boardController->pageFromSceneIndex(mPageIndex)); QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qCritical() << "cannot open " << fileName << " for writing ..."; return false; } file.write(buffer.data()); file.flush(); file.close(); } else { qDebug() << "ignoring unmodified page" << UBApplication::boardController->pageFromSceneIndex(mPageIndex); } return true; } void UBSvgSubsetAdaptor::UBSvgSubsetWriter::polygonItemToSvgLine(UBGraphicsPolygonItem* polygonItem, bool groupHoldsInfo) { mXmlWriter.writeStartElement("line"); QLineF line = polygonItem->originalLine(); mXmlWriter.writeAttribute("x1", QString::number(line.p1().x(), 'f', 2)); mXmlWriter.writeAttribute("y1", QString::number(line.p1().y(), 'f', 2)); // SVG renderers (Chrome) do not like line where (x1, y1) == (x2, y2) qreal x2 = line.p2().x(); if (line.p1() == line.p2()) x2 += 0.01; mXmlWriter.writeAttribute("x2", QString::number(x2, 'f', 2)); mXmlWriter.writeAttribute("y2", QString::number(line.p2().y(), 'f', 2)); mXmlWriter.writeAttribute("stroke-width", QString::number(polygonItem->originalWidth(), 'f', -1)); mXmlWriter.writeAttribute("stroke", polygonItem->brush().color().name()); qreal alpha = polygonItem->brush().color().alphaF(); if (alpha < 1.0) mXmlWriter.writeAttribute("stroke-opacity", QString::number(alpha, 'f', 2)); mXmlWriter.writeAttribute("stroke-linecap", "round"); if (!groupHoldsInfo) { mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "z-value", QString("%1").arg(polygonItem->zValue())); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "fill-on-dark-background", polygonItem->colorOnDarkBackground().name()); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "fill-on-light-background", polygonItem->colorOnLightBackground().name()); } mXmlWriter.writeEndElement(); } void UBSvgSubsetAdaptor::UBSvgSubsetWriter::strokeToSvgPolyline(UBGraphicsStroke* stroke, bool groupHoldsInfo) { QList pols = stroke->polygons(); if (pols.length() > 0) { mXmlWriter.writeStartElement("polyline"); QVector points; foreach(UBGraphicsPolygonItem* polygon, pols) { points << polygon->originalLine().p1(); } points << pols.last()->originalLine().p2(); // SVG renderers (Chrome) do not like line withe where x1/y1 == x2/y2 if (points.size() == 2 && (points.at(0) == points.at(1))) { points[1] = QPointF(points[1].x() + 0.01, points[1].y()); } QString svgPoints = pointsToSvgPointsAttribute(points); mXmlWriter.writeAttribute("points", svgPoints); UBGraphicsPolygonItem* firstPolygonItem = pols.at(0); mXmlWriter.writeAttribute("fill", "none"); mXmlWriter.writeAttribute("stroke-width", QString::number(firstPolygonItem->originalWidth(), 'f', 2)); mXmlWriter.writeAttribute("stroke", firstPolygonItem->brush().color().name()); mXmlWriter.writeAttribute("stroke-opacity", QString("%1").arg(firstPolygonItem->brush().color().alphaF())); mXmlWriter.writeAttribute("stroke-linecap", "round"); if (!groupHoldsInfo) { mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "z-value", QString("%1").arg(firstPolygonItem->zValue())); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri , "fill-on-dark-background", firstPolygonItem->colorOnDarkBackground().name()); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri , "fill-on-light-background", firstPolygonItem->colorOnLightBackground().name()); } mXmlWriter.writeEndElement(); } } void UBSvgSubsetAdaptor::UBSvgSubsetWriter::strokeToSvgPolygon(UBGraphicsStroke* stroke, bool groupHoldsInfo) { QList pis = stroke->polygons(); if (pis.length() > 0) { QPolygonF united; foreach(UBGraphicsPolygonItem* pi, pis) { united = united.united(pi->polygon()); } UBGraphicsPolygonItem *clone = static_cast(pis.at(0)->deepCopy()); clone->setPolygon(united); polygonItemToSvgPolygon(clone, groupHoldsInfo); } } void UBSvgSubsetAdaptor::UBSvgSubsetWriter::polygonItemToSvgPolygon(UBGraphicsPolygonItem* polygonItem, bool groupHoldsInfo) { QPolygonF polygon = polygonItem->polygon(); int pointsCount = polygon.size(); if (polygonItem && pointsCount > 0) { mXmlWriter.writeStartElement("polygon"); QString points = pointsToSvgPointsAttribute(polygon); mXmlWriter.writeAttribute("points", points); mXmlWriter.writeAttribute("fill", polygonItem->brush().color().name()); qreal alpha = polygonItem->brush().color().alphaF(); mXmlWriter.writeAttribute("fill-opacity", QString::number(alpha, 'f', 2)); // we trick SVG antialiasing, to avoid seeing light gaps between polygons if (alpha < 1.0) { qreal trickedAlpha = trickAlpha(alpha); mXmlWriter.writeAttribute("stroke", polygonItem->brush().color().name()); mXmlWriter.writeAttribute("stroke-width", "1"); mXmlWriter.writeAttribute("stroke-opacity", QString::number(trickedAlpha, 'f', 2)); } // svg default fill rule is nonzero, but Qt is evenodd // //http://www.w3.org/TR/SVG11/painting.html //http://doc.trolltech.com/4.5/qgraphicspolygonitem.html#fillRule // if (polygonItem->fillRule() == Qt::OddEvenFill) mXmlWriter.writeAttribute("fill-rule", "evenodd"); if (!groupHoldsInfo) { mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "z-value", QString("%1").arg(polygonItem->zValue())); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri , "fill-on-dark-background", polygonItem->colorOnDarkBackground().name()); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri , "fill-on-light-background", polygonItem->colorOnLightBackground().name()); } mXmlWriter.writeEndElement(); } } UBGraphicsPolygonItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::polygonItemFromPolygonSvg(const QColor& pDefaultColor) { UBGraphicsPolygonItem* polygonItem = new UBGraphicsPolygonItem(); QStringRef svgPoints = mXmlReader.attributes().value("points"); QPolygonF polygon; if (!svgPoints.isNull()) { QStringList ts = svgPoints.toString().split(QLatin1Char(' '), QString::SkipEmptyParts); foreach(const QString sPoint, ts) { QStringList sCoord = sPoint.split(QLatin1Char(','), QString::SkipEmptyParts); if (sCoord.size() == 2) { QPointF point; point.setX(sCoord.at(0).toFloat()); point.setY(sCoord.at(1).toFloat()); polygon << point; } else if (sCoord.size() == 4){ //This is the case on system were the "," is used to seperate decimal QPointF point; QString x = sCoord.at(0) + "." + sCoord.at(1); QString y = sCoord.at(2) + "." + sCoord.at(3); point.setX(x.toFloat()); point.setY(y.toFloat()); polygon << point; } else { qWarning() << "cannot make sense of a 'point' value" << sCoord; } } } else { qWarning() << "cannot make sense of 'points' value " << svgPoints.toString(); } polygonItem->setPolygon(polygon); QStringRef svgFill = mXmlReader.attributes().value("fill"); QColor brushColor = pDefaultColor; if (!svgFill.isNull()) { brushColor.setNamedColor(svgFill.toString()); } QStringRef svgFillOpacity = mXmlReader.attributes().value("fill-opacity"); qreal opacity = 1.0; if (!svgFillOpacity.isNull()) { opacity = svgFillOpacity.toString().toFloat(); brushColor.setAlphaF(opacity); } polygonItem->setColor(brushColor); QStringRef ubZValue = mXmlReader.attributes().value(mNamespaceUri, "z-value"); if (!ubZValue.isNull()) { UBGraphicsItem::assignZValue(polygonItem, ubZValue.toString().toFloat()); } else { UBGraphicsItem::assignZValue(polygonItem, mGroupZIndex); } QStringRef ubFillOnDarkBackground = mXmlReader.attributes().value(mNamespaceUri, "fill-on-dark-background"); if (!ubFillOnDarkBackground.isNull()) { QColor color; color.setNamedColor(ubFillOnDarkBackground.toString()); if (!color.isValid()) color = Qt::white; color.setAlphaF(opacity); polygonItem->setColorOnDarkBackground(color); } else { QColor color = mGroupDarkBackgroundColor; color.setAlphaF(opacity); polygonItem->setColorOnDarkBackground(color); } QStringRef ubFillOnLightBackground = mXmlReader.attributes().value(mNamespaceUri, "fill-on-light-background"); if (!ubFillOnLightBackground.isNull()) { QColor color; color.setNamedColor(ubFillOnLightBackground.toString()); if (!color.isValid()) color = Qt::black; color.setAlphaF(opacity); polygonItem->setColorOnLightBackground(color); } else { QColor color = mGroupLightBackgroundColor; color.setAlphaF(opacity); polygonItem->setColorOnLightBackground(color); } return polygonItem; } UBGraphicsPolygonItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::polygonItemFromLineSvg(const QColor& pDefaultColor) { QStringRef svgX1 = mXmlReader.attributes().value("x1"); QStringRef svgY1 = mXmlReader.attributes().value("y1"); QStringRef svgX2 = mXmlReader.attributes().value("x2"); QStringRef svgY2 = mXmlReader.attributes().value("y2"); QLineF line; if (!svgX1.isNull() && !svgY1.isNull() && !svgX2.isNull() && !svgY2.isNull()) { qreal x1 = svgX1.toString().toFloat(); qreal y1 = svgY1.toString().toFloat(); qreal x2 = svgX2.toString().toFloat(); qreal y2 = svgY2.toString().toFloat(); line.setLine(x1, y1, x2, y2); } else { qWarning() << "cannot make sense of 'line' value"; return 0; } QStringRef strokeWidth = mXmlReader.attributes().value("stroke-width"); qreal lineWidth = 1.; if (!strokeWidth.isNull()) { lineWidth = strokeWidth.toString().toFloat(); } UBGraphicsPolygonItem* polygonItem = new UBGraphicsPolygonItem(line, lineWidth); QStringRef svgStroke = mXmlReader.attributes().value("stroke"); QColor brushColor = pDefaultColor; if (!svgStroke.isNull()) { brushColor.setNamedColor(svgStroke.toString()); } QStringRef svgStrokeOpacity = mXmlReader.attributes().value("stroke-opacity"); qreal opacity = 1.0; if (!svgStrokeOpacity.isNull()) { opacity = svgStrokeOpacity.toString().toFloat(); brushColor.setAlphaF(opacity); } polygonItem->setColor(brushColor); QStringRef ubZValue = mXmlReader.attributes().value(mNamespaceUri, "z-value"); if (!ubZValue.isNull()) { UBGraphicsItem::assignZValue(polygonItem, ubZValue.toString().toFloat()); } else { UBGraphicsItem::assignZValue(polygonItem, mGroupZIndex); } QStringRef ubFillOnDarkBackground = mXmlReader.attributes().value(mNamespaceUri, "fill-on-dark-background"); if (!ubFillOnDarkBackground.isNull()) { QColor color; color.setNamedColor(ubFillOnDarkBackground.toString()); if (!color.isValid()) color = Qt::white; color.setAlphaF(opacity); polygonItem->setColorOnDarkBackground(color); } else { QColor color = mGroupDarkBackgroundColor; color.setAlphaF(opacity); polygonItem->setColorOnDarkBackground(color); } QStringRef ubFillOnLightBackground = mXmlReader.attributes().value(mNamespaceUri, "fill-on-light-background"); if (!ubFillOnLightBackground.isNull()) { QColor color; color.setNamedColor(ubFillOnLightBackground.toString()); if (!color.isValid()) color = Qt::black; color.setAlphaF(opacity); polygonItem->setColorOnLightBackground(color); } else { QColor color = mGroupLightBackgroundColor; color.setAlphaF(opacity); polygonItem->setColorOnLightBackground(color); } return polygonItem; } QList UBSvgSubsetAdaptor::UBSvgSubsetReader::polygonItemsFromPolylineSvg(const QColor& pDefaultColor) { QStringRef strokeWidth = mXmlReader.attributes().value("stroke-width"); qreal lineWidth = 1.; if (!strokeWidth.isNull()) { lineWidth = strokeWidth.toString().toFloat(); } QColor brushColor = pDefaultColor; QStringRef svgStroke = mXmlReader.attributes().value("stroke"); if (!svgStroke.isNull()) { brushColor.setNamedColor(svgStroke.toString()); } qreal opacity = 1.0; QStringRef svgStrokeOpacity = mXmlReader.attributes().value("stroke-opacity"); if (!svgStrokeOpacity.isNull()) { opacity = svgStrokeOpacity.toString().toFloat(); brushColor.setAlphaF(opacity); } QStringRef ubZValue = mXmlReader.attributes().value(mNamespaceUri, "z-value"); qreal zValue = mGroupZIndex; if (!ubZValue.isNull()) { zValue = ubZValue.toString().toFloat(); } QColor colorOnDarkBackground = mGroupDarkBackgroundColor; QStringRef ubFillOnDarkBackground = mXmlReader.attributes().value(mNamespaceUri, "fill-on-dark-background"); if (!ubFillOnDarkBackground.isNull()) { colorOnDarkBackground.setNamedColor(ubFillOnDarkBackground.toString()); } if (!colorOnDarkBackground.isValid()) colorOnDarkBackground = Qt::white; colorOnDarkBackground.setAlphaF(opacity); QColor colorOnLightBackground = mGroupLightBackgroundColor; QStringRef ubFillOnLightBackground = mXmlReader.attributes().value(mNamespaceUri, "fill-on-light-background"); if (!ubFillOnLightBackground.isNull()) { QColor colorOnLightBackground; colorOnLightBackground.setNamedColor(ubFillOnLightBackground.toString()); } if (!colorOnLightBackground.isValid()) colorOnLightBackground = Qt::black; colorOnLightBackground.setAlphaF(opacity); QStringRef svgPoints = mXmlReader.attributes().value("points"); QList polygonItems; if (!svgPoints.isNull()) { QStringList ts = svgPoints.toString().split(QLatin1Char(' '), QString::SkipEmptyParts); QList points; foreach(const QString sPoint, ts) { QStringList sCoord = sPoint.split(QLatin1Char(','), QString::SkipEmptyParts); if (sCoord.size() == 2) { QPointF point; point.setX(sCoord.at(0).toFloat()); point.setY(sCoord.at(1).toFloat()); points << point; } else if (sCoord.size() == 4){ //This is the case on system were the "," is used to seperate decimal QPointF point; QString x = sCoord.at(0) + "." + sCoord.at(1); QString y = sCoord.at(2) + "." + sCoord.at(3); point.setX(x.toFloat()); point.setY(y.toFloat()); points << point; } else { qWarning() << "cannot make sense of a 'point' value" << sCoord; } } for (int i = 0; i < points.size() - 1; i++) { UBGraphicsPolygonItem* polygonItem = new UBGraphicsPolygonItem(QLineF(points.at(i), points.at(i + 1)), lineWidth); polygonItem->setColor(brushColor); UBGraphicsItem::assignZValue(polygonItem, zValue); polygonItem->setColorOnDarkBackground(colorOnDarkBackground); polygonItem->setColorOnLightBackground(colorOnLightBackground); polygonItems <uuid().toString() + ".png"; QString path = mDocumentPath + "/" + fileName; if (!QFile::exists(path)) { QDir dir; dir.mkdir(mDocumentPath + "/" + UBPersistenceManager::imageDirectory); pixmapItem->pixmap().toImage().save(path, "PNG"); } mXmlWriter.writeAttribute(nsXLink, "href", fileName); graphicsItemToSvg(pixmapItem); mXmlWriter.writeEndElement(); } UBGraphicsPixmapItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::pixmapItemFromSvg() { UBGraphicsPixmapItem* pixmapItem = new UBGraphicsPixmapItem(); QStringRef imageHref = mXmlReader.attributes().value(nsXLink, "href"); if (!imageHref.isNull()) { QString href = imageHref.toString(); QPixmap pix(mDocumentPath + "/" + UBFileSystemUtils::normalizeFilePath(href)); pixmapItem->setPixmap(pix); } else { qWarning() << "cannot make sens of image href value"; return 0; } graphicsItemFromSvg(pixmapItem); return pixmapItem; } void UBSvgSubsetAdaptor::UBSvgSubsetWriter::svgItemToLinkedSvg(UBGraphicsSvgItem* svgItem) { mXmlWriter.writeStartElement("image"); QString fileName = UBPersistenceManager::imageDirectory + "/" + svgItem->uuid().toString() + ".svg"; QString path = mDocumentPath + "/" + fileName; if (!QFile::exists(path)) { QDir dir; dir.mkdir(mDocumentPath + "/" + UBPersistenceManager::imageDirectory); QFile file(path); if (!file.open(QIODevice::WriteOnly)) { qWarning() << "cannot open file for writing embeded svg content " << path; return; } file.write(svgItem->fileData()); } mXmlWriter.writeAttribute(nsXLink, "href", fileName); graphicsItemToSvg(svgItem); mXmlWriter.writeEndElement(); } UBGraphicsSvgItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::svgItemFromSvg() { UBGraphicsSvgItem* svgItem = 0; QStringRef imageHref = mXmlReader.attributes().value(nsXLink, "href"); if (!imageHref.isNull()) { QString href = imageHref.toString(); svgItem = new UBGraphicsSvgItem(mDocumentPath + "/" + UBFileSystemUtils::normalizeFilePath(href)); } else { qWarning() << "cannot make sens of image href value"; return 0; } graphicsItemFromSvg(svgItem); return svgItem; } void UBSvgSubsetAdaptor::UBSvgSubsetWriter::pdfItemToLinkedPDF(UBGraphicsPDFItem* pdfItem) { mXmlWriter.writeStartElement("foreignObject"); mXmlWriter.writeAttribute("requiredExtensions", "http://ns.adobe.com/pdf/1.3/"); QString fileName = UBPersistenceManager::objectDirectory + "/" + pdfItem->fileUuid().toString() + ".pdf"; QString path = mDocumentPath + "/" + fileName; if (!QFile::exists(path)) { QDir dir; dir.mkdir(mDocumentPath + "/" + UBPersistenceManager::objectDirectory); QFile file(path); if (!file.open(QIODevice::WriteOnly)) { qWarning() << "cannot open file for writing embeded pdf content " << path; return; } file.write(pdfItem->fileData()); } mXmlWriter.writeAttribute(nsXLink, "href", fileName + "#page=" + QString::number(pdfItem->pageNumber())); graphicsItemToSvg(pdfItem); mXmlWriter.writeEndElement(); } UBGraphicsPDFItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::pdfItemFromPDF() { UBGraphicsPDFItem* pdfItem = 0; QString href = mXmlReader.attributes().value(nsXLink, "href").toString(); QStringList parts = href.split("#page="); if (parts.count() != 2) { qWarning() << "invalid pdf href value" << href; return 0; } QString pdfPath = parts[0]; QUuid uuid(QFileInfo(pdfPath).baseName()); int pageNumber = parts[1].toInt(); pdfItem = new UBGraphicsPDFItem(PDFRenderer::rendererForUuid(uuid, mDocumentPath + "/" + UBFileSystemUtils::normalizeFilePath(pdfPath)), pageNumber); graphicsItemFromSvg(pdfItem); return pdfItem; } void UBSvgSubsetAdaptor::UBSvgSubsetWriter::audioItemToLinkedAudio(UBGraphicsAudioItem* audioItem) { mXmlWriter.writeStartElement("audio"); graphicsItemToSvg(audioItem); if (audioItem->mediaObject()->state() == Phonon::PausedState && audioItem->mediaObject()->remainingTime() > 0) { qint64 pos = audioItem->mediaObject()->currentTime(); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "position", QString("%1").arg(pos)); } QString audioFileHref = audioItem->mediaFileUrl().toString(); mXmlWriter.writeAttribute(nsXLink, "href", audioFileHref); mXmlWriter.writeEndElement(); } void UBSvgSubsetAdaptor::UBSvgSubsetWriter::videoItemToLinkedVideo(UBGraphicsVideoItem* videoItem) { /* w3c sample * *