diff --git a/src/qtquick/BookListModel.cpp b/src/qtquick/BookListModel.cpp index 792abe1..9fa5a09 100644 --- a/src/qtquick/BookListModel.cpp +++ b/src/qtquick/BookListModel.cpp @@ -1,412 +1,410 @@ /* * Copyright (C) 2015 Dan Leinir Turthra Jensen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "BookListModel.h" #include "BookDatabase.h" #include "CategoryEntriesModel.h" #include "ArchiveBookModel.h" #include "AcbfAuthor.h" #include "AcbfSequence.h" #include "AcbfBookinfo.h" #include #include #include #include #include #include #include #include class BookListModel::Private { public: Private() : contentModel(nullptr) , titleCategoryModel(nullptr) , newlyAddedCategoryModel(nullptr) , authorCategoryModel(nullptr) , seriesCategoryModel(nullptr) , publisherCategoryModel(nullptr) , folderCategoryModel(nullptr) , cacheLoaded(false) { db = new BookDatabase(); }; ~Private() { qDeleteAll(entries); db->deleteLater(); } QList entries; QAbstractListModel* contentModel; CategoryEntriesModel* titleCategoryModel; CategoryEntriesModel* newlyAddedCategoryModel; CategoryEntriesModel* authorCategoryModel; CategoryEntriesModel* seriesCategoryModel; CategoryEntriesModel* publisherCategoryModel; CategoryEntriesModel* folderCategoryModel; BookDatabase* db; bool cacheLoaded; void initializeSubModels(BookListModel* q) { if(!titleCategoryModel) { titleCategoryModel = new CategoryEntriesModel(q); connect(q, SIGNAL(entryDataUpdated(BookEntry*)), titleCategoryModel, SIGNAL(entryDataUpdated(BookEntry*))); connect(q, SIGNAL(entryRemoved(BookEntry*)), titleCategoryModel, SIGNAL(entryRemoved(BookEntry*))); emit q->titleCategoryModelChanged(); } if(!newlyAddedCategoryModel) { newlyAddedCategoryModel = new CategoryEntriesModel(q); connect(q, SIGNAL(entryDataUpdated(BookEntry*)), newlyAddedCategoryModel, SIGNAL(entryDataUpdated(BookEntry*))); connect(q, SIGNAL(entryRemoved(BookEntry*)), newlyAddedCategoryModel, SIGNAL(entryRemoved(BookEntry*))); emit q->newlyAddedCategoryModelChanged(); } if(!authorCategoryModel) { authorCategoryModel = new CategoryEntriesModel(q); connect(q, SIGNAL(entryDataUpdated(BookEntry*)), authorCategoryModel, SIGNAL(entryDataUpdated(BookEntry*))); connect(q, SIGNAL(entryRemoved(BookEntry*)), authorCategoryModel, SIGNAL(entryRemoved(BookEntry*))); emit q->authorCategoryModelChanged(); } if(!seriesCategoryModel) { seriesCategoryModel = new CategoryEntriesModel(q); connect(q, SIGNAL(entryDataUpdated(BookEntry*)), seriesCategoryModel, SIGNAL(entryDataUpdated(BookEntry*))); connect(q, SIGNAL(entryRemoved(BookEntry*)), seriesCategoryModel, SIGNAL(entryRemoved(BookEntry*))); emit q->seriesCategoryModelChanged(); } if(!publisherCategoryModel) { publisherCategoryModel = new CategoryEntriesModel(q); connect(q, SIGNAL(entryDataUpdated(BookEntry*)), publisherCategoryModel, SIGNAL(entryDataUpdated(BookEntry*))); connect(q, SIGNAL(entryRemoved(BookEntry*)), publisherCategoryModel, SIGNAL(entryRemoved(BookEntry*))); emit q->publisherCategoryModelChanged(); } if(!folderCategoryModel) { folderCategoryModel = new CategoryEntriesModel(q); connect(q, SIGNAL(entryDataUpdated(BookEntry*)), folderCategoryModel, SIGNAL(entryDataUpdated(BookEntry*))); connect(q, SIGNAL(entryRemoved(BookEntry*)), folderCategoryModel, SIGNAL(entryRemoved(BookEntry*))); emit q->folderCategoryModel(); } } void addEntry(BookListModel* q, BookEntry* entry) { entries.append(entry); q->append(entry); titleCategoryModel->addCategoryEntry(entry->title.left(1).toUpper(), entry); for (int i=0; iauthor.size(); i++) { authorCategoryModel->addCategoryEntry(entry->author.at(i), entry); } for (int i=0; iseries.size(); i++) { seriesCategoryModel->addCategoryEntry(entry->series.at(i), entry, SeriesRole); } if (newlyAddedCategoryModel->indexOfFile(entry->filename) == -1) { newlyAddedCategoryModel->append(entry, CreatedRole); } publisherCategoryModel->addCategoryEntry(entry->publisher, entry); QUrl url(entry->filename.left(entry->filename.lastIndexOf("/"))); folderCategoryModel->addCategoryEntry(url.path().mid(1), entry); if (folderCategoryModel->indexOfFile(entry->filename) == -1) { folderCategoryModel->append(entry); } } void loadCache(BookListModel* q) { QList entries = db->loadEntries(); if(entries.count() > 0) { initializeSubModels(q); } int i = 0; foreach(BookEntry* entry, entries) { addEntry(q, entry); if(++i % 100 == 0) { emit q->countChanged(); qApp->processEvents(); } } cacheLoaded = true; emit q->cacheLoadedChanged(); } }; BookListModel::BookListModel(QObject* parent) : CategoryEntriesModel(parent) , d(new Private) { } BookListModel::~BookListModel() { delete d; } void BookListModel::componentComplete() { QTimer::singleShot(0, this, [this](){ d->loadCache(this); }); } bool BookListModel::cacheLoaded() const { return d->cacheLoaded; } void BookListModel::setContentModel(QObject* newModel) { if(d->contentModel) { d->contentModel->disconnect(this); } d->contentModel = qobject_cast(newModel); if(d->contentModel) { connect(d->contentModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(contentModelItemsInserted(QModelIndex,int, int))); } emit contentModelChanged(); } QObject * BookListModel::contentModel() const { return d->contentModel; } void BookListModel::contentModelItemsInserted(QModelIndex index, int first, int last) { d->initializeSubModels(this); int newRow = d->entries.count(); beginInsertRows(QModelIndex(), newRow, newRow + (last - first)); int role = d->contentModel->roleNames().key("filePath"); for(int i = first; i < last + 1; ++i) { QVariant filePath = d->contentModel->data(d->contentModel->index(first, 0, index), role); BookEntry* entry = new BookEntry(); entry->filename = filePath.toUrl().toLocalFile(); QStringList splitName = entry->filename.split("/"); if (!splitName.isEmpty()) entry->filetitle = splitName.takeLast(); if(!splitName.isEmpty()) { entry->series = QStringList(splitName.takeLast()); // hahahaheuristics (dumb assumptions about filesystems, go!) entry->seriesNumbers = QStringList("0"); entry->seriesVolumes = QStringList("0"); } // just in case we end up without a title... using complete basename here, // as we would rather have "book one. part two" and the odd "book one - part two.tar" QFileInfo fileinfo(entry->filename); entry->title = fileinfo.completeBaseName(); if(entry->filename.toLower().endsWith("cbr")) { entry->thumbnail = QString("image://comiccover/").append(entry->filename); } #ifdef USE_PERUSE_PDFTHUMBNAILER else if(entry->filename.toLower().endsWith("pdf")) { entry->thumbnail = QString("image://pdfcover/").append(entry->filename); } #endif else { entry->thumbnail = QString("image://preview/").append(entry->filename); } KFileMetaData::UserMetaData data(entry->filename); entry->rating = data.rating(); entry->comment = data.userComment(); entry->tags = data.tags(); QVariantHash metadata = d->contentModel->data(d->contentModel->index(first, 0, index), Qt::UserRole + 2).toHash(); QVariantHash::const_iterator it = metadata.constBegin(); for (; it != metadata.constEnd(); it++) { if(it.key() == QLatin1String("author")) { entry->author = it.value().toStringList(); } else if(it.key() == QLatin1String("title")) { entry->title = it.value().toString().trimmed(); } else if(it.key() == QLatin1String("publisher")) { entry->publisher = it.value().toString().trimmed(); } else if(it.key() == QLatin1String("created")) { entry->created = it.value().toDateTime(); } else if(it.key() == QLatin1String("currentPage")) { entry->currentPage = it.value().toInt(); } else if(it.key() == QLatin1String("totalPages")) { entry->totalPages = it.value().toInt(); } else if(it.key() == QLatin1String("comments")) { entry->comment = it.value().toString();} else if(it.key() == QLatin1Literal("tags")) { entry->tags = it.value().toStringList();} else if(it.key() == QLatin1String("rating")) { entry->rating = it.value().toInt();} } // ACBF information is always preferred for CBRs, so let's just use that if it's there QMimeDatabase db; QString mimetype = db.mimeTypeForFile(entry->filename).name(); if(mimetype == "application/x-cbz" || mimetype == "application/x-cbr" || mimetype == "application/vnd.comicbook+zip" || mimetype == "application/vnd.comicbook+rar") { ArchiveBookModel* bookModel = new ArchiveBookModel(this); bookModel->setFilename(entry->filename); AdvancedComicBookFormat::Document* acbfDocument = qobject_cast(bookModel->acbfData()); if(acbfDocument) { for(AdvancedComicBookFormat::Sequence* sequence : acbfDocument->metaData()->bookInfo()->sequence()) { if (!entry->series.contains(sequence->title())) { entry->series.append(sequence->title()); entry->seriesNumbers.append(QString::number(sequence->number())); entry->seriesVolumes.append(QString::number(sequence->volume())); } else { int series = entry->series.indexOf(sequence->title()); entry->seriesNumbers.replace(series, QString::number(sequence->number())); entry->seriesVolumes.replace(series, QString::number(sequence->volume())); } } for(AdvancedComicBookFormat::Author* author : acbfDocument->metaData()->bookInfo()->author()) { entry->author.append(author->displayName()); } entry->description = acbfDocument->metaData()->bookInfo()->annotation(""); } if (entry->author.isEmpty()) { entry->author.append(bookModel->author()); } entry->title = bookModel->title(); entry->publisher = bookModel->publisher(); entry->totalPages = bookModel->pageCount(); bookModel->deleteLater(); } d->addEntry(this, entry); d->db->addEntry(entry); } endInsertRows(); emit countChanged(); qApp->processEvents(); } QObject * BookListModel::titleCategoryModel() const { return d->titleCategoryModel; } QObject * BookListModel::newlyAddedCategoryModel() const { return d->newlyAddedCategoryModel; } QObject * BookListModel::authorCategoryModel() const { return d->authorCategoryModel; } QObject * BookListModel::seriesCategoryModel() const { return d->seriesCategoryModel; } QObject * BookListModel::seriesModelForEntry(QString fileName) { Q_FOREACH(BookEntry* entry, d->entries) { if(entry->filename == fileName) { return d->seriesCategoryModel->leafModelForEntry(entry); } } return nullptr; } QObject *BookListModel::publisherCategoryModel() const { return d->publisherCategoryModel; } QObject * BookListModel::folderCategoryModel() const { return d->folderCategoryModel; } int BookListModel::count() const { return d->entries.count(); } void BookListModel::setBookData(QString fileName, QString property, QString value) { - qDebug() << fileName << property << value; Q_FOREACH(BookEntry* entry, d->entries) { if(entry->filename == fileName) { if(property == "totalPages") { entry->totalPages = value.toInt(); } else if(property == "currentPage") { entry->currentPage = value.toInt(); } else if(property == "rating") { entry->rating = value.toInt(); } else if(property == "tags") { entry->tags = value.split(","); } else if(property == "comment") { entry->comment = value; } emit entryDataUpdated(entry); break; } } } void BookListModel::removeBook(QString fileName, bool deleteFile) { - qDebug() << QUrl::fromLocalFile(fileName) << deleteFile; if(deleteFile) { KIO::DeleteJob* job = KIO::del(QUrl::fromLocalFile(fileName), KIO::HideProgressInfo); job->start(); } Q_FOREACH(BookEntry* entry, d->entries) { if(entry->filename == fileName) { emit entryRemoved(entry); delete entry; break; } } } QStringList BookListModel::knownBookFiles() const { QStringList files; foreach(BookEntry* entry, d->entries) { files.append(entry->filename); } return files; } diff --git a/src/qtquick/CategoryEntriesModel.cpp b/src/qtquick/CategoryEntriesModel.cpp index 6ba4a3a..7bdb35e 100644 --- a/src/qtquick/CategoryEntriesModel.cpp +++ b/src/qtquick/CategoryEntriesModel.cpp @@ -1,461 +1,460 @@ /* * Copyright (C) 2015 Dan Leinir Turthra Jensen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "CategoryEntriesModel.h" #include "PropertyContainer.h" #include #include #include #include class CategoryEntriesModel::Private { public: Private(CategoryEntriesModel* qq) : q(qq) {}; ~Private() { // No deleting the entries - this is done by the master BookListModel already, so do that at your own risk } CategoryEntriesModel* q; QString name; QList entries; QList categoryModels; QObject* wrapBookEntry(const BookEntry* entry) { PropertyContainer* obj = new PropertyContainer("book", q); obj->setProperty("author", entry->author); obj->setProperty("currentPage", QString::number(entry->currentPage)); obj->setProperty("filename", entry->filename); obj->setProperty("filetitle", entry->filetitle); obj->setProperty("created", entry->created); obj->setProperty("lastOpenedTime", entry->lastOpenedTime); obj->setProperty("publisher", entry->publisher); obj->setProperty("series", entry->series); obj->setProperty("title", entry->title); obj->setProperty("totalPages", entry->totalPages); obj->setProperty("thumbnail", entry->thumbnail); obj->setProperty("description", entry->description); obj->setProperty("comment", entry->comment); obj->setProperty("tags", entry->tags); obj->setProperty("rating", QString::number(entry->rating)); return obj; } }; CategoryEntriesModel::CategoryEntriesModel(QObject* parent) : QAbstractListModel(parent) , d(new Private(this)) { connect(this, SIGNAL(entryDataUpdated(BookEntry*)), this, SLOT(entryDataChanged(BookEntry*))); connect(this, SIGNAL(entryRemoved(BookEntry*)), this, SLOT(entryRemove(BookEntry*))); } CategoryEntriesModel::~CategoryEntriesModel() { delete d; } QHash CategoryEntriesModel::roleNames() const { QHash roles; roles[FilenameRole] = "filename"; roles[FiletitleRole] = "filetitle"; roles[TitleRole] = "title"; roles[SeriesRole] = "series"; roles[SeriesNumbersRole] = "seriesNumber"; roles[SeriesVolumesRole] = "seriesVolume"; roles[AuthorRole] = "author"; roles[PublisherRole] = "publisher"; roles[CreatedRole] = "created"; roles[LastOpenedTimeRole] = "lastOpenedTime"; roles[TotalPagesRole] = "totalPages"; roles[CurrentPageRole] = "currentPage"; roles[CategoryEntriesModelRole] = "categoryEntriesModel"; roles[CategoryEntryCountRole] = "categoryEntriesCount"; roles[ThumbnailRole] = "thumbnail"; roles[DescriptionRole] = "description"; roles[CommentRole] = "comment"; roles[TagsRole] = "tags"; roles[RatingRole] = "rating"; return roles; } QVariant CategoryEntriesModel::data(const QModelIndex& index, int role) const { QVariant result; if(index.isValid() && index.row() > -1) { if(index.row() < d->categoryModels.count()) { CategoryEntriesModel* model = d->categoryModels[index.row()]; switch(role) { case Qt::DisplayRole: case TitleRole: result.setValue(model->name()); break; case CategoryEntryCountRole: result.setValue(model->bookCount()); break; case CategoryEntriesModelRole: result.setValue(model); break; default: result.setValue(QString("Unknown role")); break; } } else { const BookEntry* entry = d->entries[index.row() - d->categoryModels.count()]; switch(role) { case Qt::DisplayRole: case FilenameRole: result.setValue(entry->filename); break; case FiletitleRole: result.setValue(entry->filetitle); break; case TitleRole: result.setValue(entry->title); break; case SeriesRole: result.setValue(entry->series); break; case SeriesNumbersRole: result.setValue(entry->seriesNumbers); break; case SeriesVolumesRole: result.setValue(entry->seriesVolumes); break; case AuthorRole: result.setValue(entry->author); break; case PublisherRole: result.setValue(entry->publisher); break; case CreatedRole: result.setValue(entry->created); break; case LastOpenedTimeRole: result.setValue(entry->lastOpenedTime); break; case TotalPagesRole: result.setValue(entry->totalPages); break; case CurrentPageRole: result.setValue(entry->currentPage); break; case CategoryEntriesModelRole: // Nothing, if we're not equipped with one such... break; case CategoryEntryCountRole: result.setValue(0); break; case ThumbnailRole: result.setValue(entry->thumbnail); break; case DescriptionRole: result.setValue(entry->description); break; case CommentRole: result.setValue(entry->comment); break; case TagsRole: result.setValue(entry->tags); break; case RatingRole: result.setValue(entry->rating); break; default: result.setValue(QString("Unknown role")); break; } } } return result; } int CategoryEntriesModel::rowCount(const QModelIndex& parent) const { if(parent.isValid()) return 0; return d->categoryModels.count() + d->entries.count(); } void CategoryEntriesModel::append(BookEntry* entry, Roles compareRole) { int insertionIndex = 0; int seriesOne = -1; int seriesTwo = -1; if(compareRole == SeriesRole) { seriesOne = entry->series.indexOf(name()); if (entry->series.contains(name(), Qt::CaseInsensitive) && seriesOne == -1){ for (int s=0; sseries.size();s++) { if (name().toLower() == entry->series.at(s).toLower()) { seriesOne = s; } } } } for(; insertionIndex < d->entries.count(); ++insertionIndex) { if(compareRole == SeriesRole) { seriesTwo = d->entries.at(insertionIndex)->series.indexOf(name()); if ( d->entries.at(insertionIndex)->series.contains(name(), Qt::CaseInsensitive) && seriesTwo == -1){ for (int s=0; s< d->entries.at(insertionIndex)->series.size();s++) { if (name().toLower() == d->entries.at(insertionIndex)->series.at(s).toLower()) { seriesTwo = s; } } } } if(compareRole == CreatedRole) { if(entry->created <= d->entries.at(insertionIndex)->created) { continue; } break; } else if((seriesOne>-1 && seriesTwo>-1) && entry->seriesNumbers.at(seriesOne).toInt() > 0 && d->entries.at(insertionIndex)->seriesNumbers.at(seriesTwo).toInt() > 0) { if (entry->seriesVolumes.at(seriesOne).toInt() >= d->entries.at(insertionIndex)->seriesVolumes.at(seriesTwo).toInt() && entry->seriesNumbers.at(seriesOne).toInt() > d->entries.at(insertionIndex)->seriesNumbers.at(seriesTwo).toInt()) {continue;} - qDebug() << name() << entry->seriesNumbers.at(seriesOne).toInt() << d->entries.at(insertionIndex)->seriesNumbers.at(seriesTwo).toInt(); break; } else { if(QString::localeAwareCompare(d->entries.at(insertionIndex)->title, entry->title) > 0) { break; } } } beginInsertRows(QModelIndex(), insertionIndex, insertionIndex); d->entries.insert(insertionIndex, entry); endInsertRows(); } QString CategoryEntriesModel::name() const { return d->name; } void CategoryEntriesModel::setName(const QString& newName) { d->name = newName; } QObject * CategoryEntriesModel::leafModelForEntry(BookEntry* entry) { QObject* model(nullptr); if(d->categoryModels.count() == 0) { if(d->entries.contains(entry)) { model = this; } } else { Q_FOREACH(CategoryEntriesModel* testModel, d->categoryModels) { model = testModel->leafModelForEntry(entry); if(model) { break; } } } return model; } void CategoryEntriesModel::addCategoryEntry(const QString& categoryName, BookEntry* entry, Roles compareRole) { if(categoryName.length() > 0) { QStringList splitName = categoryName.split("/"); // qDebug() << "Parsing" << categoryName; QString nextCategory = splitName.takeFirst(); CategoryEntriesModel* categoryModel = nullptr; Q_FOREACH(CategoryEntriesModel* existingModel, d->categoryModels) { if(existingModel->name().toLower() == nextCategory.toLower()) { categoryModel = existingModel; break; } } if(!categoryModel) { categoryModel = new CategoryEntriesModel(this); connect(this, SIGNAL(entryDataUpdated(BookEntry*)), categoryModel, SIGNAL(entryDataUpdated(BookEntry*))); connect(this, SIGNAL(entryRemoved(BookEntry*)), categoryModel, SIGNAL(entryRemoved(BookEntry*))); categoryModel->setName(nextCategory); int insertionIndex = 0; for(; insertionIndex < d->categoryModels.count(); ++insertionIndex) { if(QString::localeAwareCompare(d->categoryModels.at(insertionIndex)->name(), categoryModel->name()) > 0) { break; } } beginInsertRows(QModelIndex(), insertionIndex, insertionIndex); d->categoryModels.insert(insertionIndex, categoryModel); endInsertRows(); } if (categoryModel->indexOfFile(entry->filename) == -1) { categoryModel->append(entry, compareRole); } categoryModel->addCategoryEntry(splitName.join("/"), entry); } } QObject* CategoryEntriesModel::get(int index) { BookEntry* entry = new BookEntry(); bool deleteEntry = true; if(index > -1 && index < d->entries.count()) { entry = d->entries.at(index); deleteEntry = false; } QObject* obj = d->wrapBookEntry(entry); if(deleteEntry) { delete entry; } return obj; } int CategoryEntriesModel::indexOfFile(QString filename) { int index = -1, i = 0; if(QFile::exists(filename)) { Q_FOREACH(BookEntry* entry, d->entries) { if(entry->filename == filename) { index = i; break; } ++i; } } return index; } bool CategoryEntriesModel::indexIsBook(int index) { if(index < d->categoryModels.count() || index >= rowCount()) { return false; } return true; } int CategoryEntriesModel::bookCount() const { return d->entries.count(); } QObject* CategoryEntriesModel::getEntry(int index) { PropertyContainer* obj = new PropertyContainer("book", this); if(index < 0 && index > rowCount() -1) { // don't be a silly person, you can't get a nothing... } else if(index > d->categoryModels.count() - 1) { // This is a book - get a book! obj = qobject_cast(get(index - d->categoryModels.count())); } else { CategoryEntriesModel* catEntry = d->categoryModels.at(index); obj->setProperty("title", catEntry->name()); obj->setProperty("categoryEntriesCount", catEntry->bookCount()); obj->setProperty("entriesModel", QVariant::fromValue(catEntry)); } return obj; } QObject* CategoryEntriesModel::bookFromFile(QString filename) { PropertyContainer* obj = qobject_cast(get(indexOfFile(filename))); if(obj->property("filename").toString().isEmpty()) { if(QFileInfo::exists(filename)) { QFileInfo info(filename); obj->setProperty("title", info.completeBaseName()); obj->setProperty("created", info.created()); KFileMetaData::UserMetaData data(filename); if (data.hasAttribute("peruse.currentPage")) { int currentPage = data.attribute("peruse.currentPage").toInt(); obj->setProperty("currentPage", QVariant::fromValue(currentPage)); } if (data.hasAttribute("peruse.totalPages")) { int totalPages = data.attribute("peruse.totalPages").toInt(); obj->setProperty("totalPages", QVariant::fromValue(totalPages)); } obj->setProperty("rating", QVariant::fromValue(data.rating())); if (!data.tags().isEmpty()) { obj->setProperty("tags", QVariant::fromValue(data.tags())); } if (!data.userComment().isEmpty()) { obj->setProperty("comment", QVariant::fromValue(data.userComment())); } obj->setProperty("filename", filename); QString thumbnail; if(filename.toLower().endsWith("cbr")) { thumbnail = QString("image://comiccover/").append(filename); } #ifdef USE_PERUSE_PDFTHUMBNAILER else if(filename.toLower().endsWith("pdf")) { thumbnail = QString("image://pdfcover/").append(filename); } #endif else { thumbnail = QString("image://preview/").append(filename); } obj->setProperty("thumbnail", thumbnail); } } return obj; } void CategoryEntriesModel::entryDataChanged(BookEntry* entry) { int entryIndex = d->entries.indexOf(entry) + d->categoryModels.count(); QModelIndex changed = index(entryIndex); dataChanged(changed, changed); } void CategoryEntriesModel::entryRemove(BookEntry* entry) { int listIndex = d->entries.indexOf(entry); if(listIndex > -1) { int entryIndex = listIndex + d->categoryModels.count(); beginRemoveRows(QModelIndex(), entryIndex, entryIndex); d->entries.removeAll(entry); endRemoveRows(); } }