/* * 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 #include #include #include "core/UBPersistenceManager.h" #include "document/UBDocumentProxy.h" #include "domain/UBItem.h" #include "domain/UBGraphicsPolygonItem.h" #include "domain/UBGraphicsStroke.h" #include "domain/UBGraphicsTextItem.h" #include "domain/UBGraphicsSvgItem.h" #include "domain/UBGraphicsPixmapItem.h" #include "domain/UBGraphicsVideoItem.h" #include "domain/UBGraphicsAudioItem.h" #include "domain/UBGraphicsWidgetItem.h" #include "domain/UBGraphicsTextItem.h" #include "domain/UBGraphicsTextItemDelegate.h" #include "domain/UBW3CWidget.h" #include "frameworks/UBFileSystemUtils.h" #include "UBCFFSubsetAdaptor.h" #include "UBMetadataDcSubsetAdaptor.h" #include "UBThumbnailAdaptor.h" #include "UBSvgSubsetAdaptor.h" #include "core/UBApplication.h" #include "QFile" #include "core/memcheck.h" //#include "qtlogger.h" //tag names definition. Use them everiwhere! static QString tElement = "element"; static QString tGroup = "group"; static QString tEllipse = "ellipse"; static QString tIwb = "iwb"; static QString tMeta = "meta"; static QString tPage = "page"; static QString tPageset = "pageset"; static QString tG = "g"; static QString tSwitch = "switch"; static QString tPolygon = "polygon"; static QString tPolyline = "polyline"; static QString tRect = "rect"; static QString tSvg = "svg"; static QString tText = "text"; static QString tTextarea = "textarea"; static QString tTspan = "tspan"; static QString tBreak = "tbreak"; static QString tImage = "image"; static QString tFlash = "flash"; static QString tAudio = "a"; static QString tVideo = "video"; //attribute names definition static QString aFill = "fill"; static QString aFillopacity = "fill-opacity"; static QString aX = "x"; static QString aY = "y"; static QString aWidth = "width"; static QString aHeight = "height"; static QString aStroke = "stroke"; static QString aStrokewidth = "stroke-width"; static QString aCx = "cx"; static QString aCy = "cy"; static QString aRx = "rx"; static QString aRy = "ry"; static QString aTransform = "transform"; static QString aViewbox = "viewbox"; static QString aFontSize = "font-size"; static QString aFontfamily = "font-family"; static QString aFontstretch = "font-stretch"; static QString aFontstyle = "font-style"; static QString aFontweight = "font-weight"; static QString aTextalign = "text-align"; static QString aPoints = "points"; static QString svgNS = "http://www.w3.org/2000/svg"; static QString iwbNS = "http://www.becta.org.uk/iwb"; static QString aId = "id"; static QString aRef = "ref"; static QString aHref = "href"; static QString aBackground = "background"; static QString aLocked = "locked"; static QString aEditable = "editable"; //attributes part names static QString apRotate = "rotate"; static QString apTranslate = "translate"; UBCFFSubsetAdaptor::UBCFFSubsetAdaptor() {} bool UBCFFSubsetAdaptor::ConvertCFFFileToUbz(QString &cffSourceFile, UBDocumentProxy* pDocument) { //TODO // fill document proxy metadata // create persistance manager to save data using proxy // create UBCFFSubsetReader and make it parse cffSourceFolder QFile file(cffSourceFile); if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Cannot open file " << cffSourceFile << " for reading ..."; return false; } UBCFFSubsetReader cffReader(pDocument, &file); bool result = cffReader.parse(); file.close(); return result; } UBCFFSubsetAdaptor::UBCFFSubsetReader::UBCFFSubsetReader(UBDocumentProxy *proxy, QFile *content): mProxy(proxy) { int errorLine, errorColumn; QString errorStr; if(!mDOMdoc.setContent(content, true, &errorStr, &errorLine, &errorColumn)){ qWarning() << "Error:Parseerroratline" << errorLine << "," << "column" << errorColumn << ":" << errorStr; } else { qDebug() << "well parsed to DOM"; pwdContent = QFileInfo(content->fileName()).dir().absolutePath(); } qDebug() << "tmp path is" << pwdContent; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parse() { UBMetadataDcSubsetAdaptor::persist(mProxy); mIndent = ""; if (!getTempFileName() || !createTempFlashPath()) return false; if (mDOMdoc.isNull()) return false; bool result = parseDoc(); if (result) result = mProxy->pageCount() != 0; if (QFile::exists(mTempFilePath)) QFile::remove(mTempFilePath); // if (mTmpFlashDir.exists()) // UBFileSystemUtils::deleteDir(mTmpFlashDir.path()); return result; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseGSection(const QDomElement &element) { QDomElement currentSvgElement = element.firstChildElement(); while (!currentSvgElement.isNull()) { if (!parseSvgElement(currentSvgElement)) return false; currentSvgElement = currentSvgElement.nextSiblingElement(); } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgSwitchSection(const QDomElement &element) { QDomElement currentSvgElement = element.firstChildElement(); while (!currentSvgElement.isNull()) { if (parseSvgElement(currentSvgElement)) return true; } return false; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgRect(const QDomElement &element) { qreal x1 = element.attribute(aX).toDouble(); qreal y1 = element.attribute(aY).toDouble(); //rect dimensions qreal width = element.attribute(aWidth).toDouble(); qreal height = element.attribute(aHeight).toDouble(); QString textFillColor = element.attribute(aFill); QString textStrokeColor = element.attribute(aStroke); QString textStrokeWidth = element.attribute(aStrokewidth); QColor fillColor = !textFillColor.isNull() ? colorFromString(textFillColor) : QColor(); QColor strokeColor = !textStrokeColor.isNull() ? colorFromString(textStrokeColor) : QColor(); int strokeWidth = textStrokeWidth.toInt(); x1 -= strokeWidth/2; y1 -= strokeWidth/2; width += strokeWidth; height += strokeWidth; //init svg generator with temp file QSvgGenerator *generator = createSvgGenerator(width, height); //init painter to paint to svg QPainter painter; painter.begin(generator); //fill rect if (fillColor.isValid()) { painter.setBrush(QBrush(fillColor)); painter.fillRect(0, 0, width, height, fillColor); } QPen pen; if (strokeColor.isValid()) { pen.setColor(strokeColor); } if (strokeWidth) pen.setWidth(strokeWidth); painter.setPen(pen); painter.drawRect(0, 0, width, height); painter.end(); UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); QTransform transform; QString textTransform = element.attribute(aTransform); svgItem->resetTransform(); if (!textTransform.isNull()) { transform = transformFromString(textTransform, svgItem); } repositionSvgItem(svgItem, width, height, x1, y1, transform); hashSceneItem(element, svgItem); delete generator; return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgEllipse(const QDomElement &element) { //ellipse horisontal and vertical radius qreal rx = element.attribute(aRx).toDouble(); qreal ry = element.attribute(aRy).toDouble(); QSvgGenerator *generator = createSvgGenerator(rx * 2, ry * 2); //fill and stroke color QColor fillColor = colorFromString(element.attribute(aFill)); QColor strokeColor = colorFromString(element.attribute(aStroke)); int strokeWidth = element.attribute(aStrokewidth).toInt(); //ellipse center coordinates qreal cx = element.attribute(aCx).toDouble(); qreal cy = element.attribute(aCy).toDouble(); //init painter to paint to svg QPainter painter; painter.begin(generator); QPen pen(strokeColor); pen.setWidth(strokeWidth); painter.setPen(pen); painter.setBrush(QBrush(fillColor)); painter.drawEllipse(0, 0, rx * 2, ry * 2); painter.end(); UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); QTransform transform; QString textTransform = element.attribute(aTransform); svgItem->resetTransform(); if (!textTransform.isNull()) { transform = transformFromString(textTransform, svgItem); } repositionSvgItem(svgItem, rx * 2, ry * 2, cx - 2*rx, cy+ry, transform); hashSceneItem(element, svgItem); delete generator; return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolygon(const QDomElement &element) { QString svgPoints = element.attribute(aPoints); QPolygonF polygon; if (!svgPoints.isNull()) { QStringList ts = svgPoints.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; } } } //bounding rect lef top corner coordinates qreal x1 = polygon.boundingRect().topLeft().x(); qreal y1 = polygon.boundingRect().topLeft().y(); //bounding rect dimensions qreal width = polygon.boundingRect().width(); qreal height = polygon.boundingRect().height(); QString strokeColorText = element.attribute(aStroke); QString fillColorText = element.attribute(aFill); QString strokeWidthText = element.attribute(aStrokewidth); QColor strokeColor = !strokeColorText.isEmpty() ? colorFromString(strokeColorText) : QColor(); QColor fillColor = !fillColorText.isEmpty() ? colorFromString(fillColorText) : QColor(); int strokeWidth = strokeWidthText.toDouble(); QPen pen; pen.setColor(strokeColor); pen.setWidth(strokeWidth); QBrush brush; brush.setColor(fillColor); brush.setStyle(Qt::SolidPattern); QSvgGenerator *generator = createSvgGenerator(width + pen.width(), height + pen.width()); QPainter painter; painter.begin(generator); //drawing to svg tmp file painter.translate(pen.widthF() / 2 - x1, pen.widthF() / 2 - y1); painter.setBrush(brush); painter.setPen(pen); painter.drawPolygon(polygon); painter.end(); //add resulting svg file to scene UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); QTransform transform; QString textTransform = element.attribute(aTransform); svgItem->resetTransform(); if (!textTransform.isNull()) { transform = transformFromString(textTransform, svgItem); } repositionSvgItem(svgItem, width +strokeWidth, height + strokeWidth, x1 - strokeWidth/2 + transform.m31(), y1 + strokeWidth/2 + transform.m32(), transform); hashSceneItem(element, svgItem); delete generator; return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &element) { QString svgPoints = element.attribute(aPoints); QPolygonF polygon; if (!svgPoints.isNull()) { QStringList ts = svgPoints.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; } } } //bounding rect lef top corner coordinates qreal x1 = polygon.boundingRect().topLeft().x(); qreal y1 = polygon.boundingRect().topLeft().y(); //bounding rect dimensions qreal width = polygon.boundingRect().width(); qreal height = polygon.boundingRect().height(); QString strokeColorText = element.attribute(aStroke); QString strokeWidthText = element.attribute(aStrokewidth); QColor strokeColor = !strokeColorText.isEmpty() ? colorFromString(strokeColorText) : QColor(); int strokeWidth = strokeWidthText.toDouble(); width += strokeWidth; height += strokeWidth; QPen pen; pen.setColor(strokeColor); pen.setWidth(strokeWidth); QSvgGenerator *generator = createSvgGenerator(width + pen.width(), height + pen.width()); QPainter painter; painter.begin(generator); //drawing to svg tmp file painter.translate(pen.widthF()/2 - x1, pen.widthF()/2- y1); painter.setPen(pen); painter.drawPolyline(polygon); painter.end(); //add resulting svg file to scene UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); QTransform transform; QString textTransform = element.attribute(aTransform); svgItem->resetTransform(); if (!textTransform.isNull()) { transform = transformFromString(textTransform, svgItem); } repositionSvgItem(svgItem, width +strokeWidth, height + strokeWidth, x1 + transform.m31() - strokeWidth/2, y1 + transform.m32() + strokeWidth/2, transform); hashSceneItem(element, svgItem); delete generator; return true; } void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTextAttributes(const QDomElement &element, qreal &fontSize, QColor &fontColor, QString &fontFamily, QString &fontStretch, bool &italic, int &fontWeight, int &textAlign, QTransform &fontTransform) { //consider inch has 72 liens //since svg font size is given in pixels, divide it by pixels per line QString fontSz = element.attribute(aFontSize); if (!fontSz.isNull()) fontSize = fontSz.toDouble() * 72 / QApplication::desktop()->physicalDpiY(); QString fontColorText = element.attribute(aFill); if (!fontColorText.isNull()) fontColor = colorFromString(fontColorText); QString fontFamilyText = element.attribute(aFontfamily); if (!fontFamilyText.isNull()) fontFamily = fontFamilyText; QString fontStretchText = element.attribute(aFontstretch); if (!fontStretchText.isNull()) fontStretch = fontStretchText; if (!element.attribute(aFontstyle).isNull()) italic = (element.attribute(aFontstyle) == "italic"); QString weight = element.attribute(aFontweight); if (!weight.isNull()) { if (weight == "normal") fontWeight = QFont::Normal; else if (weight == "light") fontWeight = QFont::Light; else if (weight == "demibold") fontWeight = QFont::DemiBold; else if (weight == "bold") fontWeight = QFont::Bold; else if (weight == "black") fontWeight = QFont::Black; } QString align = element.attribute(aTextalign); if (!align.isNull()) { if (align == "middle" || align == "center") textAlign = Qt::AlignHCenter; else if (align == "start") textAlign = Qt::AlignLeft; else if (align == "end") textAlign = Qt::AlignRight; } if (!element.attribute(aTransform).isNull()) fontTransform = transformFromString(element.attribute(aTransform)); } void UBCFFSubsetAdaptor::UBCFFSubsetReader::readTextBlockAttr(const QDomElement &element, QTextBlockFormat &format) { QString fontStretchText = element.attribute(aFontstretch); if (!fontStretchText.isNull()) format.setAlignment(Qt::AlignJustify); QString align = element.attribute(aTextalign); if (!align.isNull()) { if (align == "middle" || align == "center") format.setAlignment(Qt::AlignHCenter); else if (align == "start") format.setAlignment(Qt::AlignLeft); else if (align == "end") format.setAlignment(Qt::AlignRight); else if (align == "justify") format.setAlignment(Qt::AlignJustify); } } void UBCFFSubsetAdaptor::UBCFFSubsetReader::readTextCharAttr(const QDomElement &element, QTextCharFormat &format) { QString fontSz = element.attribute(aFontSize); if (!fontSz.isNull()) { qreal fontSize = fontSz.toDouble() * 72 / QApplication::desktop()->physicalDpiY(); format.setFontPointSize(fontSize); } QString fontColorText = element.attribute(aFill); if (!fontColorText.isNull()) { QColor fontColor = colorFromString(fontColorText); if (fontColor.isValid()) format.setForeground(fontColor); } QString fontFamilyText = element.attribute(aFontfamily); if (!fontFamilyText.isNull()) { format.setFontFamily(fontFamilyText); } if (!element.attribute(aFontstyle).isNull()) { bool italic = (element.attribute(aFontstyle) == "italic"); format.setFontItalic(italic); } QString weight = element.attribute(aFontweight); if (!weight.isNull()) { if (weight == "normal") format.setFontWeight(QFont::Normal); else if (weight == "light") format.setFontWeight(QFont::Light); else if (weight == "demibold") format.setFontWeight(QFont::DemiBold); else if (weight == "bold") format.setFontWeight(QFont::Bold); else if (weight == "black") format.setFontWeight(QFont::Black); } } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgText(const QDomElement &element) { qreal x = element.attribute(aX).toDouble(); qreal y = element.attribute(aY).toDouble(); qreal width = element.attribute(aWidth).toDouble(); qreal height = element.attribute(aHeight).toDouble(); qreal fontSize = 12; QColor fontColor(qApp->palette().foreground().color()); QString fontFamily = "Arial"; QString fontStretch = "normal"; bool italic = false; int fontWeight = QFont::Normal; int textAlign = Qt::AlignLeft; QTransform fontTransform; parseTextAttributes(element, fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); QFont startFont(fontFamily, fontSize, fontWeight, italic); height = QFontMetrics(startFont).height(); width = QFontMetrics(startFont).width(element.text()) + 5; QSvgGenerator *generator = createSvgGenerator(width, height); QPainter painter; painter.begin(generator); painter.setFont(startFont); qreal curY = 0.0; qreal curX = 0.0; qreal linespacing = QFontMetricsF(painter.font()).leading(); // remember if text area has transform // QString transformString; QTransform transform = fontTransform; QRectF lastDrawnTextBoundingRect; //parse text area tags //recursive call any tspan in text svg element parseTSpan(element, painter , curX, curY, width, height, linespacing, lastDrawnTextBoundingRect , fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); painter.end(); //add resulting svg file to scene UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); svgItem->resetTransform(); repositionSvgItem(svgItem, width, height, x + transform.m31(), y + transform.m32(), transform); hashSceneItem(element, svgItem); delete generator; return true; } void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTSpan(const QDomElement &parent, QPainter &painter , qreal &curX, qreal &curY, qreal &width, qreal &height, qreal &linespacing, QRectF &lastDrawnTextBoundingRect , qreal &fontSize, QColor &fontColor, QString &fontFamily, QString &fontStretch, bool &italic , int &fontWeight, int &textAlign, QTransform &fontTransform) { QDomNode curNode = parent.firstChild(); while (!curNode.isNull()) { if (curNode.toElement().tagName() == tTspan) { QDomElement curTSpan = curNode.toElement(); parseTextAttributes(curTSpan, fontSize, fontColor, fontFamily, fontStretch, italic , fontWeight, textAlign, fontTransform); painter.setFont(QFont(fontFamily, fontSize, fontWeight, italic)); painter.setPen(fontColor); linespacing = QFontMetricsF(painter.font()).leading(); parseTSpan(curTSpan, painter , curX, curY, width, height, linespacing, lastDrawnTextBoundingRect , fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); } else if (curNode.nodeType() == QDomNode::CharacterDataNode || curNode.nodeType() == QDomNode::CDATASectionNode || curNode.nodeType() == QDomNode::TextNode) { QDomCharacterData textData = curNode.toCharacterData(); QString text = textData.data().trimmed(); // width = painter.fontMetrics().width(text); //get bounding rect to obtain desired text height lastDrawnTextBoundingRect = painter.boundingRect(QRectF(curX, curY, width, height - curY), textAlign|Qt::TextWordWrap, text); painter.drawText(curX, curY, width, lastDrawnTextBoundingRect.height(), textAlign|Qt::TextWordWrap, text); curX += lastDrawnTextBoundingRect.x() + lastDrawnTextBoundingRect.width(); } else if (curNode.nodeType() == QDomNode::ElementNode && curNode.toElement().tagName() == tBreak) { curY += lastDrawnTextBoundingRect.height() + linespacing; curX = 0.0; lastDrawnTextBoundingRect = QRectF(0,0,0,0); } curNode = curNode.nextSibling(); } } void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTSpan(const QDomElement &element, QTextCursor &cursor , QTextBlockFormat &blockFormat, QTextCharFormat &charFormat) { QDomNode curNode = element.firstChild(); while (!curNode.isNull()) { if (curNode.toElement().tagName() == tTspan) { QDomElement curTspan = curNode.toElement(); readTextBlockAttr(curTspan, blockFormat); readTextCharAttr(curTspan, charFormat); cursor.setBlockFormat(blockFormat); cursor.setCharFormat(charFormat); parseTSpan(curTspan, cursor, blockFormat, charFormat); } else if (curNode.nodeType() == QDomNode::CharacterDataNode || curNode.nodeType() == QDomNode::CDATASectionNode || curNode.nodeType() == QDomNode::TextNode) { QDomCharacterData textData = curNode.toCharacterData(); QString text = textData.data().trimmed(); cursor.insertText(text, charFormat); } else if (curNode.nodeType() == QDomNode::ElementNode && curNode.toElement().tagName() == tBreak) { cursor.insertBlock(); } curNode = curNode.nextSibling(); } } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgTextarea(const QDomElement &element) { qreal x = element.attribute(aX).toDouble(); qreal y = element.attribute(aY).toDouble(); qreal width = element.attribute(aWidth).toDouble(); qreal height = element.attribute(aHeight).toDouble(); QTextBlockFormat blockFormat; blockFormat.setAlignment(Qt::AlignLeft); QTextCharFormat textFormat; textFormat.setFontPointSize(12 * 72 / QApplication::desktop()->physicalDpiY()); textFormat.setForeground(qApp->palette().foreground().color()); textFormat.setFontFamily("Arial"); textFormat.setFontItalic(false); textFormat.setFontWeight(QFont::Normal); readTextBlockAttr(element, blockFormat); readTextCharAttr(element, textFormat); QTextDocument doc; doc.setPlainText(""); QTextCursor tCursor(&doc); tCursor.setBlockFormat(blockFormat); tCursor.setCharFormat(textFormat); parseTSpan(element, tCursor, blockFormat, textFormat); UBGraphicsTextItem *svgItem = mCurrentScene->addTextHtml(doc.toHtml()); svgItem->resize(width, height); QTransform transform; QString textTransform = element.attribute(aTransform); svgItem->resetTransform(); if (!textTransform.isNull()) { transform = transformFromString(textTransform, svgItem); } //by default all the textAreas are not editable UBGraphicsTextItemDelegate *curDelegate = dynamic_cast(svgItem->Delegate()); if (curDelegate) { curDelegate->setEditable(false); } repositionSvgItem(svgItem, width, height, x + transform.m31(), y + transform.m32(), transform); hashSceneItem(element, svgItem); return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgImage(const QDomElement &element) { qreal x = element.attribute(aX).toDouble(); qreal y = element.attribute(aY).toDouble(); qreal width = element.attribute(aWidth).toDouble(); qreal height = element.attribute(aHeight).toDouble(); QString itemRefPath = element.attribute(aHref); QPixmap pix; if (!itemRefPath.isNull()) { QString imagePath = pwdContent + "/" + itemRefPath; if (!QFile::exists(imagePath)) { qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted"; return false; } else { // qDebug() << "size of file" << itemRefPath << QFileInfo(itemRefPath).size(); } pix.load(imagePath); if (pix.isNull()) { qDebug() << "can't create pixmap for file" << pwdContent + "/" + itemRefPath << "maybe format does not supported"; } } UBGraphicsPixmapItem *pixItem = mCurrentScene->addPixmap(pix); QTransform transform; QString textTransform = element.attribute(aTransform); pixItem->resetTransform(); if (!textTransform.isNull()) { transform = transformFromString(textTransform, pixItem); } repositionSvgItem(pixItem, width, height, x + transform.m31(), y + transform.m32(), transform); hashSceneItem(element, pixItem); return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgFlash(const QDomElement &element) { QString itemRefPath = element.attribute(aHref); qreal x = element.attribute(aX).toDouble(); qreal y = element.attribute(aY).toDouble(); qreal width = element.attribute(aWidth).toDouble(); qreal height = element.attribute(aHeight).toDouble(); QUrl urlPath; QString flashPath; if (!itemRefPath.isNull()) { flashPath = pwdContent + "/" + itemRefPath; if (!QFile::exists(flashPath)) { qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted"; return false; } urlPath = QUrl::fromLocalFile(flashPath); } QDir tmpFlashDir(mTmpFlashDir); if (!tmpFlashDir.exists()) { qDebug() << "Can't create temporary directory to put flash"; return false; } QString flashUrl = UBW3CWidget::createNPAPIWrapperInDir(flashPath, tmpFlashDir, "application/x-shockwave-flash" ,QSize(mCurrentSceneRect.width(), mCurrentSceneRect.height())); UBGraphicsWidgetItem *flashItem = mCurrentScene->addW3CWidget(QUrl::fromLocalFile(flashUrl)); flashItem->setSourceUrl(urlPath); QTransform transform; QString textTransform = element.attribute(aTransform); flashItem->resetTransform(); if (!textTransform.isNull()) { transform = transformFromString(textTransform, flashItem); } repositionSvgItem(flashItem, width, height, x + transform.m31(), y + transform.m32(), transform); hashSceneItem(element, flashItem); return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgAudio(const QDomElement &element) { QDomElement parentOfAudio = element.firstChild().toElement(); qreal x = parentOfAudio.attribute(aX).toDouble(); qreal y = parentOfAudio.attribute(aY).toDouble(); QString itemRefPath = element.attribute(aHref); QUrl concreteUrl; if (!itemRefPath.isNull()) { QString audioPath = pwdContent + "/" + itemRefPath; if (!QFile::exists(audioPath)) { qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted"; return false; } concreteUrl = QUrl::fromLocalFile(audioPath); } QUuid uuid = QUuid::createUuid(); #ifdef Q_WS_X11 concreteUrl = QUrl::fromLocalFile(mCurrentScene->document()->persistencePath() + "/" + UBPersistenceManager::persistenceManager() ->addAudioFileToDocument(mCurrentScene->document(), concreteUrl.toLocalFile(), uuid)); #else concreteUrl = QUrl::fromLocalFile(UBPersistenceManager::persistenceManager() ->addAudioFileToDocument(mCurrentScene->document(), concreteUrl.toLocalFile(), uuid)); #endif UBGraphicsAudioItem *audioItem = mCurrentScene->addAudio(concreteUrl, false); QTransform transform; QString textTransform = parentOfAudio.attribute(aTransform); audioItem->resetTransform(); if (!textTransform.isNull()) { transform = transformFromString(textTransform, audioItem); } repositionSvgItem(audioItem, audioItem->boundingRect().width(), audioItem->boundingRect().height(), x + transform.m31(), y + transform.m32(), transform); hashSceneItem(element, audioItem); return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgVideo(const QDomElement &element) { QString itemRefPath = element.attribute(aHref); if (itemRefPath.startsWith(tFlash + "/") && itemRefPath.endsWith(".swf")) { if (parseSvgFlash(element)) return true; else return false; } qreal x = element.attribute(aX).toDouble(); qreal y = element.attribute(aY).toDouble(); QUrl concreteUrl; if (!itemRefPath.isNull()) { QString videoPath = pwdContent + "/" + itemRefPath; if (!QFile::exists(videoPath)) { qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted"; return false; } concreteUrl = QUrl::fromLocalFile(videoPath); } QUuid uuid = QUuid::createUuid(); #ifdef Q_WS_X11 concreteUrl = QUrl::fromLocalFile(mCurrentScene->document()->persistencePath() + "/" + UBPersistenceManager::persistenceManager() ->addVideoFileToDocument(mCurrentScene->document(), concreteUrl.toLocalFile(), uuid)); #else concreteUrl = QUrl::fromLocalFile(UBPersistenceManager::persistenceManager() ->addVideoFileToDocument(mCurrentScene->document(), concreteUrl.toLocalFile(), uuid)); #endif UBGraphicsVideoItem *videoItem = mCurrentScene->addVideo(concreteUrl, false); QTransform transform; QString textTransform = element.attribute(aTransform); videoItem->resetTransform(); if (!textTransform.isNull()) { transform = transformFromString(textTransform, videoItem); } repositionSvgItem(videoItem, videoItem->boundingRect().width(), videoItem->boundingRect().height(), x + transform.m31(), y + transform.m32(), transform); hashSceneItem(element, videoItem); return true; } void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgSectionAttr(const QDomElement &svgSection) { getViewBoxDimenstions(svgSection.attribute(aViewbox)); mSize = QSize(svgSection.attribute(aWidth).toInt(), svgSection.attribute(aHeight).toInt()); } void UBCFFSubsetAdaptor::UBCFFSubsetReader::hashSceneItem(const QDomElement &element, UBGraphicsItem *item) { // adding element pointer to hash to refer if needed QString key = element.attribute(aId); if (!key.isNull()) { persistedItems.insert(key, item); } } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgElement(const QDomElement &parent) { QString tagName = parent.tagName(); if (parent.namespaceURI() != svgNS) { qDebug() << "Incorrect namespace, error at content file, line number" << parent.lineNumber(); return false; } if (tagName == tG && !parseGSection(parent)) return false; else if (tagName == tSwitch && !parseSvgSwitchSection(parent)) return false; else if (tagName == tRect && !parseSvgRect(parent)) return false; else if (tagName == tEllipse && !parseSvgEllipse(parent)) return false; else if (tagName == tPolygon && !parseSvgPolygon(parent)) return false; else if (tagName == tPolyline && !parseSvgPolyline(parent)) return false; else if (tagName == tText && !parseSvgText(parent)) return false; else if (tagName == tTextarea && !parseSvgTextarea(parent)) return false; else if (tagName == tImage && !parseSvgImage(parent)) return false; else if (tagName == tFlash && !parseSvgFlash(parent)) return false; else if (tagName == tAudio && !parseSvgAudio(parent)) return false; else if (tagName == tVideo && !parseSvgVideo(parent)) return false; return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPage(const QDomElement &parent) { createNewScene(); QDomElement currentSvgElement = parent.firstChildElement(); while (!currentSvgElement.isNull()) { if (!parseSvgElement(currentSvgElement)) return false; currentSvgElement = currentSvgElement.nextSiblingElement(); } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPageset(const QDomElement &parent) { QDomElement currentPage = parent.firstChildElement(tPage); while (!currentPage.isNull()) { if (!parseSvgPage(currentPage)) return false; currentPage = currentPage.nextSiblingElement(tPage); } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbMeta(const QDomElement &element) { if (element.namespaceURI() != iwbNS) { qDebug() << "incorrect meta namespace, incorrect document"; return false; } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvg(const QDomElement &svgSection) { if (svgSection.namespaceURI() != svgNS) { qDebug() << "incorrect svg namespace, incorrect document"; return false; } parseSvgSectionAttr(svgSection); QDomElement currentSvg = svgSection.firstChildElement(); if (currentSvg.tagName() != tPageset) { parseSvgPage(svgSection); } else if (currentSvg.tagName() == tPageset){ parseSvgPageset(currentSvg); } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbGroup(QDomElement &parent) { //TODO. Create groups from elements parsed by parseIwbElement() function if (parent.namespaceURI() != iwbNS) { qDebug() << "incorrect iwb group namespace, incorrect document"; return false; } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::strToBool(QString str) { return str == "true"; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbElement(QDomElement &element) { if (element.namespaceURI() != iwbNS) { qDebug() << "incorrect iwb element namespace, incorrect document"; return false; } bool locked = false; bool isEditableItem = false; bool isEditable = false; //Text items to convert to UBGraphicsTextItem only QString IDRef = element.attribute(aRef); if (!IDRef.isNull()) { element.hasAttribute(aBackground) ? strToBool(element.attribute(aBackground)) : false; locked = element.hasAttribute(aBackground) ? strToBool(element.attribute(aBackground)) : false; isEditableItem = element.hasAttribute(aEditable); if (isEditableItem) isEditable = strToBool(element.attribute(aEditable)); UBGraphicsItem *referedItem(0); QHash::iterator iReferedItem; iReferedItem = persistedItems.find(IDRef); if (iReferedItem != persistedItems.end()) { referedItem = *iReferedItem; referedItem->Delegate()->lock(locked); } if (isEditableItem) { UBGraphicsTextItemDelegate *textDelegate = dynamic_cast(referedItem->Delegate()); if (textDelegate) { textDelegate->setEditable(isEditable); } } } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseDoc() { QDomElement currentTopElement = mDOMdoc.documentElement().firstChildElement(); while (!currentTopElement.isNull()) { QString tagName = currentTopElement.tagName(); if (tagName == tMeta && !parseIwbMeta(currentTopElement)) return false; else if (tagName == tSvg && !parseSvg(currentTopElement)) return false; else if (tagName == tGroup && !parseIwbGroup(currentTopElement)) return false; else if (tagName == tElement && !parseIwbElement(currentTopElement)) return false; currentTopElement = currentTopElement.nextSiblingElement(); } if (!persistScenes()) return false; return true; } void UBCFFSubsetAdaptor::UBCFFSubsetReader::repositionSvgItem(QGraphicsItem *item, qreal width, qreal height, qreal x, qreal y, QTransform &transform) { //First using viebox coordinates, then translate them to scene coordinates QRectF itemBounds = item->boundingRect(); qreal xScale = width / itemBounds.width(); qreal yScale = height / itemBounds.height(); qreal fullScaleX = mVBTransFactor * xScale; qreal fullScaleY = mVBTransFactor * yScale; QPointF oldVector((x - transform.dx()), (y - transform.dy())); QTransform rTransform; QPointF newVector = rTransform.map(oldVector); QRectF sr = mCurrentScene->sceneRect(); QRectF sr1 = mCurrentSceneRect; QRectF sr2 = mCurrentScene->normalizedSceneRect(); QTransform tr = item->sceneTransform(); item->setTransform(rTransform.scale(fullScaleX, fullScaleY), true); tr = item->sceneTransform(); QPoint pos ((int)((x + mShiftVector.x() + (newVector - oldVector).x()) * mVBTransFactor), (int)((y +mShiftVector.y() + (newVector - oldVector).y()) * mVBTransFactor)); item->setPos(pos); } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::createNewScene() { mCurrentScene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, mProxy->pageCount()); mCurrentScene->setURStackEnable(false); mCurrentScene->setSceneRect(mViewBox); if ((mCurrentScene->sceneRect().topLeft().x() >= 0) || (mCurrentScene->sceneRect().topLeft().y() >= 0)) { mShiftVector = -mViewBox.center(); } mCurrentSceneRect = mViewBox; mVBTransFactor = qMin(mCurrentScene->normalizedSceneRect().width() / mViewPort.width(), mCurrentScene->normalizedSceneRect().height() / mViewPort.height()); return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::persistCurrentScene() { if (mCurrentScene != 0 && mCurrentScene->isModified()) { UBThumbnailAdaptor::persistScene(mProxy->persistencePath(), mCurrentScene, mProxy->pageCount() - 1); UBSvgSubsetAdaptor::persistScene(mProxy, mCurrentScene, mProxy->pageCount() - 1); mCurrentScene->setModified(false); mCurrentScene = 0; } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::persistScenes() { if (!mProxy->pageCount()) { qDebug() << "No pages created"; return false; } for (int i = 0; i < mProxy->pageCount(); i++) { mCurrentScene = UBPersistenceManager::persistenceManager()->getDocumentScene(mProxy, i); if (!mCurrentScene) { qDebug() << "can't allocate scene, loading failed"; return false; } UBSvgSubsetAdaptor::persistScene(mProxy, mCurrentScene, i); UBGraphicsScene *tmpScene = UBSvgSubsetAdaptor::loadScene(mProxy, i); tmpScene->setModified(true); UBThumbnailAdaptor::persistScene(mProxy->persistencePath(), tmpScene, i); delete tmpScene; mCurrentScene->setModified(false); } return true; } QColor UBCFFSubsetAdaptor::UBCFFSubsetReader::colorFromString(const QString& clrString) { //init regexp with pattern //pattern corresponds to strings like 'rgb(1,2,3) or rgb(10%,20%,30%)' QRegExp regexp("rgb\\(([0-9]+%{0,1}),([0-9]+%{0,1}),([0-9]+%{0,1})\\)"); if (regexp.exactMatch(clrString)) { if (regexp.capturedTexts().count() == 4 && regexp.capturedTexts().at(0).length() == clrString.length()) { int r = regexp.capturedTexts().at(1).toInt(); if (regexp.capturedTexts().at(1).indexOf("%") != -1) r = r * 255 / 100; int g = regexp.capturedTexts().at(2).toInt(); if (regexp.capturedTexts().at(2).indexOf("%") != -1) g = g * 255 / 100; int b = regexp.capturedTexts().at(3).toInt(); if (regexp.capturedTexts().at(3).indexOf("%") != -1) b = b * 255 / 100; return QColor(r, g, b); } else return QColor(); } else return QColor(clrString); } QTransform UBCFFSubsetAdaptor::UBCFFSubsetReader::transformFromString(const QString trString, QGraphicsItem *item) { qreal dxr = 0.0; qreal dyr = 0.0; qreal dx = 0.0; qreal dy = 0.0; qreal angle = 0.0; QTransform tr; foreach(QString trStr, trString.split(" ", QString::SkipEmptyParts)) { //check pattern for strings like 'rotate(10)' QRegExp regexp("rotate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *\\)"); if (regexp.exactMatch(trStr)) { angle = regexp.capturedTexts().at(1).toDouble(); if (item) { item->setTransformOriginPoint(QPointF(0, 0)); item->rotate(angle); } continue; }; //check pattern for strings like 'rotate(10,20,20)' or 'rotate(10.1,10.2,34.2)' regexp.setPattern("rotate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *\\)"); if (regexp.exactMatch(trStr)) { angle = regexp.capturedTexts().at(1).toDouble(); dxr = regexp.capturedTexts().at(2).toDouble(); dyr = regexp.capturedTexts().at(3).toDouble(); if (item) { item->setTransformOriginPoint(QPointF(dxr, dyr)-item->pos()); item->rotate(angle); } continue; } //check pattern for strings like 'translate(11.0, 12.34)' regexp.setPattern("translate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *,*([-+]{0,1}[0-9]*\\.{0,1}[0-9]*)*\\)"); if (regexp.exactMatch(trStr)) { dx = regexp.capturedTexts().at(1).toDouble(); dy = regexp.capturedTexts().at(2).toDouble(); tr.translate(dx,dy); continue; } } return tr; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getViewBoxDimenstions(const QString& viewBox) { QStringList capturedTexts = viewBox.split(" ", QString::SkipEmptyParts); if (capturedTexts.count()) { if (4 == capturedTexts.count()) { mViewBox = QRectF(capturedTexts.at(0).toDouble(), capturedTexts.at(1).toDouble(), capturedTexts.at(2).toDouble(), capturedTexts.at(3).toDouble()); mViewPort = mViewBox; mViewPort.translate(- mViewPort.center()); mViewBoxCenter.setX(mViewBox.width() / 2); mViewBoxCenter.setY(mViewBox.height() / 2); return true; } } mViewBox = QRectF(0, 0, 1000, 1000); mViewBoxCenter = QPointF(500, 500); return false; } QSvgGenerator* UBCFFSubsetAdaptor::UBCFFSubsetReader::createSvgGenerator(qreal width, qreal height) { QSvgGenerator* generator = new QSvgGenerator(); // qWarning() << QString("Making generator with file %1, size (%2, %3) and viewbox (%4 %5 %6 %7)").arg(mTempFilePath) // .arg(width).arg(height).arg(0.0).arg(0.0).arg(width).arg(width); generator->setResolution(QApplication::desktop()->physicalDpiY()); generator->setFileName(mTempFilePath); generator->setSize(QSize(width, height)); generator->setViewBox(QRectF(0, 0, width, height)); return generator; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getTempFileName() { int tmpNumber = 0; QDir rootDir; while (true) { mTempFilePath = QString("%1/sanksvg%2.%3") .arg(rootDir.tempPath()) .arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm")) .arg(tmpNumber); if (!QFile::exists(mTempFilePath)) return true; tmpNumber++; if (tmpNumber == 100000) { qWarning() << "Import failed. Failed to create temporary file for svg objects"; return false; } } } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::createTempFlashPath() { int tmpNumber = 0; QDir systemTmp = QDir::temp(); while (true) { QString dirName = QString("SankTmpFlash%1.%2") .arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm")) .arg(tmpNumber++); if (!systemTmp.exists(dirName)) { if (systemTmp.mkdir(dirName)) { mTmpFlashDir = QDir(systemTmp.absolutePath() + "/" + dirName); return true; } else { qDebug() << "Can't create temporary dir maybe due to permissions"; return false; } } else if (tmpNumber == 1000) { qWarning() << "Import failed. Failed to create temporary file for svg objects"; return false; } } return true; } UBCFFSubsetAdaptor::UBCFFSubsetReader::~UBCFFSubsetReader() { // QList pages; // for (int i = 0; i < mProxy->pageCount(); i++) { // pages << i; // } // UBPersistenceManager::persistenceManager()->deleteDocumentScenes(mProxy, pages); }