File indexing completed on 2024-04-28 15:51:39
0001 /* 0002 SPDX-FileCopyrightText: 2007 Tobias Koenig <tokoe@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "annotationproxymodels.h" 0008 0009 #include <QItemSelection> 0010 #include <QList> 0011 0012 #include <QIcon> 0013 0014 #include "annotationmodel.h" 0015 #include "gui/debug_ui.h" 0016 0017 static quint32 mixIndex(int row, int column) 0018 { 0019 return (row << 4) | column; 0020 } 0021 0022 PageFilterProxyModel::PageFilterProxyModel(QObject *parent) 0023 : QSortFilterProxyModel(parent) 0024 , mGroupByCurrentPage(false) 0025 , mCurrentPage(-1) 0026 { 0027 setDynamicSortFilter(true); 0028 } 0029 0030 void PageFilterProxyModel::groupByCurrentPage(bool value) 0031 { 0032 if (mGroupByCurrentPage == value) { 0033 return; 0034 } 0035 0036 mGroupByCurrentPage = value; 0037 0038 invalidateFilter(); 0039 } 0040 0041 void PageFilterProxyModel::setCurrentPage(int page) 0042 { 0043 if (mCurrentPage == page) { 0044 return; 0045 } 0046 0047 mCurrentPage = page; 0048 0049 // no need to invalidate when we're not showing the current page only 0050 if (!mGroupByCurrentPage) { 0051 return; 0052 } 0053 0054 invalidateFilter(); 0055 } 0056 0057 bool PageFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &sourceParent) const 0058 { 0059 if (!mGroupByCurrentPage) { 0060 return true; 0061 } 0062 0063 const QModelIndex pageIndex = sourceModel()->index(row, 0, sourceParent); 0064 int page = sourceModel()->data(pageIndex, AnnotationModel::PageRole).toInt(); 0065 0066 return (page == mCurrentPage); 0067 } 0068 0069 PageGroupProxyModel::PageGroupProxyModel(QObject *parent) 0070 : QAbstractProxyModel(parent) 0071 , mGroupByPage(false) 0072 { 0073 } 0074 0075 int PageGroupProxyModel::columnCount(const QModelIndex &parentIndex) const 0076 { 0077 // For top-level and second level we have always only one column 0078 if (mGroupByPage) { 0079 if (parentIndex.isValid()) { 0080 if (parentIndex.parent().isValid()) { 0081 return 0; 0082 } else { 0083 return 1; // second-level 0084 } 0085 } else { 0086 return 1; // top-level 0087 } 0088 } else { 0089 if (!parentIndex.isValid()) { // top-level 0090 return 1; 0091 } else { 0092 return 0; 0093 } 0094 } 0095 return 1; 0096 } 0097 0098 int PageGroupProxyModel::rowCount(const QModelIndex &parentIndex) const 0099 { 0100 if (mGroupByPage) { 0101 if (parentIndex.isValid()) { 0102 if (parentIndex.parent().isValid()) { 0103 return 0; 0104 } else { 0105 return mTreeIndexes[parentIndex.row()].second.count(); // second-level 0106 } 0107 } else { 0108 return mTreeIndexes.count(); // top-level 0109 } 0110 } else { 0111 if (!parentIndex.isValid()) { // top-level 0112 return mIndexes.count(); 0113 } else { 0114 return 0; 0115 } 0116 } 0117 } 0118 0119 QModelIndex PageGroupProxyModel::index(int row, int column, const QModelIndex &parentIndex) const 0120 { 0121 if (row < 0 || column != 0) { 0122 return QModelIndex(); 0123 } 0124 0125 if (mGroupByPage) { 0126 if (parentIndex.isValid()) { 0127 if (parentIndex.row() >= 0 && parentIndex.row() < mTreeIndexes.count() && row < mTreeIndexes[parentIndex.row()].second.count()) { 0128 return createIndex(row, column, qint32(parentIndex.row() + 1)); 0129 } else { 0130 return QModelIndex(); 0131 } 0132 } else { 0133 if (row < mTreeIndexes.count()) { 0134 return createIndex(row, column); 0135 } else { 0136 return QModelIndex(); 0137 } 0138 } 0139 } else { 0140 if (row < mIndexes.count()) { 0141 return createIndex(row, column, mixIndex(parentIndex.row(), parentIndex.column())); 0142 } else { 0143 return QModelIndex(); 0144 } 0145 } 0146 } 0147 0148 QModelIndex PageGroupProxyModel::parent(const QModelIndex &idx) const 0149 { 0150 if (mGroupByPage) { 0151 if (idx.internalId() == 0) { // top-level 0152 return QModelIndex(); 0153 } else { 0154 return index(idx.internalId() - 1, idx.column()); 0155 } 0156 } else { 0157 // We have only top-level items 0158 return QModelIndex(); 0159 } 0160 } 0161 0162 QModelIndex PageGroupProxyModel::mapFromSource(const QModelIndex &sourceIndex) const 0163 { 0164 if (mGroupByPage) { 0165 if (sourceIndex.parent().isValid()) { 0166 return index(sourceIndex.row(), sourceIndex.column(), sourceIndex.parent()); 0167 } else { 0168 return index(sourceIndex.row(), sourceIndex.column()); 0169 } 0170 } else { 0171 for (int i = 0; i < mIndexes.count(); ++i) { 0172 if (mIndexes[i] == sourceIndex) { 0173 return index(i, 0); 0174 } 0175 } 0176 0177 return QModelIndex(); 0178 } 0179 } 0180 0181 QModelIndex PageGroupProxyModel::mapToSource(const QModelIndex &proxyIndex) const 0182 { 0183 if (!proxyIndex.isValid()) { 0184 return QModelIndex(); 0185 } 0186 0187 if (mGroupByPage) { 0188 if (proxyIndex.internalId() == 0) { 0189 if (proxyIndex.row() >= mTreeIndexes.count() || proxyIndex.row() < 0) { 0190 return QModelIndex(); 0191 } 0192 0193 return mTreeIndexes[proxyIndex.row()].first; 0194 } else { 0195 if (qint32(proxyIndex.internalId()) - 1 >= mTreeIndexes.count() || proxyIndex.row() >= mTreeIndexes[proxyIndex.internalId() - 1].second.count()) { 0196 return QModelIndex(); 0197 } 0198 0199 return mTreeIndexes[proxyIndex.internalId() - 1].second[proxyIndex.row()]; 0200 } 0201 } else { 0202 if (proxyIndex.column() > 0 || proxyIndex.row() >= mIndexes.count()) { 0203 return QModelIndex(); 0204 } else { 0205 return mIndexes[proxyIndex.row()]; 0206 } 0207 } 0208 } 0209 0210 void PageGroupProxyModel::setSourceModel(QAbstractItemModel *model) 0211 { 0212 if (sourceModel()) { 0213 disconnect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &PageGroupProxyModel::rebuildIndexes); 0214 disconnect(sourceModel(), &QAbstractItemModel::modelReset, this, &PageGroupProxyModel::rebuildIndexes); 0215 disconnect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &PageGroupProxyModel::rebuildIndexes); 0216 disconnect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, &PageGroupProxyModel::rebuildIndexes); 0217 disconnect(sourceModel(), &QAbstractItemModel::dataChanged, this, &PageGroupProxyModel::sourceDataChanged); 0218 } 0219 0220 QAbstractProxyModel::setSourceModel(model); 0221 0222 connect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &PageGroupProxyModel::rebuildIndexes); 0223 connect(sourceModel(), &QAbstractItemModel::modelReset, this, &PageGroupProxyModel::rebuildIndexes); 0224 connect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &PageGroupProxyModel::rebuildIndexes); 0225 connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, &PageGroupProxyModel::rebuildIndexes); 0226 connect(sourceModel(), &QAbstractItemModel::dataChanged, this, &PageGroupProxyModel::sourceDataChanged); 0227 0228 rebuildIndexes(); 0229 } 0230 0231 void PageGroupProxyModel::rebuildIndexes() 0232 { 0233 beginResetModel(); 0234 0235 if (mGroupByPage) { 0236 mTreeIndexes.clear(); 0237 0238 for (int row = 0; row < sourceModel()->rowCount(); ++row) { 0239 const QModelIndex pageIndex = sourceModel()->index(row, 0); 0240 0241 QList<QModelIndex> itemIndexes; 0242 for (int subRow = 0; subRow < sourceModel()->rowCount(pageIndex); ++subRow) { 0243 itemIndexes.append(sourceModel()->index(subRow, 0, pageIndex)); 0244 } 0245 0246 mTreeIndexes.append(QPair<QModelIndex, QList<QModelIndex>>(pageIndex, itemIndexes)); 0247 } 0248 } else { 0249 mIndexes.clear(); 0250 0251 for (int row = 0; row < sourceModel()->rowCount(); ++row) { 0252 const QModelIndex pageIndex = sourceModel()->index(row, 0); 0253 for (int subRow = 0; subRow < sourceModel()->rowCount(pageIndex); ++subRow) { 0254 mIndexes.append(sourceModel()->index(subRow, 0, pageIndex)); 0255 } 0256 } 0257 } 0258 0259 endResetModel(); 0260 } 0261 0262 void PageGroupProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) 0263 { 0264 Q_EMIT dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles); 0265 } 0266 0267 void PageGroupProxyModel::groupByPage(bool value) 0268 { 0269 if (mGroupByPage == value) { 0270 return; 0271 } 0272 0273 mGroupByPage = value; 0274 0275 rebuildIndexes(); 0276 } 0277 0278 class AuthorGroupItem 0279 { 0280 public: 0281 enum Type { Page, Author, Annotation }; 0282 0283 explicit AuthorGroupItem(AuthorGroupItem *parent, Type type = Page, const QModelIndex &index = QModelIndex()) 0284 : mParent(parent) 0285 , mType(type) 0286 , mIndex(index) 0287 { 0288 } 0289 0290 ~AuthorGroupItem() 0291 { 0292 qDeleteAll(mChilds); 0293 } 0294 0295 AuthorGroupItem(const AuthorGroupItem &) = delete; 0296 AuthorGroupItem &operator=(const AuthorGroupItem &) = delete; 0297 0298 void appendChild(AuthorGroupItem *child) 0299 { 0300 mChilds.append(child); 0301 } 0302 AuthorGroupItem *parent() const 0303 { 0304 return mParent; 0305 } 0306 AuthorGroupItem *child(int row) const 0307 { 0308 return mChilds.value(row); 0309 } 0310 int childCount() const 0311 { 0312 return mChilds.count(); 0313 } 0314 0315 void dump(int level = 0) 0316 { 0317 QString prefix; 0318 for (int i = 0; i < level; ++i) { 0319 prefix += QLatin1Char(' '); 0320 } 0321 0322 qCDebug(OkularUiDebug, "%s%s", qPrintable(prefix), (mType == Page ? "Page" : (mType == Author ? "Author" : "Annotation"))); 0323 0324 for (int i = 0; i < mChilds.count(); ++i) { 0325 mChilds[i]->dump(level + 2); 0326 } 0327 } 0328 0329 const AuthorGroupItem *findIndex(const QModelIndex &index) const 0330 { 0331 if (index == mIndex) { 0332 return this; 0333 } 0334 0335 for (int i = 0; i < mChilds.count(); ++i) { 0336 const AuthorGroupItem *item = mChilds[i]->findIndex(index); 0337 if (item) { 0338 return item; 0339 } 0340 } 0341 0342 return nullptr; 0343 } 0344 0345 int row() const 0346 { 0347 return (mParent ? mParent->mChilds.indexOf(const_cast<AuthorGroupItem *>(this)) : 0); 0348 } 0349 0350 Type type() const 0351 { 0352 return mType; 0353 } 0354 QModelIndex index() const 0355 { 0356 return mIndex; 0357 } 0358 0359 void setAuthor(const QString &author) 0360 { 0361 mAuthor = author; 0362 } 0363 QString author() const 0364 { 0365 return mAuthor; 0366 } 0367 0368 private: 0369 AuthorGroupItem *mParent; 0370 Type mType; 0371 QModelIndex mIndex; 0372 QList<AuthorGroupItem *> mChilds; 0373 QString mAuthor; 0374 }; 0375 0376 class AuthorGroupProxyModel::Private 0377 { 0378 public: 0379 explicit Private(AuthorGroupProxyModel *parent) 0380 : mParent(parent) 0381 , mRoot(nullptr) 0382 , mGroupByAuthor(false) 0383 { 0384 } 0385 ~Private() 0386 { 0387 delete mRoot; 0388 } 0389 0390 AuthorGroupProxyModel *mParent; 0391 AuthorGroupItem *mRoot; 0392 bool mGroupByAuthor; 0393 }; 0394 0395 AuthorGroupProxyModel::AuthorGroupProxyModel(QObject *parent) 0396 : QAbstractProxyModel(parent) 0397 , d(new Private(this)) 0398 { 0399 } 0400 0401 AuthorGroupProxyModel::~AuthorGroupProxyModel() 0402 { 0403 delete d; 0404 } 0405 0406 int AuthorGroupProxyModel::columnCount(const QModelIndex &) const 0407 { 0408 return 1; 0409 } 0410 0411 int AuthorGroupProxyModel::rowCount(const QModelIndex &parentIndex) const 0412 { 0413 AuthorGroupItem *item = nullptr; 0414 if (!parentIndex.isValid()) { 0415 item = d->mRoot; 0416 } else { 0417 item = static_cast<AuthorGroupItem *>(parentIndex.internalPointer()); 0418 } 0419 0420 return item ? item->childCount() : 0; 0421 } 0422 0423 QModelIndex AuthorGroupProxyModel::index(int row, int column, const QModelIndex &parentIndex) const 0424 { 0425 if (!hasIndex(row, column, parentIndex)) { 0426 return QModelIndex(); 0427 } 0428 0429 AuthorGroupItem *parentItem = nullptr; 0430 if (!parentIndex.isValid()) { 0431 parentItem = d->mRoot; 0432 } else { 0433 parentItem = static_cast<AuthorGroupItem *>(parentIndex.internalPointer()); 0434 } 0435 0436 AuthorGroupItem *child = parentItem->child(row); 0437 if (child) { 0438 return createIndex(row, column, child); 0439 } else { 0440 return QModelIndex(); 0441 } 0442 } 0443 0444 QModelIndex AuthorGroupProxyModel::parent(const QModelIndex &index) const 0445 { 0446 if (!index.isValid()) { 0447 return QModelIndex(); 0448 } 0449 0450 AuthorGroupItem *childItem = static_cast<AuthorGroupItem *>(index.internalPointer()); 0451 AuthorGroupItem *parentItem = childItem->parent(); 0452 0453 if (parentItem == d->mRoot) { 0454 return QModelIndex(); 0455 } else { 0456 return createIndex(parentItem->row(), 0, parentItem); 0457 } 0458 } 0459 0460 QModelIndex AuthorGroupProxyModel::mapFromSource(const QModelIndex &sourceIndex) const 0461 { 0462 if (!sourceIndex.isValid()) { 0463 return QModelIndex(); 0464 } 0465 0466 const AuthorGroupItem *item = d->mRoot->findIndex(sourceIndex); 0467 if (!item) { 0468 return QModelIndex(); 0469 } 0470 0471 return createIndex(item->row(), 0, const_cast<AuthorGroupItem *>(item)); 0472 } 0473 0474 QModelIndex AuthorGroupProxyModel::mapToSource(const QModelIndex &proxyIndex) const 0475 { 0476 if (!proxyIndex.isValid()) { 0477 return QModelIndex(); 0478 } 0479 0480 const AuthorGroupItem *item = static_cast<AuthorGroupItem *>(proxyIndex.internalPointer()); 0481 0482 return item->index(); 0483 } 0484 0485 void AuthorGroupProxyModel::setSourceModel(QAbstractItemModel *model) 0486 { 0487 if (sourceModel()) { 0488 disconnect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &AuthorGroupProxyModel::rebuildIndexes); 0489 disconnect(sourceModel(), &QAbstractItemModel::modelReset, this, &AuthorGroupProxyModel::rebuildIndexes); 0490 disconnect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &AuthorGroupProxyModel::rebuildIndexes); 0491 disconnect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, &AuthorGroupProxyModel::rebuildIndexes); 0492 disconnect(sourceModel(), &QAbstractItemModel::dataChanged, this, &AuthorGroupProxyModel::sourceDataChanged); 0493 } 0494 0495 QAbstractProxyModel::setSourceModel(model); 0496 0497 connect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &AuthorGroupProxyModel::rebuildIndexes); 0498 connect(sourceModel(), &QAbstractItemModel::modelReset, this, &AuthorGroupProxyModel::rebuildIndexes); 0499 connect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &AuthorGroupProxyModel::rebuildIndexes); 0500 connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, &AuthorGroupProxyModel::rebuildIndexes); 0501 connect(sourceModel(), &QAbstractItemModel::dataChanged, this, &AuthorGroupProxyModel::sourceDataChanged); 0502 0503 rebuildIndexes(); 0504 } 0505 0506 static bool isAuthorItem(const QModelIndex &index) 0507 { 0508 if (!index.isValid()) { 0509 return false; 0510 } 0511 0512 const AuthorGroupItem *item = static_cast<AuthorGroupItem *>(index.internalPointer()); 0513 return (item->type() == AuthorGroupItem::Author); 0514 } 0515 0516 QItemSelection AuthorGroupProxyModel::mapSelectionToSource(const QItemSelection &selection) const 0517 { 0518 const QModelIndexList proxyIndexes = selection.indexes(); 0519 QItemSelection sourceSelection; 0520 for (const QModelIndex &proxyIndex : proxyIndexes) { 0521 if (!isAuthorItem(proxyIndex)) { 0522 sourceSelection << QItemSelectionRange(mapToSource(proxyIndex)); 0523 } 0524 } 0525 0526 return sourceSelection; 0527 } 0528 0529 QItemSelection AuthorGroupProxyModel::mapSelectionFromSource(const QItemSelection &selection) const 0530 { 0531 return QAbstractProxyModel::mapSelectionFromSource(selection); 0532 } 0533 0534 QVariant AuthorGroupProxyModel::data(const QModelIndex &proxyIndex, int role) const 0535 { 0536 if (isAuthorItem(proxyIndex)) { 0537 const AuthorGroupItem *item = static_cast<AuthorGroupItem *>(proxyIndex.internalPointer()); 0538 if (role == Qt::DisplayRole) { 0539 return item->author(); 0540 } else if (role == Qt::DecorationRole) { 0541 return QIcon::fromTheme(item->author().isEmpty() ? QStringLiteral("user-away") : QStringLiteral("user-identity")); 0542 } else { 0543 return QVariant(); 0544 } 0545 } else { 0546 return QAbstractProxyModel::data(proxyIndex, role); 0547 } 0548 } 0549 0550 QMap<int, QVariant> AuthorGroupProxyModel::itemData(const QModelIndex &index) const 0551 { 0552 if (isAuthorItem(index)) { 0553 return QMap<int, QVariant>(); 0554 } else { 0555 return QAbstractProxyModel::itemData(index); 0556 } 0557 } 0558 0559 Qt::ItemFlags AuthorGroupProxyModel::flags(const QModelIndex &index) const 0560 { 0561 if (isAuthorItem(index)) { 0562 return Qt::ItemIsEnabled | Qt::ItemIsSelectable; 0563 } else { 0564 return QAbstractProxyModel::flags(index); 0565 } 0566 } 0567 0568 void AuthorGroupProxyModel::groupByAuthor(bool value) 0569 { 0570 if (d->mGroupByAuthor == value) { 0571 return; 0572 } 0573 0574 d->mGroupByAuthor = value; 0575 0576 rebuildIndexes(); 0577 } 0578 0579 void AuthorGroupProxyModel::rebuildIndexes() 0580 { 0581 beginResetModel(); 0582 delete d->mRoot; 0583 d->mRoot = new AuthorGroupItem(nullptr); 0584 0585 if (d->mGroupByAuthor) { 0586 QMap<QString, AuthorGroupItem *> authorMap; 0587 0588 for (int row = 0; row < sourceModel()->rowCount(); ++row) { 0589 const QModelIndex idx = sourceModel()->index(row, 0); 0590 const QString author = sourceModel()->data(idx, AnnotationModel::AuthorRole).toString(); 0591 if (!author.isEmpty()) { 0592 // We have the annotations as top-level, so introduce authors as new 0593 // top-levels and append the annotations 0594 AuthorGroupItem *authorItem = authorMap.value(author, nullptr); 0595 if (!authorItem) { 0596 authorItem = new AuthorGroupItem(d->mRoot, AuthorGroupItem::Author); 0597 authorItem->setAuthor(author); 0598 0599 // Add item to tree 0600 d->mRoot->appendChild(authorItem); 0601 0602 // Insert to lookup list 0603 authorMap.insert(author, authorItem); 0604 } 0605 0606 AuthorGroupItem *item = new AuthorGroupItem(authorItem, AuthorGroupItem::Annotation, idx); 0607 authorItem->appendChild(item); 0608 } else { 0609 // We have the pages as top-level, so we use them as top-level, append the 0610 // authors for all annotations of the page, and then the annotations themself 0611 AuthorGroupItem *pageItem = new AuthorGroupItem(d->mRoot, AuthorGroupItem::Page, idx); 0612 d->mRoot->appendChild(pageItem); 0613 0614 // First collect all authors... 0615 QMap<QString, AuthorGroupItem *> pageAuthorMap; 0616 for (int subRow = 0; subRow < sourceModel()->rowCount(idx); ++subRow) { 0617 const QModelIndex annIdx = sourceModel()->index(subRow, 0, idx); 0618 const QString pageAuthor = sourceModel()->data(annIdx, AnnotationModel::AuthorRole).toString(); 0619 0620 AuthorGroupItem *authorItem = pageAuthorMap.value(pageAuthor, nullptr); 0621 if (!authorItem) { 0622 authorItem = new AuthorGroupItem(pageItem, AuthorGroupItem::Author); 0623 authorItem->setAuthor(pageAuthor); 0624 0625 // Add item to tree 0626 pageItem->appendChild(authorItem); 0627 0628 // Insert to lookup list 0629 pageAuthorMap.insert(pageAuthor, authorItem); 0630 } 0631 0632 AuthorGroupItem *item = new AuthorGroupItem(authorItem, AuthorGroupItem::Annotation, annIdx); 0633 authorItem->appendChild(item); 0634 } 0635 } 0636 } 0637 } else { 0638 for (int row = 0; row < sourceModel()->rowCount(); ++row) { 0639 const QModelIndex idx = sourceModel()->index(row, 0); 0640 const QString author = sourceModel()->data(idx, AnnotationModel::AuthorRole).toString(); 0641 if (!author.isEmpty()) { 0642 // We have the annotations as top-level items 0643 AuthorGroupItem *item = new AuthorGroupItem(d->mRoot, AuthorGroupItem::Annotation, idx); 0644 d->mRoot->appendChild(item); 0645 } else { 0646 // We have the pages as top-level items 0647 AuthorGroupItem *pageItem = new AuthorGroupItem(d->mRoot, AuthorGroupItem::Page, idx); 0648 d->mRoot->appendChild(pageItem); 0649 0650 // Append all annotations as second-level 0651 for (int subRow = 0; subRow < sourceModel()->rowCount(idx); ++subRow) { 0652 const QModelIndex subIdx = sourceModel()->index(subRow, 0, idx); 0653 AuthorGroupItem *item = new AuthorGroupItem(pageItem, AuthorGroupItem::Annotation, subIdx); 0654 pageItem->appendChild(item); 0655 } 0656 } 0657 } 0658 } 0659 0660 endResetModel(); 0661 } 0662 0663 void AuthorGroupProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) 0664 { 0665 Q_EMIT dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles); 0666 } 0667 0668 #include "moc_annotationproxymodels.cpp"