From e6d6d29566c5bfca0e7fa091311828f182426dcd Mon Sep 17 00:00:00 2001 From: thomas_lucky13 Date: Sun, 17 Jul 2022 16:29:49 +0400 Subject: [PATCH] LineItem in Adaptors --- src/adaptors/UBCFFSubsetAdaptor.cpp | 108 ++++++++++++ src/adaptors/UBCFFSubsetAdaptor.h | 1 + src/adaptors/UBSvgSubsetAdaptor.cpp | 247 ++++++++++++++++++++++++++++ src/adaptors/UBSvgSubsetAdaptor.h | 4 + 4 files changed, 360 insertions(+) diff --git a/src/adaptors/UBCFFSubsetAdaptor.cpp b/src/adaptors/UBCFFSubsetAdaptor.cpp index 71991ca9..3769fd1c 100644 --- a/src/adaptors/UBCFFSubsetAdaptor.cpp +++ b/src/adaptors/UBCFFSubsetAdaptor.cpp @@ -38,6 +38,7 @@ #include "domain/UBItem.h" #include "domain/UBGraphicsPolygonItem.h" +#include "domain/UBGraphicsLineItem.h" #include "domain/UBGraphicsStroke.h" #include "domain/UBGraphicsTextItem.h" #include "domain/UBGraphicsSvgItem.h" @@ -74,6 +75,7 @@ static QString tG = "g"; static QString tSwitch = "switch"; static QString tPolygon = "polygon"; static QString tPolyline = "polyline"; +static QString tLine = "line"; static QString tRect = "rect"; static QString tSvg = "svg"; static QString tText = "text"; @@ -90,6 +92,8 @@ static QString aFill = "fill"; static QString aFillopacity = "fill-opacity"; static QString aX = "x"; static QString aY = "y"; +static QString aX2 = "x2"; +static QString aY2 = "y2"; static QString aWidth = "width"; static QString aHeight = "height"; static QString aStroke = "stroke"; @@ -115,6 +119,7 @@ static QString aHref = "href"; static QString aBackground = "background"; static QString aLocked = "locked"; static QString aEditable = "editable"; +static QString aLinestyle = "line-style"; //attributes part names static QString apRotate = "rotate"; @@ -581,6 +586,108 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement & return true; } + +bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgLine(const QDomElement &element) +{ + QString svgPoints = element.attribute(aPoints); + QLineF line; + + qreal x1 = element.attribute(aX).toDouble(); + qreal y1 = element.attribute(aY).toDouble(); + qreal x2 = element.attribute(aX2).toDouble(); + qreal y2 = element.attribute(aY2).toDouble(); + qreal width = element.attribute(aWidth).toDouble(); + qreal height = element.attribute(aHeight).toDouble(); + QString textStrokeColor = element.attribute(aStroke); + QString textStrokeWidth = element.attribute(aStrokewidth); + qreal style = element.attribute(aLinestyle).toDouble(); + + QColor strokeColor = !textStrokeColor.isNull() ? colorFromString(textStrokeColor) : QColor(); + int strokeWidth = textStrokeWidth.toInt(); + + width += strokeWidth; + height += strokeWidth; + + QPen pen; + if (strokeColor.isValid()) { + pen.setColor(strokeColor); + } + if (strokeWidth) + pen.setWidth(strokeWidth); + if (style == 2) + { + pen.setStyle(Qt::PenStyle::DotLine); + pen.setCapStyle(Qt::PenCapStyle::RoundCap); + } else if (style == 1) + { + pen.setStyle(Qt::PenStyle::DashLine); + } else + { + pen.setStyle(Qt::PenStyle::SolidLine); + } + QUuid itemUuid(element.attribute(aId).right(QUuid().toString().length())); + QUuid itemGroupUuid(element.attribute(aId).left(QUuid().toString().length()-1)); + if (!itemUuid.isNull() && (itemGroupUuid!=itemUuid)) // reimported from UBZ + { + UBGraphicsLineItem *graphicsLine = new UBGraphicsLineItem(line); + + UBGraphicsStroke *stroke = new UBGraphicsStroke(); + //graphicsLine->setStroke(stroke); + + graphicsLine->setPen(pen); + QTransform transform; + QString textTransform = element.attribute(aTransform); + + graphicsLine->resetTransform(); + if (!textTransform.isNull()) { + transform = transformFromString(textTransform, graphicsLine); + } + mCurrentScene->addItem(graphicsLine); + + graphicsLine->setUuid(itemUuid); + mRefToUuidMap.insert(element.attribute(aId), itemUuid.toString()); + + } + else // simple CFF + { + QSvgGenerator *generator = createSvgGenerator(width + pen.width(), height + pen.width()); + QPainter painter; + + painter.begin(generator); + painter.setPen(pen); + painter.drawLine(x1, y1, x2, y2); + painter.end(); + + + //add resulting svg file to scene + UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); + + QString uuid = QUuid::createUuid().toString(); + mRefToUuidMap.insert(element.attribute(aId), uuid); + svgItem->setUuid(QUuid(uuid)); + + 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); + + if (mGSectionContainer) + { + addItemToGSection(svgItem); + } + + delete generator; + } + + + return true; +} + void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTextAttributes(const QDomElement &element, qreal &fontSize, QColor &fontColor, QString &fontFamily, QString &fontStretch, bool &italic, int &fontWeight, @@ -1101,6 +1208,7 @@ bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgElement(const QDomElement &p 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 == tLine && !parseSvgLine(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; diff --git a/src/adaptors/UBCFFSubsetAdaptor.h b/src/adaptors/UBCFFSubsetAdaptor.h index 168eee27..96573fe3 100644 --- a/src/adaptors/UBCFFSubsetAdaptor.h +++ b/src/adaptors/UBCFFSubsetAdaptor.h @@ -110,6 +110,7 @@ private: inline bool parseSvgEllipse(const QDomElement &element); inline bool parseSvgPolygon(const QDomElement &element); inline bool parseSvgPolyline(const QDomElement &element); + inline bool parseSvgLine(const QDomElement &element); inline bool parseSvgText(const QDomElement &element); inline bool parseSvgTextarea(const QDomElement &element); inline bool parseSvgImage(const QDomElement &element); diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index d4b421eb..15c80db1 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -40,6 +40,7 @@ #include "domain/UBGraphicsPixmapItem.h" #include "domain/UBGraphicsProxyWidget.h" #include "domain/UBGraphicsPolygonItem.h" +#include "domain/UBGraphicsLineItem.h" #include "domain/UBGraphicsMediaItem.h" #include "domain/UBGraphicsWidgetItem.h" #include "domain/UBGraphicsPDFItem.h" @@ -618,6 +619,47 @@ UBGraphicsScene* UBSvgSubsetAdaptor::UBSvgSubsetReader::loadScene(UBDocumentProx group->addToGroup(polygonItem); } } + else if (mXmlReader.name() == "lineL") + { + UBGraphicsLineItem* lineItem = 0; + + QString parentId = mXmlReader.attributes().value(mNamespaceUri, "parent").toString(); + + lineItem = lineItemFromLineSvg(mScene->isDarkBackground() ? Qt::white : Qt::black); + + if(parentId.isEmpty() && strokesGroup) + parentId = strokesGroup->uuid().toString(); + + if(parentId.isEmpty()) + parentId = QUuid::createUuid().toString(); + + if (lineItem) + { + lineItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Graphic)); + + UBGraphicsStrokesGroup* group; + if(!mStrokesList.contains(parentId)){ + group = new UBGraphicsStrokesGroup(); + mStrokesList.insert(parentId,group); + group->setTransform(lineItem->transform()); + UBGraphicsItem::assignZValue(group, lineItem->zValue()); + } + else + group = mStrokesList.value(parentId); + + if (!currentStroke) + currentStroke = new UBGraphicsStroke(); + + if(lineItem->transform().isIdentity()) + lineItem->setTransform(group->transform()); + + group->addToGroup(lineItem); + lineItem->setStrokesGroup(group); + + lineItem->show(); + group->addToGroup(lineItem); + } + } else if (mXmlReader.name() == "polyline") { QList polygonItems = polygonItemsFromPolylineSvg(mScene->isDarkBackground() ? Qt::white : Qt::black); @@ -1300,6 +1342,56 @@ bool UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistScene(UBDocumentProxy* proxy, continue; } + // Is the item a line? + UBGraphicsLineItem *lineItem = qgraphicsitem_cast (item); + if (lineItem && lineItem->isVisible()) + { + UBGraphicsLineStroke* currentStroke = lineItem->stroke(); + + bool firstLineInStroke = currentStroke && !openStroke; + + if (firstLineInStroke) + { + mXmlWriter.writeStartElement("g"); + + QColor colorOnDarkBackground = lineItem->colorOnDarkBackground(); + QColor colorOnLightBackground = lineItem->colorOnLightBackground(); + UBGraphicsStrokesGroup * sg = lineItem->strokesGroup(); + + if (colorOnDarkBackground.isValid() && colorOnLightBackground.isValid() && sg) + { + mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "z-value" + , QString("%1").arg(lineItem->strokesGroup()->zValue())); + + mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri + , "fill-on-dark-background", colorOnDarkBackground.name()); + mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri + , "fill-on-light-background", colorOnLightBackground.name()); + + mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "uuid", UBStringUtils::toCanonicalUuid(sg->uuid())); + + QVariant locked = sg->data(UBGraphicsItemData::ItemLocked); + if (!locked.isNull() && locked.toBool()) + mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "locked", xmlTrue); + + QVariant layer = sg->data(UBGraphicsItemData::ItemLayerType); + mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "layer", QString("%1").arg(layer.toInt())); + + QMatrix matrix = sg->sceneMatrix(); + if (!matrix.isIdentity()) + mXmlWriter.writeAttribute("transform", toSvgTransform(matrix)); + + qDebug() << "Attributes written"; + + groupHoldsInfo = true; + } + } + + lineItemToSvgLine(lineItem, groupHoldsInfo); + + continue; + } + if (openStroke) { mXmlWriter.writeEndElement(); //g @@ -1555,6 +1647,53 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::polygonItemToSvgLine(UBGraphicsPolyg } +void UBSvgSubsetAdaptor::UBSvgSubsetWriter::lineItemToSvgLine(UBGraphicsLineItem* lineItem, bool groupHoldsInfo) +{ + mXmlWriter.writeStartElement("lineL"); + + QLineF line = lineItem->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(lineItem->originalWidth(), 'f', -1)); + mXmlWriter.writeAttribute("stroke", lineItem->pen().color().name()); + + qreal alpha = lineItem->pen().color().alphaF(); + if (alpha < 1.0) + mXmlWriter.writeAttribute("stroke-opacity", QString::number(alpha, 'f', 2)); + mXmlWriter.writeAttribute("stroke-linecap", "round"); + + switch (lineItem->style()) + { + case Qt::PenStyle::DotLine: + mXmlWriter.writeAttribute("line-style", "2"); + break; + case Qt::PenStyle::DashLine: + mXmlWriter.writeAttribute("line-style", "1"); + break; + default: + mXmlWriter.writeAttribute("line-style", "0"); + } + + if (!groupHoldsInfo) + { + mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "z-value", QString("%1").arg(lineItem->zValue())); + mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "fill-on-dark-background", lineItem->colorOnDarkBackground().name()); + mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "fill-on-light-background", lineItem->colorOnLightBackground().name()); + } + + mXmlWriter.writeEndElement(); + +} void UBSvgSubsetAdaptor::UBSvgSubsetWriter::strokeToSvgPolyline(UBGraphicsStroke* stroke, bool groupHoldsInfo) { @@ -1901,6 +2040,114 @@ UBGraphicsPolygonItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::polygonItemFromLin return polygonItem; } +UBGraphicsLineItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::lineItemFromLineSvg(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"); + + qreal style = mXmlReader.attributes().value("line-style").toDouble(); + + 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(); + } + + UBGraphicsLineItem* lineItem = new UBGraphicsLineItem(line, lineWidth); + graphicsItemFromSvg(lineItem); + + QStringRef svgStroke = mXmlReader.attributes().value("stroke"); + + QColor penColor = pDefaultColor; + + if (!svgStroke.isNull()) + { + penColor.setNamedColor(svgStroke.toString()); + + } + + QStringRef svgStrokeOpacity = mXmlReader.attributes().value("stroke-opacity"); + qreal opacity = 1.0; + + if (!svgStrokeOpacity.isNull()) + { + opacity = svgStrokeOpacity.toString().toFloat(); + penColor.setAlphaF(opacity); + } + + lineItem->setColor(penColor); + if (style == 2) + { + lineItem->setStyle(Qt::PenStyle::DotLine); + } else if (style == 1) + { + lineItem->setStyle(Qt::PenStyle::DashLine); + } else + { + lineItem->setStyle(Qt::PenStyle::SolidLine); + } + 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); + lineItem->setColorOnDarkBackground(color); + } + else + { + QColor color = mGroupDarkBackgroundColor; + color.setAlphaF(opacity); + lineItem->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); + lineItem->setColorOnLightBackground(color); + } + else + { + QColor color = mGroupLightBackgroundColor; + color.setAlphaF(opacity); + lineItem->setColorOnLightBackground(color); + } + + return lineItem; +} + QList UBSvgSubsetAdaptor::UBSvgSubsetReader::polygonItemsFromPolylineSvg(const QColor& pDefaultColor) { QStringRef strokeWidth = mXmlReader.attributes().value("stroke-width"); diff --git a/src/adaptors/UBSvgSubsetAdaptor.h b/src/adaptors/UBSvgSubsetAdaptor.h index 25ccc9ef..3e025d86 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.h +++ b/src/adaptors/UBSvgSubsetAdaptor.h @@ -38,6 +38,7 @@ class UBGraphicsSvgItem; class UBGraphicsPolygonItem; +class UBGraphicsLineItem; class UBGraphicsPixmapItem; class UBGraphicsPDFItem; class UBGraphicsWidgetItem; @@ -125,6 +126,8 @@ class UBSvgSubsetAdaptor QList polygonItemsFromPolylineSvg(const QColor& pDefaultColor); + UBGraphicsLineItem* lineItemFromLineSvg(const QColor& pDefaultPenColor); + UBGraphicsPixmapItem* pixmapItemFromSvg(); UBGraphicsSvgItem* svgItemFromSvg(); @@ -195,6 +198,7 @@ class UBSvgSubsetAdaptor void persistStrokeToDom(QGraphicsItem *strokeItem, QDomElement *curParent, QDomDocument *curDomDocument); void polygonItemToSvgPolygon(UBGraphicsPolygonItem* polygonItem, bool groupHoldsInfo); void polygonItemToSvgLine(UBGraphicsPolygonItem* polygonItem, bool groupHoldsInfo); + void lineItemToSvgLine(UBGraphicsLineItem* lineItem, bool groupHoldsInfo); void strokeToSvgPolyline(UBGraphicsStroke* stroke, bool groupHoldsInfo); void strokeToSvgPolygon(UBGraphicsStroke* stroke, bool groupHoldsInfo);