diff --git a/src/adaptors/UBCFFSubsetAdaptor.cpp b/src/adaptors/UBCFFSubsetAdaptor.cpp index b19d6529..572486d7 100644 --- a/src/adaptors/UBCFFSubsetAdaptor.cpp +++ b/src/adaptors/UBCFFSubsetAdaptor.cpp @@ -25,6 +25,7 @@ #include "domain/UBGraphicsStroke.h" #include "domain/UBGraphicsTextItem.h" #include "domain/UBGraphicsSvgItem.h" +#include "domain/UBGraphicsPixmapItem.h" #include "UBCFFSubsetAdaptor.h" #include "UBMetadataDcSubsetAdaptor.h" @@ -55,6 +56,7 @@ static QString tText = "text"; static QString tTextarea = "textarea"; static QString tTspan = "tspan"; static QString tBreak = "tbreak"; +static QString tImage = "image"; //attribute names definition static QString aFill = "fill"; @@ -81,56 +83,57 @@ 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"; + +//attributes part names +static QString apRotate = "rotate"; +static QString apTranslate = "translate"; UBCFFSubsetAdaptor::UBCFFSubsetAdaptor() { + } void UBCFFSubsetAdaptor::UBCFFSubsetReader::hashSiblingIwbElements(QDomElement *parent, QDomElement *topGroup) { QDomElement curExt = parent->firstChildElement(tElement); while (!curExt.isNull()) { - QDomElement n = curExt; if (curExt.namespaceURI() != iwbNS) continue; - QHash::iterator iSvgElement = extProperties.find(curExt.attribute("ref")); - if (iSvgElement != extProperties.end()) { + QHash::iterator iSvgElement = iwbExtProperties.find(curExt.attribute(aRef)); + if (iSvgElement != iwbExtProperties.end()) { IwbExt &svgElement = *iSvgElement; svgElement.extAttr.push_back(curExt); if (topGroup) - qDebug() << "made"; + svgElement.group = *topGroup; } curExt = curExt.nextSiblingElement(tElement); } } -void UBCFFSubsetAdaptor::UBCFFSubsetReader::addExtentionsToHash(QDomElement *parent) +void UBCFFSubsetAdaptor::UBCFFSubsetReader::addExtentionsToHash(QDomElement *parent, QDomElement *topGroup) { - //add top level elements + if(*parent == mDOMdoc.documentElement()) { + hashSiblingIwbElements(parent); + } else + hashSiblingIwbElements(parent, topGroup); + + //add iwb groups if needed QDomElement curGroup = parent->firstChildElement(tGroup); - QDomElement topGroup; while (!curGroup.isNull()) { if (curGroup.namespaceURI() != iwbNS) continue; - -// if (parent == mDOMdoc.documentElement()) -// topGroup = curGroup; -// QHash::iterator iSvgElement = extProperties.find(curExt.attribute("ref")); -// if (iSvgElement != extProperties.end()) { -// IwbExt &svgElement = *iSvgElement; -// svgElement.group = curGroup; -// qDebug() << "made"; -// } - hashSiblingIwbElements(&curGroup, &topGroup); + if(*parent == mDOMdoc.documentElement()) { + topGroup = &curGroup; + } if (curGroup.hasChildNodes()) { - addExtentionsToHash(&curGroup); + addExtentionsToHash(&curGroup, topGroup); } - curGroup = curGroup.nextSiblingElement(tGroup); } - //add groups } void UBCFFSubsetAdaptor::UBCFFSubsetReader::hashSvg(QDomNode *parent, QString prefix) @@ -140,7 +143,7 @@ void UBCFFSubsetAdaptor::UBCFFSubsetReader::hashSvg(QDomNode *parent, QString pr QDomElement e = n.toElement(); QString id = e.attribute(aId); if(!id.isNull()) { - extProperties.insert(id, IwbExt(e)); + iwbExtProperties.insert(id, IwbExt(e)); qDebug() << prefix + e.prefix() + ":" + e.tagName(); } if (n.hasChildNodes()) { @@ -152,36 +155,51 @@ void UBCFFSubsetAdaptor::UBCFFSubsetReader::hashSvg(QDomNode *parent, QString pr bool UBCFFSubsetAdaptor::UBCFFSubsetReader::hashElements() { - QDomElement svgSection = mDOMdoc.elementsByTagNameNS(svgNS, tSvg).at(0).toElement(); - Q_ASSERT(!svgSection.isNull()); + bool result = true; + QDomElement svgSection = mDOMdoc.elementsByTagNameNS(svgNS, tSvg).at(0).toElement(); + if (svgSection.isNull()) { + qDebug("\"svg:svg\" section not found maybe invalid document"); + result = false; + } hashSvg(&svgSection); QDomElement parElement = mDOMdoc.documentElement(); - Q_ASSERT(!parElement.isNull()); - - addExtentionsToHash(&parElement); - -// qDebug() << "ext properties count " << extProperties.count(); -// qDebug() << extProperties.value("link1").element.toElement().tagName(); - foreach (IwbExt cur, extProperties) { - qDebug() << (cur.extAttr.count() ? cur.extAttr.first().toElement().tagName() : "count < 0") ; + if (parElement.isNull()) { + qDebug("invalid pass paramentr maybe invalid document"); + result = false; } -// for (int i = 0; i < extProperties.count(); i++) { + // Adding iwb extentions to hash table crossing elements and groups using recursive descent + addExtentionsToHash(&parElement, 0); + +// int i = 0; +// foreach (IwbExt cur, iwbExtProperties) { +// QString elem = cur.element.toElement().attribute(aId); +// QString tagName = cur.element.toElement().tagName(); +// QString gr = !cur.group.isNull() +// ? i++, " is group\n-------------\n" + QString::number(i) +// + cur.group.toElement().tagName() +// + (cur.group.toElement().hasChildNodes() ? "true" : "false") +// : ""; +//// QString attr = !cur.extAttr.isEmpty() ? cur.extAttr.first().toElement().attribute(aRef) : ""; +//// if (cur.group) { +//// *(cur.group); +//// } +// qDebug() << "element" + elem + "tag" + tagName + gr; +// if (!gr.isNull()) { + +// mDOMdoc.documentElement().removeChild(cur.group); +// } +// } +// QDomNode n = mDOMdoc.documentElement().firstChild(); +// while (!n.isNull()) { +// qDebug() << "new dom tags"<< n.toElement().tagName(); +// n = n.nextSibling(); // } - // QDomNode n = docElem.firstChild(); -// int i = 0; -// while(!n.isNull()) { -// QDomElement e = n.toElement(); // try to convert the node to an element. -// if(!e.isNull()) { -// qDebug() << e.prefix() << ":" << e.tagName() ; // the node really is an element. -// i++; -// } -// n = n.nextSibling(); -// } - return false; + + return result; } bool UBCFFSubsetAdaptor::ConvertCFFFileToUbz(QString &cffSourceFile, UBDocumentProxy* pDocument) @@ -198,25 +216,14 @@ bool UBCFFSubsetAdaptor::ConvertCFFFileToUbz(QString &cffSourceFile, UBDocumentP return false; } -// QTextStream out(&file); -// out.setCodec("UTF-8"); -// QString dta = out.readAll(); - QByteArray data = file.readAll(); - if (data.length() == 0) - { - qWarning() << "Either content file " << cffSourceFile << " is empty or failed to read from file"; - file.close(); - return false; - } - - UBCFFSubsetReader cffReader(pDocument, data); + UBCFFSubsetReader cffReader(pDocument, &file); bool result = cffReader.parse(); file.close(); return result; } -UBCFFSubsetAdaptor::UBCFFSubsetReader::UBCFFSubsetReader(UBDocumentProxy *proxy, QByteArray &content): +UBCFFSubsetAdaptor::UBCFFSubsetReader::UBCFFSubsetReader(UBDocumentProxy *proxy, QFile *content): mReader(content), mProxy(proxy), currentState(NONE) { int errorLine, errorColumn; @@ -226,6 +233,7 @@ UBCFFSubsetAdaptor::UBCFFSubsetReader::UBCFFSubsetReader(UBDocumentProxy *proxy, << "column" << errorColumn << ":" << errorStr; } else { qDebug() << "well parsed to DOM"; + pwdContent = QFileInfo(content->fileName()).dir().absolutePath(); } // QFile tfile("/home/ilia/Documents/tmp/2/out.xml"); // tfile.open(QIODevice::ReadWr ite | QIODevice::Text); @@ -272,8 +280,633 @@ void UBCFFSubsetAdaptor::UBCFFSubsetReader::PushState(int state) currentState = state; } +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.isNull() ? textStrokeWidth.toInt() : 0; + + //init svg generator with temp file + QSvgGenerator *generator = createSvgGenerator(width + 10, height + 10); + + //init painter to paint to svg + QPainter painter; + + painter.begin(generator); + + //fill rect + if (fillColor.isValid()) { + painter.setBrush(QBrush(fillColor)); + painter.fillRect(5, 5, width, height, fillColor); + } + QPen pen; + if (strokeColor.isValid()) { + pen.setColor(strokeColor); + } + if (strokeWidth) + pen.setWidth(strokeWidth); + painter.setPen(pen); + painter.drawRect(5, 5, width, height); + + painter.end(); + + UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); + QTransform transform; + QString textTransform = element.attribute(aTransform); + bool hastransform = false; + if (!textTransform.isNull()) { + transform = transformFromString(textTransform); + hastransform = true; + } + repositionSvgItem(svgItem, width + 10, height + 10, x1 - 5, y1 - 5, hastransform, transform); + 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 + 10, ry * 2 + 10); + + //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(5, 5, rx * 2, ry * 2); + + painter.end(); + + UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); + QTransform transform; + QString textTransform = element.attribute(aTransform); + bool hastransform = false; + if (!textTransform.isNull()) { + transform = transformFromString(textTransform); + hastransform = true; + } + repositionSvgItem(svgItem, rx * 2 + 10, ry * 2 + 10, cx - rx - 5, cy - ry -5, hastransform, transform); + 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 { + 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.toInt() > 0 ? strokeWidthText.toInt() : 0; + + 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); + bool hastransform = false; + if (!textTransform.isNull()) { + transform = transformFromString(textTransform); + hastransform = true; + } + repositionSvgItem(svgItem, width + 10, height + 10, x1 - 5, y1 - 5, hastransform, transform); + 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 { + 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.toInt() > 0 ? strokeWidthText.toInt() : 0; + + 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); + bool hastransform = false; + if (!textTransform.isNull()) { + transform = transformFromString(textTransform); + hastransform = true; + } + repositionSvgItem(svgItem, width + 10, height + 10, x1 - 5, y1 - 5, hastransform, transform); + 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)); +} + +bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgText(const QDomElement &element) +{ +// qreal x = element.attribute(aX).toDouble(); +// qreal y = element.attribute(aY).toDouble();; + +// qreal width = 0; +// qreal height = 0; + +// QList textRects; +// QList textFonts; +// QList textLines; +// QList textAligns; +// QList textColors; + +// qWarning() << QString().sprintf("Text coordinates : %f,%f. Text size %f,%f", x, y, width, height); + +// qreal fontSize = 12.0; +// QFont textFont; +// QColor fontColor; +// 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); +// textFont = QFont(fontFamily, fontSize, fontWeight, italic); + +// QFontMetricsF metrics = QFontMetricsF(textFont); +// qreal curHeight = metrics.height(); + +// qreal curY = 0.0; +// qreal curX = 0.0; + +// qreal linespacing = QFontMetrics(textFont).leading(); + +// //remember if text area has transform +// QTransform transform; +//// bool hasTransform = getCurElementTransorm(transform); + +// QRectF lastDrawnTextBoundingRect; + +// QStack fontStack; +// QStack colorStack; +// QStack alignStack; + +// // first extimate desired text area size +// // to do that, parse text area tags +// while(true) +// { +// mReader.readNext(); +// QStringRef elementName = mReader.name(); +// if (mReader.isEndDocument()) +// break; +// if (mReader.isEndElement()) +// { +// if (elementName == tBreak) +// { +// //when tbreak appers, move down by the drawn rect height +// //TODO: line spacing is not calculated yet, probably additional code is required +// curY += lastDrawnTextBoundingRect.height() + linespacing; +// curX = 0.0; +// height += lastDrawnTextBoundingRect.height(); +// lastDrawnTextBoundingRect = QRectF(0,0,0,0); +// continue; +// } +// if (elementName == tTspan) +// { +// textFont = fontStack.pop(); +// fontColor = colorStack.pop(); +// textAlign = alignStack.pop(); +// continue; +// } +// } +// if (mReader.isEndElement() && elementName == tText) +// break; +// if (mReader.isStartElement() && elementName == tTspan) +// { +// fontStack.push(textFont); +// colorStack.push(fontColor); +// alignStack.push(textAlign); + +// parseTextAttributes(fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); +// textFont = QFont(fontFamily, fontSize, fontWeight, italic); +// metrics = QFontMetricsF(textFont); +// curHeight = metrics.height(); +// linespacing = QFontMetricsF(textFont).leading(); +// continue; +// } +// if (mReader.isCharacters() || mReader.isCDATA()) +// { +// QString text = mReader.text().toString(); + +// //skip empty text +// if (text.trimmed().length() == 0) +// continue; +// //get bounding rect to obtain desired text height +// lastDrawnTextBoundingRect = metrics.boundingRect(QRectF(), textAlign, text); +// QString log = QString().sprintf(" at rect %f, %f, %f, %f. Bounding rect is %f, %f, %f, %f", 0.0, curY, width, height - curY, lastDrawnTextBoundingRect.x(), lastDrawnTextBoundingRect.y(), lastDrawnTextBoundingRect.width(), lastDrawnTextBoundingRect.height()); +// qWarning() << "Text " << text << log; +// textFonts.append(textFont); +// textRects.append(QRectF(curX, curY, lastDrawnTextBoundingRect.width(), lastDrawnTextBoundingRect.height())); +// textLines.append(text); +// textAligns.append(textAlign); +// textColors.append(fontColor); +// curX += lastDrawnTextBoundingRect.width(); +// if (width < curX) +// width = curX; +// if (height == 0) +// height = curHeight; + +// continue; +// } +// } + +// QSvgGenerator *generator = createSvgGenerator(width, height); +// QPainter painter; +// painter.begin(generator); + +// if (textRects.count() != 0) +// { +// QListIterator textRectsIter(textRects); +// QListIterator textFontsIter(textFonts); +// QListIterator textLinesIter(textLines); +// QListIterator textAlignsIter(textAligns); +// QListIterator textColorsIter(textColors); + +// while (textRectsIter.hasNext()) +// { +// QRectF rt = textRectsIter.next(); +// QFont font = textFontsIter.next(); +// QString line = textLinesIter.next(); +// int align = textAlignsIter.next(); +// QColor color = textColorsIter.next(); +// painter.setFont(font); +// painter.setPen(color); +// painter.drawText(rt.x(), rt.y(), rt.width(), rt.height(), align, line); +// } +// } + +// painter.end(); + +// //add resulting svg file to scene +// UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); +// repositionSvgItem(svgItem, width, height, x, y, hasTransform, transform); + +// delete generator; + + return true; + +} +bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgTextarea(const QDomElement &element) +{ + //TODO textarea node + 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; + QString fontFamily = "Arial"; + QString fontStretch = "normal"; + bool italic = false; + int fontWeight = QFont::Normal; + int textAlign = Qt::AlignLeft; + QTransform fontTransform; + parseTextAttributes(fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); + + QSvgGenerator *generator = createSvgGenerator(width, height); + QPainter painter; + painter.begin(generator); + painter.setFont(QFont(fontFamily, fontSize, fontWeight, italic)); + + 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; + bool hasTransform = !fontTransform.isIdentity(); + + QRectF lastDrawnTextBoundingRect; + //parse text area tags + + QDomElement curTextElement = element.firstChildElement(); + while (!curTextElement.isNull()) { + QString tagName = curTextElement.tagName(); + if (tagName == tTspan) { + parseTextAttributes(curTextElement, fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); + painter.setFont(QFont(fontFamily, fontSize, fontWeight, italic)); + painter.setPen(fontColor); + linespacing = QFontMetricsF(painter.font()).leading(); + + QDomNode tspanNode = curTextElement.firstChild(); + while (!tspanNode.isNull()) { + if (tspanNode.nodeType() == QDomNode::CharacterDataNode + || tspanNode.nodeType() == QDomNode::CDATASectionNode) { + QDomCharacterData textData = tspanNode.toCharacterData(); + QString text = textData.data().trimmed(); + //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 (tspanNode.nodeType() == QDomNode::ElementNode) { + //when tbreak appers, move down by the drawn rect height + //TODO: line spacing is not calculated yet, additional code is required + curY += lastDrawnTextBoundingRect.height() + linespacing; + curX = 0.0; + lastDrawnTextBoundingRect = QRectF(0,0,0,0); + } + tspanNode = tspanNode.nextSibling(); + } + } else if (tagName == tBreak) { + + } + curTextElement = curTextElement.nextSiblingElement(); + } + + painter.end(); + + //add resulting svg file to scene + UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); + repositionSvgItem(svgItem, width, height, x, y, hasTransform, transform); + delete generator; + + 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; + } + 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); + bool hastransform = false; + if (!textTransform.isNull()) { + transform = transformFromString(textTransform); + hastransform = true; + } +// repositionSvgItem(svgItem, rx * 2 + 10, ry * 2 + 10, cx - rx - 5, cy - ry -5, hastransform, transform); +repositionPixmapItem(pixItem, width, height, x, y, hastransform, transform); + + return true; +} + +void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgSectionAttr(const QDomElement &svgSection) +{ + getViewBoxDimenstions(svgSection.attribute(aViewbox)); + mSize = QSize(svgSection.attribute(aWidth).toInt(), + svgSection.attribute(aHeight).toInt()); +} + +bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbGroup(QDomNode *group) +{ + QDomElement curGroupPtr = group->firstChildElement(); + + while (!curGroupPtr.isNull()) { + if (curGroupPtr.namespaceURI() != iwbNS) + continue; + if (curGroupPtr.hasChildNodes() && curGroupPtr.toElement().tagName() == tGroup) { + parseIwbGroup(&curGroupPtr); + } else if (curGroupPtr.toElement().tagName() == tElement) { + QHash::iterator iSvgElementExt = iwbExtProperties.find(curGroupPtr.attribute(aRef)); + if (iSvgElementExt != iwbExtProperties.end()) { + IwbExt &svgElementExt = *iSvgElementExt; + QDomNode &svgElement = svgElementExt.element; + svgElement.parentNode().removeChild(svgElement); + } + } + curGroupPtr = curGroupPtr.nextSiblingElement(tElement); + } + return true; +} + +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 == 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; + + 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(); + } + persistCurrentScene(); + 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::parseDoc() { + if (!hashElements()) return false; //hashing all elements having id attribute + + QDomElement svgSection = mDOMdoc.elementsByTagNameNS(svgNS, tSvg).at(0).toElement(); + parseSvgSectionAttr(svgSection); + + QDomElement currentSvg = svgSection.firstChildElement(); + + if (currentSvg.tagName() != tPageset) { + parseSvgPage(svgSection); + } else if (currentSvg.tagName() == tPageset){ + parseSvgPageset(currentSvg); + } + + // while (!mReader.atEnd()) // { // mReader.readNext(); @@ -297,7 +930,6 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseDoc() // } // if (!mReader.error() == QXmlStreamReader::NoError) // UBApplication::showMessage(mReader.errorString()); - if (!hashElements()) return false; return true; } @@ -305,8 +937,8 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseDoc() bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseCurrentElementStart() { QStringRef elName = mReader.name(); - QString log = QString("%1<%2>").arg(mIndent).arg(elName.toString()); - qDebug() << log; +// QString log = QString("%1<%2>").arg(mIndent).arg(elName.toString()); +// qDebug() << log; mIndent += " "; if ( elName == tIwb) { @@ -467,10 +1099,12 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvg() return true; } -void UBCFFSubsetAdaptor::UBCFFSubsetReader::repositionSvgItem(UBGraphicsSvgItem *item, qreal width, qreal height, qreal x, qreal y, bool useTransform, QTransform &transform) +void UBCFFSubsetAdaptor::UBCFFSubsetReader::repositionSvgItem(UBGraphicsSvgItem *item, qreal width, qreal height, + qreal x, qreal y, + bool useTransform, QTransform &transform) { QTransform curTrans = item->transform(); - qWarning() << QString().sprintf("Item current transform = %f 0 0 %f %f %f, position %f, %f", curTrans.m11(), curTrans.m22(), curTrans.dx(), curTrans.dy(), item->x(), item->y()); +// qWarning() << QString().sprintf("Item current transform = %f 0 0 %f %f %f, position %f, %f", curTrans.m11(), curTrans.m22(), curTrans.dx(), curTrans.dy(), item->x(), item->y()); //check if rect is rotated //rotate svg item itself QRectF itemBounds = item->boundingRect(); @@ -495,7 +1129,49 @@ void UBCFFSubsetAdaptor::UBCFFSubsetReader::repositionSvgItem(UBGraphicsSvgItem } QTransform newTrans = item->transform(); - qWarning() << QString("Item new transform = %3 0 0 %4 %1 %2, position %5, %6").arg(newTrans.dx()).arg(newTrans.dy()).arg(newTrans.m11()).arg(newTrans.m22()).arg(item->x()).arg(item->y()); +// qWarning() << QString("Item new transform = %3 0 0 %4 %1 %2, position %5, %6").arg(newTrans.dx()).arg(newTrans.dy()).arg(newTrans.m11()).arg(newTrans.m22()).arg(item->x()).arg(item->y()); + +} +void UBCFFSubsetAdaptor::UBCFFSubsetReader::repositionPixmapItem(UBGraphicsPixmapItem *item, qreal width, qreal height, + qreal x, qreal y, + bool useTransform, QTransform &transform) +{ + //if element is to transform +// if (!transform.isIdentity()) { +// QTransform curTransform = item->transform(); +// qreal hScale = item->boundingRect().width() / width * curTransform.m11(); +// qreal vScale = item->boundingRect().height() / height * curTransform.m22(); +// curTransform = curTransform.translate(x - mViewBoxCenter.x(), y - mViewBoxCenter.y()).scale(hScale, vScale); +// curTransform = curTransform * transform; + +// item->setTransform(curTransform); + + + QTransform curTrans = item->transform(); +// qWarning() << QString().sprintf("Item current transform = %f 0 0 %f %f %f, position %f, %f", curTrans.m11(), curTrans.m22(), curTrans.dx(), curTrans.dy(), item->x(), item->y()); + //check if rect is rotated + //rotate svg item itself + QRectF itemBounds = item->boundingRect(); + //first, svg is mapped to svg item bound + //second, svg item is mapped to scene + //so, get svg to svg item scale and multiple by scene scale + qreal hScale = itemBounds.width() / width * curTrans.m11(); + qreal vScale = itemBounds.height() / height * curTrans.m22(); + + if (useTransform) + { + QPointF oldVector((x - transform.dx()), (y - transform.dy())); + QTransform rTransform(transform.m11(), transform.m12(), transform.m21(), transform.m22(), 0, 0); + QPointF newVector = rTransform.map(oldVector); + rTransform.scale(curTrans.m11(), curTrans.m22()); + item->setTransform(QTransform(rTransform.m11(), rTransform.m12(), rTransform.m21(), rTransform.m22(), 0, 0)); + item->setPos((x - mViewBoxCenter.x() + (newVector - oldVector).x()) * hScale, (y - mViewBoxCenter.y() + (newVector - oldVector).y()) * vScale ); + } + else + { + item->setPos((x - mViewBoxCenter.x()) * hScale, (y - mViewBoxCenter.y()) * vScale); + } + } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseRect() @@ -995,8 +1671,6 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parsePolyline() if (mReader.attributes().hasAttribute(aStrokewidth)) pen.setWidth(mReader.attributes().value(aStrokewidth).toString().toInt()); - pen.setColor(Qt::yellow); - QSvgGenerator *generator = createSvgGenerator(width + pen.width(), height + pen.width()); QPainter painter; @@ -1025,11 +1699,8 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parsePage() qWarning() << "iwb content parse error, unexpected page tag at line" << mReader.lineNumber(); return false; } - createNewScene(); - qWarning() << "Added page number" << mProxy->pageCount(); - return true; } @@ -1115,31 +1786,31 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getCurElementTransorm(QTransform &tr QTransform UBCFFSubsetAdaptor::UBCFFSubsetReader::transformFromString(const QString trString) { + qreal dx = 0.0; + qreal dy = 0.0; + qreal angle = 0.0; + //check pattern for strings like 'rotate(10)' QRegExp regexp("rotate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *\\)"); - if (regexp.exactMatch(trString)) - { - if (regexp.capturedTexts().count() == 2 && regexp.capturedTexts().at(0).length() == trString.length()) - { - qreal angle = regexp.capturedTexts().at(1).toDouble(); - return QTransform().rotate(angle); + if (regexp.exactMatch(trString)) { + angle = regexp.capturedTexts().at(1).toDouble(); + } else { + //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(trString)) { + angle = regexp.capturedTexts().at(1).toDouble(); + dx = regexp.capturedTexts().at(2).toDouble(); + dy = regexp.capturedTexts().at(3).toDouble(); } } - - //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(trString)) - { - if (regexp.capturedTexts().count() == 4 && regexp.capturedTexts().at(0).length() == trString.length()) - { - qreal angle = regexp.capturedTexts().at(1).toDouble(); - qreal dx = regexp.capturedTexts().at(2).toDouble(); - qreal dy = regexp.capturedTexts().at(3).toDouble(); - return QTransform().translate(dx, dy).rotate(angle); - } + //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(trString)) { + dx = regexp.capturedTexts().at(1).toDouble(); + dy = regexp.capturedTexts().at(2).toDouble(); } - return QTransform(); + return QTransform().translate(dx, dy).rotate(angle); } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getViewBoxDimenstions(const QString& viewBox) diff --git a/src/adaptors/UBCFFSubsetAdaptor.h b/src/adaptors/UBCFFSubsetAdaptor.h index bd4a7e71..78d953ee 100644 --- a/src/adaptors/UBCFFSubsetAdaptor.h +++ b/src/adaptors/UBCFFSubsetAdaptor.h @@ -26,7 +26,9 @@ class UBDocumentProxy; class UBGraphicsScene; class QSvgGenerator; class UBGraphicsSvgItem; +class UBGraphicsPixmapItem; class QTransform; +class QPainter; struct IwbExt { IwbExt() {;} @@ -36,7 +38,7 @@ struct IwbExt { QDomNode element; QVector extAttr; QHash textAttributes; - operator bool() const {return group.isNull() || !element.isNull();} + operator bool() const {return !group.isNull() || !element.isNull();} }; class UBCFFSubsetAdaptor @@ -62,10 +64,11 @@ private: }; public: - UBCFFSubsetReader(UBDocumentProxy *proxy, QByteArray &content); + UBCFFSubsetReader(UBDocumentProxy *proxy, QFile *content); QXmlStreamReader mReader; UBDocumentProxy *mProxy; + QString pwdContent; bool parse(); @@ -79,14 +82,38 @@ private: QSize mSize; private: + // to kill QDomDocument mDOMdoc; - QHash extProperties; + QDomNode mCurrentDOMElement; + QHash iwbExtProperties; + bool hashElements(); - void addExtentionsToHash(QDomElement *parent); + void addExtentionsToHash(QDomElement *parent, QDomElement *topGroup); void hashSvg(QDomNode *parent, QString prefix = ""); void hashSiblingIwbElements(QDomElement *parent, QDomElement *topGroup = 0); + inline void parseSvgSectionAttr(const QDomElement &); + bool parseSvgPage(const QDomElement &parent); + bool parseSvgPageset(const QDomElement &parent); + bool parseSvgElement(const QDomElement &parent); + + inline bool parseSvgRect(const QDomElement &element); + inline bool parseSvgEllipse(const QDomElement &element); + inline bool parseSvgPolygon(const QDomElement &element); + inline bool parseSvgPolyline(const QDomElement &element); + inline bool parseSvgText(const QDomElement &element); + inline bool parseSvgTextarea(const QDomElement &element); + inline bool parseSvgImage(const QDomElement &element); +// inline bool parseSvgTSpan(const QDomElement) + bool parseIwbGroup(QDomNode *element); + + + // to kill + void parseTextAttributes(const QDomElement &element, qreal &fontSize, QColor &fontColor, + QString &fontFamily, QString &fontStretch, bool &italic, + int &fontWeight, int &textAlign, QTransform &fontTransform); + //methods to store current xml parse state int PopState(); @@ -123,6 +150,8 @@ private: //helper methods bool getCurElementTransorm(QTransform &transform); void repositionSvgItem(UBGraphicsSvgItem *item, qreal width, qreal height, qreal x, qreal y, bool useTransform, QTransform &transform); + void repositionPixmapItem(UBGraphicsPixmapItem *item, qreal width, qreal height, qreal x, qreal y + , bool useTransform, QTransform &transform); QColor colorFromString(const QString& clrString); QTransform transformFromString(const QString trString); bool getViewBoxDimenstions(const QString& viewBox); diff --git a/src/board/UBBoardPaletteManager.cpp b/src/board/UBBoardPaletteManager.cpp old mode 100755 new mode 100644