You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
668 lines
20 KiB
668 lines
20 KiB
/* |
|
SPDX-FileCopyrightText: 2007 Tobias Koenig <tokoe@kde.org> |
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later |
|
*/ |
|
|
|
#include "annotationproxymodels.h" |
|
|
|
#include <QItemSelection> |
|
#include <QList> |
|
|
|
#include <QIcon> |
|
|
|
#include "annotationmodel.h" |
|
#include "gui/debug_ui.h" |
|
|
|
static quint32 mixIndex(int row, int column) |
|
{ |
|
return (row << 4) | column; |
|
} |
|
|
|
PageFilterProxyModel::PageFilterProxyModel(QObject *parent) |
|
: QSortFilterProxyModel(parent) |
|
, mGroupByCurrentPage(false) |
|
, mCurrentPage(-1) |
|
{ |
|
setDynamicSortFilter(true); |
|
} |
|
|
|
void PageFilterProxyModel::groupByCurrentPage(bool value) |
|
{ |
|
if (mGroupByCurrentPage == value) { |
|
return; |
|
} |
|
|
|
mGroupByCurrentPage = value; |
|
|
|
invalidateFilter(); |
|
} |
|
|
|
void PageFilterProxyModel::setCurrentPage(int page) |
|
{ |
|
if (mCurrentPage == page) { |
|
return; |
|
} |
|
|
|
mCurrentPage = page; |
|
|
|
// no need to invalidate when we're not showing the current page only |
|
if (!mGroupByCurrentPage) { |
|
return; |
|
} |
|
|
|
invalidateFilter(); |
|
} |
|
|
|
bool PageFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &sourceParent) const |
|
{ |
|
if (!mGroupByCurrentPage) { |
|
return true; |
|
} |
|
|
|
const QModelIndex pageIndex = sourceModel()->index(row, 0, sourceParent); |
|
int page = sourceModel()->data(pageIndex, AnnotationModel::PageRole).toInt(); |
|
|
|
return (page == mCurrentPage); |
|
} |
|
|
|
PageGroupProxyModel::PageGroupProxyModel(QObject *parent) |
|
: QAbstractProxyModel(parent) |
|
, mGroupByPage(false) |
|
{ |
|
} |
|
|
|
int PageGroupProxyModel::columnCount(const QModelIndex &parentIndex) const |
|
{ |
|
// For top-level and second level we have always only one column |
|
if (mGroupByPage) { |
|
if (parentIndex.isValid()) { |
|
if (parentIndex.parent().isValid()) { |
|
return 0; |
|
} else { |
|
return 1; // second-level |
|
} |
|
} else { |
|
return 1; // top-level |
|
} |
|
} else { |
|
if (!parentIndex.isValid()) { // top-level |
|
return 1; |
|
} else { |
|
return 0; |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
int PageGroupProxyModel::rowCount(const QModelIndex &parentIndex) const |
|
{ |
|
if (mGroupByPage) { |
|
if (parentIndex.isValid()) { |
|
if (parentIndex.parent().isValid()) { |
|
return 0; |
|
} else { |
|
return mTreeIndexes[parentIndex.row()].second.count(); // second-level |
|
} |
|
} else { |
|
return mTreeIndexes.count(); // top-level |
|
} |
|
} else { |
|
if (!parentIndex.isValid()) { // top-level |
|
return mIndexes.count(); |
|
} else { |
|
return 0; |
|
} |
|
} |
|
} |
|
|
|
QModelIndex PageGroupProxyModel::index(int row, int column, const QModelIndex &parentIndex) const |
|
{ |
|
if (row < 0 || column != 0) { |
|
return QModelIndex(); |
|
} |
|
|
|
if (mGroupByPage) { |
|
if (parentIndex.isValid()) { |
|
if (parentIndex.row() >= 0 && parentIndex.row() < mTreeIndexes.count() && row < mTreeIndexes[parentIndex.row()].second.count()) { |
|
return createIndex(row, column, qint32(parentIndex.row() + 1)); |
|
} else { |
|
return QModelIndex(); |
|
} |
|
} else { |
|
if (row < mTreeIndexes.count()) { |
|
return createIndex(row, column); |
|
} else { |
|
return QModelIndex(); |
|
} |
|
} |
|
} else { |
|
if (row < mIndexes.count()) { |
|
return createIndex(row, column, mixIndex(parentIndex.row(), parentIndex.column())); |
|
} else { |
|
return QModelIndex(); |
|
} |
|
} |
|
} |
|
|
|
QModelIndex PageGroupProxyModel::parent(const QModelIndex &idx) const |
|
{ |
|
if (mGroupByPage) { |
|
if (idx.internalId() == 0) { // top-level |
|
return QModelIndex(); |
|
} else { |
|
return index(idx.internalId() - 1, idx.column()); |
|
} |
|
} else { |
|
// We have only top-level items |
|
return QModelIndex(); |
|
} |
|
} |
|
|
|
QModelIndex PageGroupProxyModel::mapFromSource(const QModelIndex &sourceIndex) const |
|
{ |
|
if (mGroupByPage) { |
|
if (sourceIndex.parent().isValid()) { |
|
return index(sourceIndex.row(), sourceIndex.column(), sourceIndex.parent()); |
|
} else { |
|
return index(sourceIndex.row(), sourceIndex.column()); |
|
} |
|
} else { |
|
for (int i = 0; i < mIndexes.count(); ++i) { |
|
if (mIndexes[i] == sourceIndex) { |
|
return index(i, 0); |
|
} |
|
} |
|
|
|
return QModelIndex(); |
|
} |
|
} |
|
|
|
QModelIndex PageGroupProxyModel::mapToSource(const QModelIndex &proxyIndex) const |
|
{ |
|
if (!proxyIndex.isValid()) { |
|
return QModelIndex(); |
|
} |
|
|
|
if (mGroupByPage) { |
|
if (proxyIndex.internalId() == 0) { |
|
if (proxyIndex.row() >= mTreeIndexes.count() || proxyIndex.row() < 0) { |
|
return QModelIndex(); |
|
} |
|
|
|
return mTreeIndexes[proxyIndex.row()].first; |
|
} else { |
|
if (qint32(proxyIndex.internalId()) - 1 >= mTreeIndexes.count() || proxyIndex.row() >= mTreeIndexes[proxyIndex.internalId() - 1].second.count()) { |
|
return QModelIndex(); |
|
} |
|
|
|
return mTreeIndexes[proxyIndex.internalId() - 1].second[proxyIndex.row()]; |
|
} |
|
} else { |
|
if (proxyIndex.column() > 0 || proxyIndex.row() >= mIndexes.count()) { |
|
return QModelIndex(); |
|
} else { |
|
return mIndexes[proxyIndex.row()]; |
|
} |
|
} |
|
} |
|
|
|
void PageGroupProxyModel::setSourceModel(QAbstractItemModel *model) |
|
{ |
|
if (sourceModel()) { |
|
disconnect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &PageGroupProxyModel::rebuildIndexes); |
|
disconnect(sourceModel(), &QAbstractItemModel::modelReset, this, &PageGroupProxyModel::rebuildIndexes); |
|
disconnect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &PageGroupProxyModel::rebuildIndexes); |
|
disconnect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, &PageGroupProxyModel::rebuildIndexes); |
|
disconnect(sourceModel(), &QAbstractItemModel::dataChanged, this, &PageGroupProxyModel::sourceDataChanged); |
|
} |
|
|
|
QAbstractProxyModel::setSourceModel(model); |
|
|
|
connect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &PageGroupProxyModel::rebuildIndexes); |
|
connect(sourceModel(), &QAbstractItemModel::modelReset, this, &PageGroupProxyModel::rebuildIndexes); |
|
connect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &PageGroupProxyModel::rebuildIndexes); |
|
connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, &PageGroupProxyModel::rebuildIndexes); |
|
connect(sourceModel(), &QAbstractItemModel::dataChanged, this, &PageGroupProxyModel::sourceDataChanged); |
|
|
|
rebuildIndexes(); |
|
} |
|
|
|
void PageGroupProxyModel::rebuildIndexes() |
|
{ |
|
beginResetModel(); |
|
|
|
if (mGroupByPage) { |
|
mTreeIndexes.clear(); |
|
|
|
for (int row = 0; row < sourceModel()->rowCount(); ++row) { |
|
const QModelIndex pageIndex = sourceModel()->index(row, 0); |
|
|
|
QList<QModelIndex> itemIndexes; |
|
for (int subRow = 0; subRow < sourceModel()->rowCount(pageIndex); ++subRow) { |
|
itemIndexes.append(sourceModel()->index(subRow, 0, pageIndex)); |
|
} |
|
|
|
mTreeIndexes.append(QPair<QModelIndex, QList<QModelIndex>>(pageIndex, itemIndexes)); |
|
} |
|
} else { |
|
mIndexes.clear(); |
|
|
|
for (int row = 0; row < sourceModel()->rowCount(); ++row) { |
|
const QModelIndex pageIndex = sourceModel()->index(row, 0); |
|
for (int subRow = 0; subRow < sourceModel()->rowCount(pageIndex); ++subRow) { |
|
mIndexes.append(sourceModel()->index(subRow, 0, pageIndex)); |
|
} |
|
} |
|
} |
|
|
|
endResetModel(); |
|
} |
|
|
|
void PageGroupProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) |
|
{ |
|
Q_EMIT dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles); |
|
} |
|
|
|
void PageGroupProxyModel::groupByPage(bool value) |
|
{ |
|
if (mGroupByPage == value) { |
|
return; |
|
} |
|
|
|
mGroupByPage = value; |
|
|
|
rebuildIndexes(); |
|
} |
|
|
|
class AuthorGroupItem |
|
{ |
|
public: |
|
enum Type { Page, Author, Annotation }; |
|
|
|
explicit AuthorGroupItem(AuthorGroupItem *parent, Type type = Page, const QModelIndex &index = QModelIndex()) |
|
: mParent(parent) |
|
, mType(type) |
|
, mIndex(index) |
|
{ |
|
} |
|
|
|
~AuthorGroupItem() |
|
{ |
|
qDeleteAll(mChilds); |
|
} |
|
|
|
AuthorGroupItem(const AuthorGroupItem &) = delete; |
|
AuthorGroupItem &operator=(const AuthorGroupItem &) = delete; |
|
|
|
void appendChild(AuthorGroupItem *child) |
|
{ |
|
mChilds.append(child); |
|
} |
|
AuthorGroupItem *parent() const |
|
{ |
|
return mParent; |
|
} |
|
AuthorGroupItem *child(int row) const |
|
{ |
|
return mChilds.value(row); |
|
} |
|
int childCount() const |
|
{ |
|
return mChilds.count(); |
|
} |
|
|
|
void dump(int level = 0) |
|
{ |
|
QString prefix; |
|
for (int i = 0; i < level; ++i) { |
|
prefix += QLatin1Char(' '); |
|
} |
|
|
|
qCDebug(OkularUiDebug, "%s%s", qPrintable(prefix), (mType == Page ? "Page" : (mType == Author ? "Author" : "Annotation"))); |
|
|
|
for (int i = 0; i < mChilds.count(); ++i) { |
|
mChilds[i]->dump(level + 2); |
|
} |
|
} |
|
|
|
const AuthorGroupItem *findIndex(const QModelIndex &index) const |
|
{ |
|
if (index == mIndex) { |
|
return this; |
|
} |
|
|
|
for (int i = 0; i < mChilds.count(); ++i) { |
|
const AuthorGroupItem *item = mChilds[i]->findIndex(index); |
|
if (item) { |
|
return item; |
|
} |
|
} |
|
|
|
return nullptr; |
|
} |
|
|
|
int row() const |
|
{ |
|
return (mParent ? mParent->mChilds.indexOf(const_cast<AuthorGroupItem *>(this)) : 0); |
|
} |
|
|
|
Type type() const |
|
{ |
|
return mType; |
|
} |
|
QModelIndex index() const |
|
{ |
|
return mIndex; |
|
} |
|
|
|
void setAuthor(const QString &author) |
|
{ |
|
mAuthor = author; |
|
} |
|
QString author() const |
|
{ |
|
return mAuthor; |
|
} |
|
|
|
private: |
|
AuthorGroupItem *mParent; |
|
Type mType; |
|
QModelIndex mIndex; |
|
QList<AuthorGroupItem *> mChilds; |
|
QString mAuthor; |
|
}; |
|
|
|
class AuthorGroupProxyModel::Private |
|
{ |
|
public: |
|
explicit Private(AuthorGroupProxyModel *parent) |
|
: mParent(parent) |
|
, mRoot(nullptr) |
|
, mGroupByAuthor(false) |
|
{ |
|
} |
|
~Private() |
|
{ |
|
delete mRoot; |
|
} |
|
|
|
AuthorGroupProxyModel *mParent; |
|
AuthorGroupItem *mRoot; |
|
bool mGroupByAuthor; |
|
}; |
|
|
|
AuthorGroupProxyModel::AuthorGroupProxyModel(QObject *parent) |
|
: QAbstractProxyModel(parent) |
|
, d(new Private(this)) |
|
{ |
|
} |
|
|
|
AuthorGroupProxyModel::~AuthorGroupProxyModel() |
|
{ |
|
delete d; |
|
} |
|
|
|
int AuthorGroupProxyModel::columnCount(const QModelIndex &) const |
|
{ |
|
return 1; |
|
} |
|
|
|
int AuthorGroupProxyModel::rowCount(const QModelIndex &parentIndex) const |
|
{ |
|
AuthorGroupItem *item = nullptr; |
|
if (!parentIndex.isValid()) { |
|
item = d->mRoot; |
|
} else { |
|
item = static_cast<AuthorGroupItem *>(parentIndex.internalPointer()); |
|
} |
|
|
|
return item ? item->childCount() : 0; |
|
} |
|
|
|
QModelIndex AuthorGroupProxyModel::index(int row, int column, const QModelIndex &parentIndex) const |
|
{ |
|
if (!hasIndex(row, column, parentIndex)) { |
|
return QModelIndex(); |
|
} |
|
|
|
AuthorGroupItem *parentItem = nullptr; |
|
if (!parentIndex.isValid()) { |
|
parentItem = d->mRoot; |
|
} else { |
|
parentItem = static_cast<AuthorGroupItem *>(parentIndex.internalPointer()); |
|
} |
|
|
|
AuthorGroupItem *child = parentItem->child(row); |
|
if (child) { |
|
return createIndex(row, column, child); |
|
} else { |
|
return QModelIndex(); |
|
} |
|
} |
|
|
|
QModelIndex AuthorGroupProxyModel::parent(const QModelIndex &index) const |
|
{ |
|
if (!index.isValid()) { |
|
return QModelIndex(); |
|
} |
|
|
|
AuthorGroupItem *childItem = static_cast<AuthorGroupItem *>(index.internalPointer()); |
|
AuthorGroupItem *parentItem = childItem->parent(); |
|
|
|
if (parentItem == d->mRoot) { |
|
return QModelIndex(); |
|
} else { |
|
return createIndex(parentItem->row(), 0, parentItem); |
|
} |
|
} |
|
|
|
QModelIndex AuthorGroupProxyModel::mapFromSource(const QModelIndex &sourceIndex) const |
|
{ |
|
if (!sourceIndex.isValid()) { |
|
return QModelIndex(); |
|
} |
|
|
|
const AuthorGroupItem *item = d->mRoot->findIndex(sourceIndex); |
|
if (!item) { |
|
return QModelIndex(); |
|
} |
|
|
|
return createIndex(item->row(), 0, const_cast<AuthorGroupItem *>(item)); |
|
} |
|
|
|
QModelIndex AuthorGroupProxyModel::mapToSource(const QModelIndex &proxyIndex) const |
|
{ |
|
if (!proxyIndex.isValid()) { |
|
return QModelIndex(); |
|
} |
|
|
|
AuthorGroupItem *item = static_cast<AuthorGroupItem *>(proxyIndex.internalPointer()); |
|
|
|
return item->index(); |
|
} |
|
|
|
void AuthorGroupProxyModel::setSourceModel(QAbstractItemModel *model) |
|
{ |
|
if (sourceModel()) { |
|
disconnect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &AuthorGroupProxyModel::rebuildIndexes); |
|
disconnect(sourceModel(), &QAbstractItemModel::modelReset, this, &AuthorGroupProxyModel::rebuildIndexes); |
|
disconnect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &AuthorGroupProxyModel::rebuildIndexes); |
|
disconnect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, &AuthorGroupProxyModel::rebuildIndexes); |
|
disconnect(sourceModel(), &QAbstractItemModel::dataChanged, this, &AuthorGroupProxyModel::sourceDataChanged); |
|
} |
|
|
|
QAbstractProxyModel::setSourceModel(model); |
|
|
|
connect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &AuthorGroupProxyModel::rebuildIndexes); |
|
connect(sourceModel(), &QAbstractItemModel::modelReset, this, &AuthorGroupProxyModel::rebuildIndexes); |
|
connect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &AuthorGroupProxyModel::rebuildIndexes); |
|
connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, &AuthorGroupProxyModel::rebuildIndexes); |
|
connect(sourceModel(), &QAbstractItemModel::dataChanged, this, &AuthorGroupProxyModel::sourceDataChanged); |
|
|
|
rebuildIndexes(); |
|
} |
|
|
|
static bool isAuthorItem(const QModelIndex &index) |
|
{ |
|
if (!index.isValid()) { |
|
return false; |
|
} |
|
|
|
AuthorGroupItem *item = static_cast<AuthorGroupItem *>(index.internalPointer()); |
|
return (item->type() == AuthorGroupItem::Author); |
|
} |
|
|
|
QItemSelection AuthorGroupProxyModel::mapSelectionToSource(const QItemSelection &selection) const |
|
{ |
|
const QModelIndexList proxyIndexes = selection.indexes(); |
|
QItemSelection sourceSelection; |
|
for (const QModelIndex &proxyIndex : proxyIndexes) { |
|
if (!isAuthorItem(proxyIndex)) { |
|
sourceSelection << QItemSelectionRange(mapToSource(proxyIndex)); |
|
} |
|
} |
|
|
|
return sourceSelection; |
|
} |
|
|
|
QItemSelection AuthorGroupProxyModel::mapSelectionFromSource(const QItemSelection &selection) const |
|
{ |
|
return QAbstractProxyModel::mapSelectionFromSource(selection); |
|
} |
|
|
|
QVariant AuthorGroupProxyModel::data(const QModelIndex &proxyIndex, int role) const |
|
{ |
|
if (isAuthorItem(proxyIndex)) { |
|
AuthorGroupItem *item = static_cast<AuthorGroupItem *>(proxyIndex.internalPointer()); |
|
if (role == Qt::DisplayRole) { |
|
return item->author(); |
|
} else if (role == Qt::DecorationRole) { |
|
return QIcon::fromTheme(item->author().isEmpty() ? QStringLiteral("user-away") : QStringLiteral("user-identity")); |
|
} else { |
|
return QVariant(); |
|
} |
|
} else { |
|
return QAbstractProxyModel::data(proxyIndex, role); |
|
} |
|
} |
|
|
|
QMap<int, QVariant> AuthorGroupProxyModel::itemData(const QModelIndex &index) const |
|
{ |
|
if (isAuthorItem(index)) { |
|
return QMap<int, QVariant>(); |
|
} else { |
|
return QAbstractProxyModel::itemData(index); |
|
} |
|
} |
|
|
|
Qt::ItemFlags AuthorGroupProxyModel::flags(const QModelIndex &index) const |
|
{ |
|
if (isAuthorItem(index)) { |
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable; |
|
} else { |
|
return QAbstractProxyModel::flags(index); |
|
} |
|
} |
|
|
|
void AuthorGroupProxyModel::groupByAuthor(bool value) |
|
{ |
|
if (d->mGroupByAuthor == value) { |
|
return; |
|
} |
|
|
|
d->mGroupByAuthor = value; |
|
|
|
rebuildIndexes(); |
|
} |
|
|
|
void AuthorGroupProxyModel::rebuildIndexes() |
|
{ |
|
beginResetModel(); |
|
delete d->mRoot; |
|
d->mRoot = new AuthorGroupItem(nullptr); |
|
|
|
if (d->mGroupByAuthor) { |
|
QMap<QString, AuthorGroupItem *> authorMap; |
|
|
|
for (int row = 0; row < sourceModel()->rowCount(); ++row) { |
|
const QModelIndex idx = sourceModel()->index(row, 0); |
|
const QString author = sourceModel()->data(idx, AnnotationModel::AuthorRole).toString(); |
|
if (!author.isEmpty()) { |
|
// We have the annotations as top-level, so introduce authors as new |
|
// top-levels and append the annotations |
|
AuthorGroupItem *authorItem = authorMap.value(author, nullptr); |
|
if (!authorItem) { |
|
authorItem = new AuthorGroupItem(d->mRoot, AuthorGroupItem::Author); |
|
authorItem->setAuthor(author); |
|
|
|
// Add item to tree |
|
d->mRoot->appendChild(authorItem); |
|
|
|
// Insert to lookup list |
|
authorMap.insert(author, authorItem); |
|
} |
|
|
|
AuthorGroupItem *item = new AuthorGroupItem(authorItem, AuthorGroupItem::Annotation, idx); |
|
authorItem->appendChild(item); |
|
} else { |
|
// We have the pages as top-level, so we use them as top-level, append the |
|
// authors for all annotations of the page, and then the annotations themself |
|
AuthorGroupItem *pageItem = new AuthorGroupItem(d->mRoot, AuthorGroupItem::Page, idx); |
|
d->mRoot->appendChild(pageItem); |
|
|
|
// First collect all authors... |
|
QMap<QString, AuthorGroupItem *> pageAuthorMap; |
|
for (int subRow = 0; subRow < sourceModel()->rowCount(idx); ++subRow) { |
|
const QModelIndex annIdx = sourceModel()->index(subRow, 0, idx); |
|
const QString author = sourceModel()->data(annIdx, AnnotationModel::AuthorRole).toString(); |
|
|
|
AuthorGroupItem *authorItem = pageAuthorMap.value(author, nullptr); |
|
if (!authorItem) { |
|
authorItem = new AuthorGroupItem(pageItem, AuthorGroupItem::Author); |
|
authorItem->setAuthor(author); |
|
|
|
// Add item to tree |
|
pageItem->appendChild(authorItem); |
|
|
|
// Insert to lookup list |
|
pageAuthorMap.insert(author, authorItem); |
|
} |
|
|
|
AuthorGroupItem *item = new AuthorGroupItem(authorItem, AuthorGroupItem::Annotation, annIdx); |
|
authorItem->appendChild(item); |
|
} |
|
} |
|
} |
|
} else { |
|
for (int row = 0; row < sourceModel()->rowCount(); ++row) { |
|
const QModelIndex idx = sourceModel()->index(row, 0); |
|
const QString author = sourceModel()->data(idx, AnnotationModel::AuthorRole).toString(); |
|
if (!author.isEmpty()) { |
|
// We have the annotations as top-level items |
|
AuthorGroupItem *item = new AuthorGroupItem(d->mRoot, AuthorGroupItem::Annotation, idx); |
|
d->mRoot->appendChild(item); |
|
} else { |
|
// We have the pages as top-level items |
|
AuthorGroupItem *pageItem = new AuthorGroupItem(d->mRoot, AuthorGroupItem::Page, idx); |
|
d->mRoot->appendChild(pageItem); |
|
|
|
// Append all annotations as second-level |
|
for (int subRow = 0; subRow < sourceModel()->rowCount(idx); ++subRow) { |
|
const QModelIndex subIdx = sourceModel()->index(subRow, 0, idx); |
|
AuthorGroupItem *item = new AuthorGroupItem(pageItem, AuthorGroupItem::Annotation, subIdx); |
|
pageItem->appendChild(item); |
|
} |
|
} |
|
} |
|
} |
|
|
|
endResetModel(); |
|
} |
|
|
|
void AuthorGroupProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) |
|
{ |
|
Q_EMIT dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles); |
|
} |
|
|
|
#include "moc_annotationproxymodels.cpp"
|
|
|