1 /*
2 * Copyright 2018 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) version 3, or any
8 * later version accepted by the membership of KDE e.V. (or its
9 * successor approved by the membership of KDE e.V.), which shall
10 * act as a proxy defined in Section 6 of version 3 of the license.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "AcbfReferences.h"
23 #include <QTimer>
24 #include <QXmlStreamReader>
25
26 #include <acbf_debug.h>
27
28 using namespace AdvancedComicBookFormat;
29
30 class References::Private {
31 public:
Private(References * qq)32 Private(References* qq)
33 : q(qq)
34 {}
35 References* q;
36 QMultiHash<QString, Reference*> referencesById;
37 QObjectList references;
38
addReference(Reference * reference,bool emitListChangeSignal=true)39 void addReference(Reference* reference, bool emitListChangeSignal = true) {
40 referencesById.insert(reference->id(), reference);
41 references << reference;
42 QObject::connect(reference, &Reference::languageChanged, q, &References::referencesChanged);
43 QObject::connect(reference, &Reference::paragraphsChanged, q, &References::referencesChanged);
44 QObject::connect(reference, &Reference::idChanged, q, [this, reference](){
45 QMutableHashIterator<QString, Reference*> iterator(referencesById);
46 while(iterator.findNext(reference)) {
47 iterator.remove();
48 }
49 referencesById.insert(reference->id(), reference);
50 Q_EMIT q->referencesChanged();
51 });
52 QObject::connect(reference, &QObject::destroyed, q, [this, reference](){
53 referencesById.remove(referencesById.key(reference));
54 references.removeAll(reference);
55 Q_EMIT q->referencesChanged();
56 });
57 Q_EMIT q->referenceAdded(reference);
58 if (emitListChangeSignal) {
59 Q_EMIT q->referencesChanged();
60 }
61 }
62 };
63
References(Document * parent)64 References::References(Document* parent)
65 : QObject(parent)
66 , d(new Private(this))
67 {
68 static const int typeId = qRegisterMetaType<References*>("References*");
69 Q_UNUSED(typeId);
70 }
71
72 References::~References() = default;
73
toXml(QXmlStreamWriter * writer)74 void References::toXml(QXmlStreamWriter* writer) {
75 writer->writeStartElement(QStringLiteral("references"));
76
77 for(QObject* reference : d->references) {
78 qobject_cast<Reference*>(reference)->toXml(writer);
79 }
80 writer->writeEndElement();
81 }
82
fromXml(QXmlStreamReader * xmlReader)83 bool References::fromXml(QXmlStreamReader *xmlReader)
84 {
85 qDeleteAll(d->references);
86 while(xmlReader->readNextStartElement())
87 {
88 if(xmlReader->name() == QStringLiteral("reference"))
89 {
90 Reference* newReference = new Reference(this);
91 if(!newReference->fromXml(xmlReader)) {
92 return false;
93 }
94 d->addReference(newReference, false);
95 }
96 else
97 {
98 qCWarning(ACBF_LOG) << Q_FUNC_INFO << "currently unsupported subsection:" << xmlReader->name();
99 xmlReader->skipCurrentElement();
100 }
101 }
102
103 if (xmlReader->hasError()) {
104 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();
105 }
106
107 qCDebug(ACBF_LOG) << Q_FUNC_INFO << "Created reference section with" << d->references.count() << "references";
108 Q_EMIT referencesChanged();
109
110 return !xmlReader->hasError();
111 }
112
reference(const QString & id) const113 Reference* References::reference(const QString& id) const
114 {
115 return d->referencesById.value(id);
116 }
117
addReference(const QString & id,const QStringList & paragraphs,const QString & language)118 Reference* References::addReference(const QString& id, const QStringList& paragraphs, const QString& language)
119 {
120 Reference* ref = new Reference(this);
121 ref->setId(id);
122 ref->setParagraphs(paragraphs);
123 ref->setLanguage(language);
124 d->addReference(ref);
125 return ref;
126 }
127
referenceIds() const128 QStringList References::referenceIds() const
129 {
130 return d->referencesById.keys();
131 }
132
references() const133 QObjectList References::references() const
134 {
135 return d->references;
136 }
137
referenceIndex(Reference * reference) const138 int References::referenceIndex(Reference* reference) const
139 {
140 return d->references.indexOf(reference);
141 }
142
swapReferences(QObject * swapThis,QObject * withThis)143 void References::swapReferences(QObject* swapThis, QObject* withThis)
144 {
145 int first = d->references.indexOf(swapThis);
146 int second = d->references.indexOf(withThis);
147 swapReferencesByIndex(first, second);
148 }
149
swapReferencesByIndex(int swapThis,int withThis)150 void References::swapReferencesByIndex(int swapThis, int withThis)
151 {
152 if (swapThis > -1 && swapThis < d->references.count() && withThis > -1 && withThis < d->references.count()) {
153 d->references.swapItemsAt(swapThis, withThis);
154 InternalReferenceObject* first = qobject_cast<InternalReferenceObject*>(d->references[swapThis]);
155 InternalReferenceObject* second = qobject_cast<InternalReferenceObject*>(d->references[withThis]);
156 Q_EMIT first->propertyDataChanged();
157 Q_EMIT second->propertyDataChanged();
158 Q_EMIT referencesChanged();
159 } else {
160 qCWarning(ACBF_LOG) << "There was an attempt to swap two references, and at least one of them was outside the bounds of the current list of references:" << swapThis << withThis;
161 }
162 }
163