File indexing completed on 2024-05-26 04:38:00

0001 /*
0002  * Copyright 2018  Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) version 3, or any
0008  * later version accepted by the membership of KDE e.V. (or its
0009  * successor approved by the membership of KDE e.V.), which shall
0010  * act as a proxy defined in Section 6 of version 3 of the license.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0019  *
0020  */
0021 
0022 #include "AcbfFrame.h"
0023 #include <QXmlStreamReader>
0024 
0025 #include <acbf_debug.h>
0026 
0027 using namespace AdvancedComicBookFormat;
0028 
0029 class Frame::Private
0030 {
0031 public:
0032     Private()
0033     {}
0034     QString id;
0035     QString bgcolor;
0036     QList<QPoint> points;
0037 };
0038 
0039 Frame::Frame(Page* parent)
0040     : InternalReferenceObject(InternalReferenceObject::ReferenceTarget, parent)
0041     , d(new Private)
0042 {
0043     static const int typeId = qRegisterMetaType<Frame*>("Frame*");
0044     Q_UNUSED(typeId);
0045     connect(this, &Frame::pointCountChanged, this, &Frame::boundsChanged);
0046 
0047     connect(this, &Frame::idChanged, this, &InternalReferenceObject::propertyDataChanged);
0048     connect(this, &Frame::bgcolorChanged, this, &InternalReferenceObject::propertyDataChanged);
0049     connect(this, &Frame::boundsChanged, this, &InternalReferenceObject::propertyDataChanged);
0050 }
0051 
0052 Frame::~Frame() = default;
0053 
0054 void Frame::toXml(QXmlStreamWriter* writer) {
0055     writer->writeStartElement(QStringLiteral("frame"));
0056     if(!d->id.isEmpty()) {
0057         writer->writeAttribute(QStringLiteral("id"), id());
0058     }
0059 
0060     QStringList points;
0061     for(const QPoint& point : d->points) {
0062         points << QStringLiteral("%1,%2").arg(QString::number(point.x())).arg(QString::number(point.y()));
0063     }
0064     writer->writeAttribute(QStringLiteral("points"), points.join(' '));
0065     if(!d->bgcolor.isEmpty()) {
0066         writer->writeAttribute(QStringLiteral("bgcolor"), d->bgcolor);
0067     }
0068     writer->writeEndElement();
0069 }
0070 
0071 bool Frame::fromXml(QXmlStreamReader *xmlReader)
0072 {
0073     setId(xmlReader->attributes().value(QStringLiteral("id")).toString());
0074     setBgcolor(xmlReader->attributes().value(QStringLiteral("bgcolor")).toString());
0075 
0076     QVector<QStringRef> points = xmlReader->attributes().value(QStringLiteral("points")).split(' ');
0077     for(QStringRef point : points) {
0078         QVector<QStringRef> elements = point.split(',');
0079         if(elements.length() == 2)
0080         {
0081             addPoint(QPoint(elements.at(0).toInt(), elements.at(1).toInt()));
0082         }
0083         else
0084         {
0085             qCWarning(ACBF_LOG) << "Failed to construct one of the points for a frame. Attempted to handle the point" << point << "in the data" << points;
0086             return false;
0087         }
0088     }
0089 
0090     if (xmlReader->hasError()) {
0091         qCWarning(ACBF_LOG) << Q_FUNC_INFO << "Failed to read ACBF XML document at token" << xmlReader->name() << "(" << xmlReader->lineNumber() << ":" << xmlReader->columnNumber() << ") The reported error was:" << xmlReader->errorString();
0092     }
0093     qCDebug(ACBF_LOG) << Q_FUNC_INFO << "Created a frame with " << points.count() << "points";
0094 
0095     return !xmlReader->hasError();
0096 }
0097 
0098 QString Frame::id() const
0099 {
0100     return d->id;
0101 }
0102 
0103 void Frame::setId(const QString& newId)
0104 {
0105     if (d->id != newId) {
0106         d->id = newId;
0107         Q_EMIT idChanged();
0108     }
0109 }
0110 
0111 QList<QPoint> Frame::points() const
0112 {
0113     return d->points;
0114 }
0115 
0116 QPoint Frame::point(int index) const
0117 {
0118     return d->points.at(index);
0119 }
0120 
0121 int Frame::pointIndex(const QPoint& point) const
0122 {
0123     return d->points.indexOf(point);
0124 }
0125 
0126 void Frame::addPoint(const QPoint& point, int index)
0127 {
0128     if(index > -1 && d->points.count() < index) {
0129         d->points.insert(index, point);
0130     }
0131     else {
0132         d->points.append(point);
0133     }
0134     emit pointCountChanged();
0135 }
0136 
0137 void Frame::removePoint(const QPoint& point)
0138 {
0139     d->points.removeAll(point);
0140     emit pointCountChanged();
0141 }
0142 
0143 bool Frame::swapPoints(const QPoint& swapThis, const QPoint& withThis)
0144 {
0145     int index1 = d->points.indexOf(swapThis);
0146     int index2 = d->points.indexOf(withThis);
0147     if(index1 > -1 && index2 > -1) {
0148         d->points.swapItemsAt(index1, index2);
0149         emit pointCountChanged();
0150         return true;
0151     }
0152     return false;
0153 }
0154 
0155 void Frame::setPointsFromRect(const QPoint &topLeft, const QPoint &bottomRight)
0156 {
0157     QRect rect(topLeft, bottomRight);
0158     d->points.clear();
0159     d->points.append(rect.topLeft());
0160     d->points.append(rect.topRight());
0161     d->points.append(rect.bottomRight());
0162     d->points.append(rect.bottomLeft());
0163     emit pointCountChanged();
0164 }
0165 
0166 int Frame::pointCount() const
0167 {
0168     return d->points.size();
0169 }
0170 
0171 QRect Frame::bounds() const
0172 {
0173     // Would use QPolygon here, but that requires including QTGUI.
0174     if (d->points.size()==0) {
0175         return QRect();
0176     }
0177     QRect rect(d->points.at(0), d->points.at(1));
0178     for (int i = 2; i < d->points.size(); i++) {
0179         QPoint p = d->points.at(i);
0180         if (rect.left() > p.x()) {
0181             rect.setLeft(p.x());
0182         }
0183         if (rect.right() < p.x()) {
0184             rect.setRight(p.x());
0185         }
0186         if (rect.bottom() < p.y()) {
0187             rect.setBottom(p.y());
0188         }
0189         if (rect.top() > p.y()) {
0190             rect.setTop(p.y());
0191         }
0192     }
0193     return rect;
0194 }
0195 
0196 QString Frame::bgcolor() const
0197 {
0198     return d->bgcolor;
0199 }
0200 
0201 void Frame::setBgcolor(const QString& newColor)
0202 {
0203     d->bgcolor = newColor;
0204     emit bgcolorChanged();
0205 }
0206 
0207 int AdvancedComicBookFormat::Frame::localIndex()
0208 {
0209     int idx{-1};
0210     Page* page = qobject_cast<Page*>(parent());
0211     if (page) {
0212         idx = page->frameIndex(this);
0213     }
0214     return idx;
0215 }