File indexing completed on 2024-06-09 04:32:02
0001 /* 0002 * Copyright (C) 2020 Dan Leinir Turthra Jensen <admin@leinir.dk> 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 "AcbfIdentifiedObjectModel.h" 0023 #include "AcbfBody.h" 0024 #include "AcbfDocument.h" 0025 #include "AcbfInternalReferenceObject.h" 0026 #include "AcbfData.h" 0027 #include "AcbfFrame.h" 0028 #include "AcbfJump.h" 0029 #include "AcbfReferences.h" 0030 #include "AcbfTextarea.h" 0031 0032 using namespace AdvancedComicBookFormat; 0033 0034 class IdentifiedObjectModel::Private { 0035 public: 0036 Private(IdentifiedObjectModel* qq) 0037 : q(qq) 0038 {} 0039 IdentifiedObjectModel* q{nullptr}; 0040 Document* document{nullptr}; 0041 QList<InternalReferenceObject*> identifiedObjects; 0042 0043 void addAndConnectChild(InternalReferenceObject* child) { 0044 if (child) { 0045 int idx = identifiedObjects.count(); 0046 q->beginInsertRows(QModelIndex(), idx, idx); 0047 identifiedObjects.append(child); 0048 q->endInsertRows(); 0049 QObject::connect(child, &QObject::destroyed, q, [this, child](){ 0050 int idx = identifiedObjects.indexOf(child); 0051 q->beginRemoveRows(QModelIndex(), idx, idx); 0052 identifiedObjects.removeOne(child); 0053 q->endRemoveRows(); 0054 child->disconnect(q); 0055 }); 0056 QObject::connect(child, &InternalReferenceObject::propertyDataChanged, q, [this, child]() { 0057 QModelIndex idx = q->index(identifiedObjects.indexOf(child)); 0058 q->dataChanged(idx, idx); 0059 }); 0060 0061 // Some special handling for pages, because pages are special and potentially contain things, including some that can also have reference objects 0062 Page* page = qobject_cast<Page*>(child); 0063 if (page) { 0064 connect(page, &Page::jumpAdded, q, [this](QObject* child) { addAndConnectChild(qobject_cast<InternalReferenceObject*>(child)); }); 0065 connect(page, &Page::jumpsChanged, q, [this]() { q->dataChanged(q->index(0), q->index(identifiedObjects.count())); }); 0066 for (QObject* obj: page->jumps()) { 0067 addAndConnectChild(qobject_cast<InternalReferenceObject*>(obj)); 0068 } 0069 connect(page, &Page::frameAdded, q, [this](QObject* child) { addAndConnectChild(qobject_cast<InternalReferenceObject*>(child)); }); 0070 connect(page, &Page::framePointStringsChanged, q, [this]() { q->dataChanged(q->index(0), q->index(identifiedObjects.count())); }); 0071 for (Frame* frame : page->frames()) { 0072 addAndConnectChild(frame); 0073 } 0074 connect(page, &Page::textLayerAdded, q, [this](QObject* child) { connectTextLayer(qobject_cast<Textlayer*>(child)); }); 0075 connect(page, &Page::textLayerLanguagesChanged, q, [this](){ q->dataChanged(q->index(0), q->index(identifiedObjects.count())); }); 0076 for (Textlayer* textlayer : page->textLayersForAllLanguages()) { 0077 connectTextLayer(textlayer); 0078 } 0079 } 0080 } 0081 } 0082 void connectTextLayer(Textlayer* textlayer) { 0083 connect(textlayer, &Textlayer::textareaAdded, q, [this](QObject* child) { addAndConnectChild(qobject_cast<InternalReferenceObject*>(child)); }); 0084 connect(textlayer, &Textlayer::textareasChanged, q, [this](){ q->dataChanged(q->index(0), q->index(identifiedObjects.count())); }); 0085 for (QObject* obj : textlayer->textareas()) { 0086 Textarea* textarea = qobject_cast<Textarea*>(obj); 0087 addAndConnectChild(textarea); 0088 } 0089 } 0090 }; 0091 0092 IdentifiedObjectModel::IdentifiedObjectModel(QObject* parent) 0093 : QAbstractListModel(parent) 0094 , d(new Private(this)) 0095 { 0096 } 0097 0098 IdentifiedObjectModel::~IdentifiedObjectModel() = default; 0099 0100 QHash<int, QByteArray> IdentifiedObjectModel::roleNames() const 0101 { 0102 static const QHash<int, QByteArray> roleNames{ 0103 {IdRole, "id"}, 0104 {OriginalIndexRole, "originalIndex"}, 0105 {TypeRole, "type"}, 0106 {ObjectRole, "object"} 0107 }; 0108 return roleNames; 0109 } 0110 0111 QVariant IdentifiedObjectModel::data(const QModelIndex& index, int role) const 0112 { 0113 QVariant data; 0114 if (checkIndex(index) && d->document) { 0115 InternalReferenceObject* object = d->identifiedObjects.value(index.row()); 0116 if (object) { 0117 switch(role) { 0118 case IdRole: 0119 data.setValue(object->property("id")); 0120 break; 0121 case TypeRole: 0122 if (qobject_cast<Reference*>(object)) { 0123 data.setValue<int>(ReferenceType); 0124 } else if (qobject_cast<Binary*>(object)) { 0125 data.setValue<int>(BinaryType); 0126 } else if (qobject_cast<Textarea*>(object)) { 0127 data.setValue<int>(TextareaType); 0128 } else if (qobject_cast<Frame*>(object)) { 0129 data.setValue<int>(FrameType); 0130 } else if (qobject_cast<Page*>(object)) { 0131 data.setValue<int>(PageType); 0132 } else if (qobject_cast<Jump*>(object)) { 0133 data.setValue<int>(JumpType); 0134 } else { 0135 data.setValue<int>(UnknownType); 0136 } 0137 break; 0138 case OriginalIndexRole: 0139 data.setValue<int>(object->localIndex()); 0140 break; 0141 case ObjectRole: 0142 data.setValue<QObject*>(object); 0143 break; 0144 default: 0145 break; 0146 }; 0147 } 0148 } 0149 return data; 0150 } 0151 0152 int IdentifiedObjectModel::rowCount(const QModelIndex& parent) const 0153 { 0154 if(parent.isValid()) { 0155 return 0; 0156 } 0157 return d->identifiedObjects.count(); 0158 } 0159 0160 QObject * IdentifiedObjectModel::document() const 0161 { 0162 return d->document; 0163 } 0164 0165 void IdentifiedObjectModel::setDocument(QObject* document) 0166 { 0167 if (d->document != document) { 0168 beginResetModel(); 0169 for (QObject* obj : d->identifiedObjects) { 0170 obj->disconnect(this); 0171 } 0172 d->identifiedObjects.clear(); 0173 d->document = qobject_cast<Document*>(document); 0174 if (d->document) { 0175 std::function<void(const QObject* parent)> findAllIdentifiedObjects; 0176 findAllIdentifiedObjects = [&findAllIdentifiedObjects, this](const QObject *parent) { 0177 for (QObject *child : parent->children()) { 0178 InternalReferenceObject* refObj = qobject_cast<InternalReferenceObject*>(child); 0179 if (refObj) { 0180 d->addAndConnectChild(refObj); 0181 } 0182 findAllIdentifiedObjects(child); 0183 } 0184 }; 0185 findAllIdentifiedObjects(d->document); 0186 connect(d->document->data(), &Data::binaryAdded, this, [this](QObject* child){ d->addAndConnectChild(qobject_cast<InternalReferenceObject*>(child)); }); 0187 connect(d->document->data(), &Data::binariesChanged, this, [this](){ dataChanged(index(0), index(d->identifiedObjects.count())); }); 0188 connect(d->document->references(), &References::referenceAdded, this, [this](QObject* child){ d->addAndConnectChild(qobject_cast<InternalReferenceObject*>(child)); }); 0189 connect(d->document->references(), &References::referencesChanged, this, [this](){ dataChanged(index(0), index(d->identifiedObjects.count())); }); 0190 connect(d->document->body(), &Body::pageCountChanged, this, [this](){ dataChanged(index(0), index(d->identifiedObjects.count())); }); 0191 connect(d->document->body(), &Body::pageAdded, this, [this](QObject* child) { d->addAndConnectChild(qobject_cast<InternalReferenceObject*>(child)); }); 0192 } 0193 endResetModel(); 0194 Q_EMIT documentChanged(); 0195 } 0196 } 0197 0198 QObject * IdentifiedObjectModel::objectById(const QString& id) 0199 { 0200 QObject* identified{nullptr}; 0201 static const char* idProp{"id"}; 0202 for (InternalReferenceObject* object : d->identifiedObjects) { 0203 if ((object->supportedReferenceType() & InternalReferenceObject::ReferenceTarget) == InternalReferenceObject::ReferenceTarget) { 0204 if (object->property(idProp).toString() == id) { 0205 identified = object; 0206 break; 0207 } 0208 } 0209 } 0210 return identified; 0211 }