File indexing completed on 2024-04-28 04:32:37
0001 /* 0002 SPDX-FileCopyrightText: 2006 Pino Toscano <pino@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "bookmarkmanager.h" 0008 0009 // qt/kde includes 0010 #include <KBookmarkAction> 0011 #include <KBookmarkManager> 0012 #include <KBookmarkMenu> 0013 #include <KBookmarkOwner> 0014 #include <QDebug> 0015 #include <QFileInfo> 0016 #include <QGuiApplication> 0017 #include <QHash> 0018 #include <QSet> 0019 #include <QStandardPaths> 0020 #include <QUrl> 0021 0022 // local includes 0023 #include "document_p.h" 0024 #include "observer.h" 0025 0026 using namespace Okular; 0027 0028 #define foreachObserver(cmd) \ 0029 { \ 0030 QSet<DocumentObserver *>::const_iterator it = d->document->m_observers.constBegin(), end = d->document->m_observers.constEnd(); \ 0031 for (; it != end; ++it) { \ 0032 (*it)->cmd; \ 0033 } \ 0034 } 0035 0036 #define foreachObserverD(cmd) \ 0037 { \ 0038 QSet<DocumentObserver *>::const_iterator it = document->m_observers.constBegin(), end = document->m_observers.constEnd(); \ 0039 for (; it != end; ++it) { \ 0040 (*it)->cmd; \ 0041 } \ 0042 } 0043 0044 class OkularBookmarkAction : public KBookmarkAction 0045 { 0046 Q_OBJECT 0047 public: 0048 OkularBookmarkAction(const Okular::DocumentViewport &vp, const KBookmark &bk, KBookmarkOwner *owner, QObject *parent) 0049 : KBookmarkAction(bk, owner, parent) 0050 { 0051 if (vp.isValid()) { 0052 setText(QString::number(vp.pageNumber + 1) + QStringLiteral(" - ") + text()); 0053 } 0054 setProperty("pageNumber", vp.pageNumber + 1); 0055 setProperty("htmlRef", bk.url().fragment(QUrl::FullyDecoded)); 0056 } 0057 0058 inline int pageNumber() const 0059 { 0060 return property("pageNumber").toInt(); 0061 } 0062 0063 inline QString htmlRef() const 0064 { 0065 return property("htmlRef").toString(); 0066 } 0067 }; 0068 0069 static inline bool documentViewportFuzzyCompare(const DocumentViewport &vp1, const DocumentViewport &vp2) 0070 { 0071 bool equal = vp1.isValid() && vp2.isValid() && (vp1.pageNumber == vp2.pageNumber) && (vp1.rePos.pos == vp2.rePos.pos); 0072 0073 if (!equal) { 0074 return false; 0075 } 0076 0077 if (qAbs(vp1.rePos.normalizedX - vp2.rePos.normalizedX) >= 0.000001) { 0078 return false; 0079 } 0080 0081 if (qAbs(vp1.rePos.normalizedY - vp2.rePos.normalizedY) >= 0.000001) { 0082 return false; 0083 } 0084 0085 return true; 0086 } 0087 0088 static inline bool bookmarkLessThan(const KBookmark &b1, const KBookmark &b2) 0089 { 0090 DocumentViewport vp1(b1.url().fragment(QUrl::FullyDecoded)); 0091 DocumentViewport vp2(b2.url().fragment(QUrl::FullyDecoded)); 0092 0093 return vp1 < vp2; 0094 } 0095 0096 static inline bool okularBookmarkActionLessThan(QAction *a1, QAction *a2) 0097 { 0098 DocumentViewport vp1(static_cast<OkularBookmarkAction *>(a1)->htmlRef()); 0099 DocumentViewport vp2(static_cast<OkularBookmarkAction *>(a2)->htmlRef()); 0100 0101 return vp1 < vp2; 0102 } 0103 0104 static QUrl mostCanonicalUrl(const QUrl &url) 0105 { 0106 if (!url.isLocalFile()) { 0107 return url; 0108 } 0109 0110 const QFileInfo fi(url.toLocalFile()); 0111 return QUrl::fromLocalFile(fi.canonicalFilePath()); 0112 } 0113 0114 class BookmarkManager::Private : public KBookmarkOwner 0115 { 0116 public: 0117 explicit Private(BookmarkManager *qq) 0118 : KBookmarkOwner() 0119 , q(qq) 0120 , document(nullptr) 0121 , file(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/okular/bookmarks.xml")) 0122 , manager(KBookmarkManager(file)) 0123 { 0124 } 0125 0126 ~Private() override 0127 { 0128 knownFiles.clear(); 0129 // no need to delete the manager, it's automatically done by KBookmarkManager 0130 // delete manager; 0131 } 0132 0133 Private(const Private &) = delete; 0134 Private &operator=(const Private &) = delete; 0135 0136 QUrl currentUrl() const override; 0137 QString currentTitle() const override; 0138 bool enableOption(BookmarkOption option) const override; 0139 void openBookmark(const KBookmark &bm, Qt::MouseButtons, Qt::KeyboardModifiers) override; 0140 0141 QHash<QUrl, QString>::iterator bookmarkFind(const QUrl &url, bool doCreate, KBookmarkGroup *result = nullptr); 0142 0143 // slots 0144 void _o_changed(const QString &groupAddress); 0145 0146 BookmarkManager *q; 0147 QUrl url; 0148 QHash<int, int> urlBookmarks; 0149 DocumentPrivate *document; 0150 QString file; 0151 KBookmarkManager manager; 0152 QHash<QUrl, QString> knownFiles; 0153 }; 0154 0155 static inline QUrl urlForGroup(const KBookmark &group) 0156 { 0157 if (group.url().isValid()) { 0158 return group.url(); 0159 } else { 0160 return QUrl::fromUserInput(group.fullText()); 0161 } 0162 } 0163 0164 BookmarkManager::BookmarkManager(DocumentPrivate *document) 0165 : QObject(document->m_parent) 0166 , d(new Private(this)) 0167 { 0168 setObjectName(QStringLiteral("Okular::BookmarkManager")); 0169 0170 d->document = document; 0171 0172 connect(&d->manager, &KBookmarkManager::changed, this, [this](const QString &groupAddress) { d->_o_changed(groupAddress); }); 0173 } 0174 0175 BookmarkManager::~BookmarkManager() 0176 { 0177 delete d; 0178 } 0179 0180 // BEGIN Reimplementations from KBookmarkOwner 0181 QUrl BookmarkManager::Private::currentUrl() const 0182 { 0183 return url; 0184 } 0185 0186 QString BookmarkManager::Private::currentTitle() const 0187 { 0188 return url.toDisplayString(); 0189 } 0190 0191 bool BookmarkManager::Private::enableOption(BookmarkOption option) const 0192 { 0193 Q_UNUSED(option) 0194 return false; 0195 } 0196 0197 void BookmarkManager::Private::openBookmark(const KBookmark &bm, Qt::MouseButtons, Qt::KeyboardModifiers) 0198 { 0199 Q_EMIT q->openUrl(bm.url()); 0200 } 0201 // END Reimplementations from KBookmarkOwner 0202 0203 void BookmarkManager::Private::_o_changed(const QString &groupAddress) 0204 { 0205 if (groupAddress.isEmpty()) { 0206 return; 0207 } 0208 0209 QUrl referurl; 0210 // first, try to find the bookmark group whom change notification was just received 0211 QHash<QUrl, QString>::iterator it = knownFiles.begin(), itEnd = knownFiles.end(); 0212 for (; it != itEnd; ++it) { 0213 if (it.value() == groupAddress) { 0214 referurl = it.key(); 0215 knownFiles.erase(it); 0216 break; 0217 } 0218 } 0219 if (!referurl.isValid()) { 0220 const KBookmark bm = manager.findByAddress(groupAddress); 0221 // better be safe than sorry 0222 if (bm.isNull()) { 0223 return; 0224 } 0225 Q_ASSERT(bm.isGroup()); 0226 referurl = urlForGroup(bm); 0227 } 0228 Q_ASSERT(referurl.isValid()); 0229 Q_EMIT q->bookmarksChanged(referurl); 0230 // case for the url representing the current document 0231 // (this might happen if the same document is open in another place; 0232 // in such case, make really sure to be in sync) 0233 if (referurl == url) { 0234 // save the old bookmarks for the current url 0235 const QHash<int, int> oldUrlBookmarks = urlBookmarks; 0236 // set the same url again, so we reload the information we have about it 0237 q->setUrl(referurl); 0238 // then notify the observers about the changes in the bookmarks 0239 for (int i = 0; i < qMax(oldUrlBookmarks.size(), urlBookmarks.size()); i++) { 0240 bool oldContains = oldUrlBookmarks.contains(i) && oldUrlBookmarks[i] > 0; 0241 bool curContains = urlBookmarks.contains(i) && urlBookmarks[i] > 0; 0242 0243 if (oldContains != curContains) { 0244 foreachObserverD(notifyPageChanged(i, DocumentObserver::Bookmark)); 0245 } else if (oldContains && oldUrlBookmarks[i] != urlBookmarks[i]) { 0246 foreachObserverD(notifyPageChanged(i, DocumentObserver::Bookmark)); 0247 } 0248 } 0249 } 0250 Q_EMIT q->saved(); 0251 } 0252 0253 QList<QUrl> BookmarkManager::files() const 0254 { 0255 QList<QUrl> ret; 0256 KBookmarkGroup group = d->manager.root(); 0257 for (KBookmark bm = group.first(); !bm.isNull(); bm = group.next(bm)) { 0258 if (bm.isSeparator() || !bm.isGroup()) { 0259 continue; 0260 } 0261 0262 ret.append(urlForGroup(bm)); 0263 } 0264 return ret; 0265 } 0266 0267 KBookmark::List BookmarkManager::bookmarks(const QUrl &documentUrl) const 0268 { 0269 const QUrl url = mostCanonicalUrl(documentUrl); 0270 KBookmark::List ret; 0271 KBookmarkGroup group = d->manager.root(); 0272 for (KBookmark bm = group.first(); !bm.isNull(); bm = group.next(bm)) { 0273 if (!bm.isGroup() || urlForGroup(bm) != url) { 0274 continue; 0275 } 0276 0277 KBookmarkGroup group = bm.toGroup(); 0278 for (KBookmark b = group.first(); !b.isNull(); b = group.next(b)) { 0279 if (b.isSeparator() || b.isGroup()) { 0280 continue; 0281 } 0282 0283 ret.append(b); 0284 } 0285 break; 0286 } 0287 0288 return ret; 0289 } 0290 0291 KBookmark::List BookmarkManager::bookmarks() const 0292 { 0293 return bookmarks(d->url); 0294 } 0295 0296 KBookmark::List BookmarkManager::bookmarks(int page) const 0297 { 0298 const KBookmark::List bmarks = bookmarks(); 0299 KBookmark::List ret; 0300 for (const KBookmark &bm : bmarks) { 0301 DocumentViewport vp(bm.url().fragment(QUrl::FullyDecoded)); 0302 if (vp.isValid() && vp.pageNumber == page) { 0303 ret.append(bm); 0304 } 0305 } 0306 0307 return ret; 0308 } 0309 0310 KBookmark BookmarkManager::bookmark(int page) const 0311 { 0312 const KBookmark::List bmarks = bookmarks(); 0313 for (const KBookmark &bm : bmarks) { 0314 DocumentViewport vp(bm.url().fragment(QUrl::FullyDecoded)); 0315 if (vp.isValid() && vp.pageNumber == page) { 0316 return bm; 0317 } 0318 } 0319 return KBookmark(); 0320 } 0321 0322 KBookmark BookmarkManager::bookmark(const DocumentViewport &viewport) const 0323 { 0324 if (!viewport.isValid() || !isBookmarked(viewport.pageNumber)) { 0325 return KBookmark(); 0326 } 0327 0328 KBookmarkGroup thebg; 0329 QHash<QUrl, QString>::iterator it = d->bookmarkFind(d->url, false, &thebg); 0330 if (it == d->knownFiles.end()) { 0331 return KBookmark(); 0332 } 0333 0334 for (KBookmark bm = thebg.first(); !bm.isNull(); bm = thebg.next(bm)) { 0335 if (bm.isSeparator() || bm.isGroup()) { 0336 continue; 0337 } 0338 0339 DocumentViewport vp(bm.url().fragment(QUrl::FullyDecoded)); 0340 if (documentViewportFuzzyCompare(vp, viewport)) { 0341 return bm; 0342 } 0343 } 0344 0345 return KBookmark(); 0346 } 0347 0348 void BookmarkManager::save() const 0349 { 0350 d->manager.emitChanged(); 0351 Q_EMIT const_cast<BookmarkManager *>(this)->saved(); 0352 } 0353 0354 QHash<QUrl, QString>::iterator BookmarkManager::Private::bookmarkFind(const QUrl &url, bool doCreate, KBookmarkGroup *result) 0355 { 0356 QHash<QUrl, QString>::iterator it = knownFiles.find(url); 0357 if (it == knownFiles.end()) { 0358 // if the url we want to add a new entry for is not in the hash of the 0359 // known files, then first try to find the file among the top-level 0360 // "folder" names 0361 bool found = false; 0362 KBookmarkGroup root = manager.root(); 0363 for (KBookmark bm = root.first(); !found && !bm.isNull(); bm = root.next(bm)) { 0364 if (bm.isSeparator() || !bm.isGroup()) { 0365 continue; 0366 } 0367 0368 QUrl tmpurl(urlForGroup(bm)); 0369 if (tmpurl == url) { 0370 // got it! place it the hash of known files 0371 KBookmarkGroup bg = bm.toGroup(); 0372 it = knownFiles.insert(url, bg.address()); 0373 found = true; 0374 if (result) { 0375 *result = bg; 0376 } 0377 break; 0378 } 0379 } 0380 if (!found && doCreate) { 0381 // folder not found :( 0382 // then, in a single step create a new folder and add it in our cache :) 0383 QString purl = url.isLocalFile() ? url.toLocalFile() : url.toDisplayString(); 0384 KBookmarkGroup newbg = root.createNewFolder(purl); 0385 newbg.setUrl(url); 0386 it = knownFiles.insert(url, newbg.address()); 0387 if (result) { 0388 *result = newbg; 0389 } 0390 } 0391 } else if (result) { 0392 const KBookmark bm = manager.findByAddress(it.value()); 0393 Q_ASSERT(bm.isGroup()); 0394 *result = bm.toGroup(); 0395 } 0396 return it; 0397 } 0398 0399 void BookmarkManager::addBookmark(int page) 0400 { 0401 if (page >= 0 && page < (int)d->document->m_pagesVector.count()) { 0402 if (setPageBookmark(page)) 0403 foreachObserver(notifyPageChanged(page, DocumentObserver::Bookmark)); 0404 } 0405 } 0406 0407 void BookmarkManager::addBookmark(const DocumentViewport &vp) 0408 { 0409 addBookmark(d->url, vp); 0410 } 0411 0412 bool BookmarkManager::addBookmark(const QUrl &documentUrl, const Okular::DocumentViewport &vp, const QString &title) 0413 { 0414 if (!documentUrl.isValid() || !vp.isValid()) { 0415 return false; 0416 } 0417 0418 if (vp.pageNumber < 0 || vp.pageNumber >= d->document->m_pagesVector.count()) { 0419 return false; 0420 } 0421 0422 const QUrl referurl = mostCanonicalUrl(documentUrl); 0423 0424 KBookmarkGroup thebg; 0425 QHash<QUrl, QString>::iterator it = d->bookmarkFind(referurl, true, &thebg); 0426 Q_ASSERT(it != d->knownFiles.end()); 0427 0428 int count = 0; // Number of bookmarks in the current page 0429 bool found = false; 0430 // Check if the bookmark already exists 0431 for (KBookmark bm = thebg.first(); !found && !bm.isNull(); bm = thebg.next(bm)) { 0432 if (bm.isSeparator() || bm.isGroup()) { 0433 continue; 0434 } 0435 0436 DocumentViewport bmViewport(bm.url().fragment(QUrl::FullyDecoded)); 0437 if (bmViewport.isValid() && bmViewport.pageNumber == vp.pageNumber) { 0438 ++count; 0439 0440 if (documentViewportFuzzyCompare(bmViewport, vp)) { 0441 found = true; 0442 } 0443 } 0444 } 0445 0446 if (found) { 0447 return false; 0448 } 0449 0450 QString newtitle; 0451 if (title.isEmpty()) { 0452 // if we have no title specified for the new bookmark, then give it the 0453 // name '#p' where p is the page number where the bookmark is located. 0454 // if there's more than one bookmark per page, give the name '#p-n' 0455 // where n is the index of this bookmark among the ones of its page. 0456 if (count > 0) { 0457 newtitle = QStringLiteral("#%1-%2").arg(vp.pageNumber + 1).arg(count); 0458 } else { 0459 newtitle = QStringLiteral("#%1").arg(vp.pageNumber + 1); 0460 } 0461 } else { 0462 newtitle = title; 0463 } 0464 0465 QUrl newurl = referurl; 0466 newurl.setFragment(vp.toString(), QUrl::DecodedMode); 0467 thebg.addBookmark(newtitle, newurl, QString()); 0468 if (referurl == d->document->m_url) { 0469 d->urlBookmarks[vp.pageNumber]++; 0470 foreachObserver(notifyPageChanged(vp.pageNumber, DocumentObserver::Bookmark)); 0471 } 0472 d->manager.emitChanged(thebg); 0473 return true; 0474 } 0475 0476 void BookmarkManager::removeBookmark(int page) 0477 { 0478 if (page >= 0 && page < (int)d->document->m_pagesVector.count()) { 0479 if (removePageBookmark(page)) 0480 foreachObserver(notifyPageChanged(page, DocumentObserver::Bookmark)); 0481 } 0482 } 0483 0484 void BookmarkManager::removeBookmark(const DocumentViewport &vp) 0485 { 0486 int page = vp.pageNumber; 0487 if (page >= 0 && page < d->document->m_pagesVector.count()) { 0488 removeBookmark(d->url, bookmark(vp)); 0489 } 0490 } 0491 0492 void BookmarkManager::renameBookmark(KBookmark *bm, const QString &newName) 0493 { 0494 KBookmarkGroup thebg; 0495 QHash<QUrl, QString>::iterator it = d->bookmarkFind(d->url, false, &thebg); 0496 Q_ASSERT(it != d->knownFiles.end()); 0497 if (it == d->knownFiles.end()) { 0498 return; 0499 } 0500 0501 bm->setFullText(newName); 0502 d->manager.emitChanged(thebg); 0503 } 0504 0505 void BookmarkManager::renameBookmark(const QUrl &documentUrl, const QString &newName) 0506 { 0507 if (!documentUrl.isValid()) { 0508 return; 0509 } 0510 0511 const QUrl referurl = mostCanonicalUrl(documentUrl); 0512 0513 KBookmarkGroup thebg; 0514 QHash<QUrl, QString>::iterator it = d->bookmarkFind(referurl, false, &thebg); 0515 Q_ASSERT(it != d->knownFiles.end()); 0516 if (it == d->knownFiles.end()) { 0517 return; 0518 } 0519 0520 thebg.setFullText(newName); 0521 d->manager.emitChanged(thebg); 0522 } 0523 0524 QString BookmarkManager::titleForUrl(const QUrl &documentUrl) const 0525 { 0526 KBookmarkGroup thebg; 0527 QHash<QUrl, QString>::iterator it = d->bookmarkFind(mostCanonicalUrl(documentUrl), false, &thebg); 0528 Q_ASSERT(it != d->knownFiles.end()); 0529 0530 return thebg.fullText(); 0531 } 0532 0533 int BookmarkManager::removeBookmark(const QUrl &documentUrl, const KBookmark &bm) 0534 { 0535 if (!documentUrl.isValid() || bm.isNull() || bm.isGroup() || bm.isSeparator()) { 0536 return -1; 0537 } 0538 0539 DocumentViewport vp(bm.url().fragment(QUrl::FullyDecoded)); 0540 if (!vp.isValid()) { 0541 return -1; 0542 } 0543 0544 const QUrl referurl = mostCanonicalUrl(documentUrl); 0545 0546 KBookmarkGroup thebg; 0547 QHash<QUrl, QString>::iterator it = d->bookmarkFind(referurl, false, &thebg); 0548 if (it == d->knownFiles.end()) { 0549 return -1; 0550 } 0551 0552 thebg.deleteBookmark(bm); 0553 0554 if (referurl == d->document->m_url) { 0555 d->urlBookmarks[vp.pageNumber]--; 0556 foreachObserver(notifyPageChanged(vp.pageNumber, DocumentObserver::Bookmark)); 0557 } 0558 d->manager.emitChanged(thebg); 0559 0560 return vp.pageNumber; 0561 } 0562 0563 void BookmarkManager::removeBookmarks(const QUrl &documentUrl, const KBookmark::List &list) 0564 { 0565 if (!documentUrl.isValid() || list.isEmpty()) { 0566 return; 0567 } 0568 0569 const QUrl referurl = mostCanonicalUrl(documentUrl); 0570 0571 KBookmarkGroup thebg; 0572 QHash<QUrl, QString>::iterator it = d->bookmarkFind(referurl, false, &thebg); 0573 if (it == d->knownFiles.end()) { 0574 return; 0575 } 0576 0577 const QHash<int, int> oldUrlBookmarks = d->urlBookmarks; 0578 bool deletedAny = false; 0579 for (const KBookmark &bm : list) { 0580 if (bm.parentGroup() == thebg) { 0581 thebg.deleteBookmark(bm); 0582 deletedAny = true; 0583 0584 DocumentViewport vp(bm.url().fragment(QUrl::FullyDecoded)); 0585 if (referurl == d->document->m_url) { 0586 d->urlBookmarks[vp.pageNumber]--; 0587 } 0588 } 0589 } 0590 0591 if (referurl == d->document->m_url) { 0592 for (int i = 0; i < qMax(oldUrlBookmarks.size(), d->urlBookmarks.size()); i++) { 0593 bool oldContains = oldUrlBookmarks.contains(i) && oldUrlBookmarks[i] > 0; 0594 bool curContains = d->urlBookmarks.contains(i) && d->urlBookmarks[i] > 0; 0595 0596 if (oldContains != curContains) { 0597 foreachObserver(notifyPageChanged(i, DocumentObserver::Bookmark)); 0598 } else if (oldContains && oldUrlBookmarks[i] != d->urlBookmarks[i]) { 0599 foreachObserver(notifyPageChanged(i, DocumentObserver::Bookmark)); 0600 } 0601 } 0602 } 0603 if (deletedAny) { 0604 d->manager.emitChanged(thebg); 0605 } 0606 } 0607 0608 QList<QAction *> BookmarkManager::actionsForUrl(const QUrl &documentUrl) const 0609 { 0610 const QUrl url = mostCanonicalUrl(documentUrl); 0611 QList<QAction *> ret; 0612 KBookmarkGroup group = d->manager.root(); 0613 for (KBookmark bm = group.first(); !bm.isNull(); bm = group.next(bm)) { 0614 if (!bm.isGroup() || urlForGroup(bm) != url) { 0615 continue; 0616 } 0617 0618 KBookmarkGroup group = bm.toGroup(); 0619 for (KBookmark b = group.first(); !b.isNull(); b = group.next(b)) { 0620 if (b.isSeparator() || b.isGroup()) { 0621 continue; 0622 } 0623 0624 ret.append(new OkularBookmarkAction(DocumentViewport(b.url().fragment(QUrl::FullyDecoded)), b, d, nullptr)); 0625 } 0626 break; 0627 } 0628 std::sort(ret.begin(), ret.end(), okularBookmarkActionLessThan); 0629 return ret; 0630 } 0631 0632 void BookmarkManager::setUrl(const QUrl &url) 0633 { 0634 d->url = mostCanonicalUrl(url); 0635 d->urlBookmarks.clear(); 0636 KBookmarkGroup thebg; 0637 QHash<QUrl, QString>::iterator it = d->bookmarkFind(d->url, false, &thebg); 0638 if (it != d->knownFiles.end()) { 0639 for (KBookmark bm = thebg.first(); !bm.isNull(); bm = thebg.next(bm)) { 0640 if (bm.isSeparator() || bm.isGroup()) { 0641 continue; 0642 } 0643 0644 DocumentViewport vp(bm.url().fragment(QUrl::FullyDecoded)); 0645 if (!vp.isValid()) { 0646 continue; 0647 } 0648 0649 d->urlBookmarks[vp.pageNumber]++; 0650 } 0651 } 0652 } 0653 0654 bool BookmarkManager::setPageBookmark(int page) 0655 { 0656 KBookmarkGroup thebg; 0657 QHash<QUrl, QString>::iterator it = d->bookmarkFind(d->url, true, &thebg); 0658 Q_ASSERT(it != d->knownFiles.end()); 0659 0660 bool found = false; 0661 bool added = false; 0662 for (KBookmark bm = thebg.first(); !found && !bm.isNull(); bm = thebg.next(bm)) { 0663 if (bm.isSeparator() || bm.isGroup()) { 0664 continue; 0665 } 0666 0667 DocumentViewport vp(bm.url().fragment(QUrl::FullyDecoded)); 0668 if (vp.isValid() && vp.pageNumber == page) { 0669 found = true; 0670 } 0671 } 0672 if (!found) { 0673 d->urlBookmarks[page]++; 0674 DocumentViewport vp; 0675 vp.pageNumber = page; 0676 QUrl newurl = d->url; 0677 newurl.setFragment(vp.toString(), QUrl::DecodedMode); 0678 thebg.addBookmark(QLatin1String("#") + QString::number(vp.pageNumber + 1), newurl, QString()); 0679 added = true; 0680 d->manager.emitChanged(thebg); 0681 } 0682 return added; 0683 } 0684 0685 bool BookmarkManager::removePageBookmark(int page) 0686 { 0687 KBookmarkGroup thebg; 0688 QHash<QUrl, QString>::iterator it = d->bookmarkFind(d->url, false, &thebg); 0689 if (it == d->knownFiles.end()) { 0690 return false; 0691 } 0692 0693 bool found = false; 0694 for (KBookmark bm = thebg.first(); !found && !bm.isNull(); bm = thebg.next(bm)) { 0695 if (bm.isSeparator() || bm.isGroup()) { 0696 continue; 0697 } 0698 0699 DocumentViewport vp(bm.url().fragment(QUrl::FullyDecoded)); 0700 if (vp.isValid() && vp.pageNumber == page) { 0701 found = true; 0702 thebg.deleteBookmark(bm); 0703 d->urlBookmarks[page]--; 0704 d->manager.emitChanged(thebg); 0705 } 0706 } 0707 return found; 0708 } 0709 0710 bool BookmarkManager::isBookmarked(int page) const 0711 { 0712 return d->urlBookmarks.contains(page) && d->urlBookmarks[page] > 0; 0713 } 0714 0715 bool BookmarkManager::isBookmarked(const DocumentViewport &viewport) const 0716 { 0717 KBookmark bm = bookmark(viewport); 0718 0719 return !bm.isNull(); 0720 } 0721 0722 KBookmark BookmarkManager::nextBookmark(const DocumentViewport &viewport) const 0723 { 0724 KBookmark::List bmarks = bookmarks(); 0725 std::sort(bmarks.begin(), bmarks.end(), bookmarkLessThan); 0726 0727 KBookmark bookmark; 0728 for (const KBookmark &bm : std::as_const(bmarks)) { 0729 DocumentViewport vp(bm.url().fragment(QUrl::FullyDecoded)); 0730 if (viewport < vp) { 0731 bookmark = bm; 0732 break; 0733 } 0734 } 0735 0736 return bookmark; 0737 } 0738 0739 KBookmark BookmarkManager::previousBookmark(const DocumentViewport &viewport) const 0740 { 0741 KBookmark::List bmarks = bookmarks(); 0742 std::sort(bmarks.begin(), bmarks.end(), bookmarkLessThan); 0743 0744 KBookmark bookmark; 0745 for (KBookmark::List::const_iterator it = bmarks.constEnd(); it != bmarks.constBegin(); --it) { 0746 KBookmark bm = *(it - 1); 0747 DocumentViewport vp(bm.url().fragment(QUrl::FullyDecoded)); 0748 if (vp < viewport) { 0749 bookmark = bm; 0750 break; 0751 } 0752 } 0753 0754 return bookmark; 0755 } 0756 0757 #undef foreachObserver 0758 #undef foreachObserverD 0759 0760 #include "bookmarkmanager.moc" 0761 0762 /* kate: replace-tabs on; indent-width 4; */