File indexing completed on 2023-10-01 07:48:10
0001 // -*- c-basic-offset:4; indent-tabs-mode:nil -*- 0002 /* 0003 This file is part of the KDE libraries 0004 SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org> 0005 SPDX-FileCopyrightText: 2003 Alexander Kellett <lypanov@kde.org> 0006 SPDX-FileCopyrightText: 2008 Norbert Frese <nf2@scheinwelt.at> 0007 0008 SPDX-License-Identifier: LGPL-2.0-only 0009 */ 0010 0011 #include "kbookmarkmanager.h" 0012 #include "kbookmarkdialog.h" 0013 #include "kbookmarkimporter.h" 0014 #include "kbookmarkmenu.h" 0015 #include "kbookmarkmenu_p.h" 0016 #include "kbookmarks_debug.h" 0017 #ifndef KBOOKMARKS_NO_DBUS 0018 #include "kbookmarkmanageradaptor_p.h" 0019 #endif 0020 0021 #include <QDir> 0022 #include <QFile> 0023 #include <QFileInfo> 0024 #include <QProcess> 0025 #include <QRegularExpression> 0026 #include <QTextCodec> 0027 #include <QTextStream> 0028 #ifndef KBOOKMARKS_NO_DBUS 0029 #include <QDBusConnection> 0030 #include <QDBusMessage> 0031 #endif 0032 #include <QApplication> 0033 #include <QMessageBox> 0034 #include <QReadWriteLock> 0035 #include <QThread> 0036 0037 #include <KBackup> 0038 #include <KConfig> 0039 #include <KConfigGroup> 0040 #include <KDirWatch> 0041 #include <QSaveFile> 0042 #include <QStandardPaths> 0043 0044 namespace 0045 { 0046 namespace Strings 0047 { 0048 QString bookmarkChangeNotifyInterface() 0049 { 0050 return QStringLiteral("org.kde.KIO.KBookmarkManager"); 0051 } 0052 QString piData() 0053 { 0054 return QStringLiteral("version=\"1.0\" encoding=\"UTF-8\""); 0055 } 0056 } 0057 } 0058 0059 class KBookmarkManagerList : public QList<KBookmarkManager *> 0060 { 0061 public: 0062 KBookmarkManagerList(); 0063 ~KBookmarkManagerList() 0064 { 0065 cleanup(); 0066 } 0067 void cleanup() 0068 { 0069 QList<KBookmarkManager *> copy = *this; 0070 qDeleteAll(copy); // auto-delete functionality 0071 clear(); 0072 } 0073 0074 QReadWriteLock lock; 0075 }; 0076 0077 Q_GLOBAL_STATIC(KBookmarkManagerList, s_pSelf) 0078 0079 static void deleteManagers() 0080 { 0081 if (s_pSelf.exists()) { 0082 s_pSelf->cleanup(); 0083 } 0084 } 0085 0086 KBookmarkManagerList::KBookmarkManagerList() 0087 { 0088 // Delete the KBookmarkManagers while qApp exists, since we interact with the DBus thread 0089 qAddPostRoutine(deleteManagers); 0090 } 0091 0092 class KBookmarkMap : private KBookmarkGroupTraverser 0093 { 0094 public: 0095 KBookmarkMap() 0096 : m_mapNeedsUpdate(true) 0097 { 0098 } 0099 void setNeedsUpdate() 0100 { 0101 m_mapNeedsUpdate = true; 0102 } 0103 void update(KBookmarkManager *); 0104 QList<KBookmark> find(const QString &url) const 0105 { 0106 return m_bk_map.value(url); 0107 } 0108 0109 private: 0110 void visit(const KBookmark &) override; 0111 void visitEnter(const KBookmarkGroup &) override 0112 { 0113 ; 0114 } 0115 void visitLeave(const KBookmarkGroup &) override 0116 { 0117 ; 0118 } 0119 0120 private: 0121 typedef QList<KBookmark> KBookmarkList; 0122 QMap<QString, KBookmarkList> m_bk_map; 0123 bool m_mapNeedsUpdate; 0124 }; 0125 0126 void KBookmarkMap::update(KBookmarkManager *manager) 0127 { 0128 if (m_mapNeedsUpdate) { 0129 m_mapNeedsUpdate = false; 0130 0131 m_bk_map.clear(); 0132 KBookmarkGroup root = manager->root(); 0133 traverse(root); 0134 } 0135 } 0136 0137 void KBookmarkMap::visit(const KBookmark &bk) 0138 { 0139 if (!bk.isSeparator()) { 0140 // add bookmark to url map 0141 m_bk_map[bk.internalElement().attribute(QStringLiteral("href"))].append(bk); 0142 } 0143 } 0144 0145 // ######################### 0146 // KBookmarkManagerPrivate 0147 class KBookmarkManagerPrivate 0148 { 0149 public: 0150 KBookmarkManagerPrivate(bool bDocIsloaded, const QString &dbusObjectName = QString()) 0151 : m_doc(QStringLiteral("xbel")) 0152 , m_dbusObjectName(dbusObjectName) 0153 , m_docIsLoaded(bDocIsloaded) 0154 , m_update(false) 0155 , m_dialogAllowed(true) 0156 , m_dialogParent(nullptr) 0157 , m_browserEditor(false) 0158 , m_typeExternal(false) 0159 , m_dirWatch(nullptr) 0160 { 0161 } 0162 0163 ~KBookmarkManagerPrivate() 0164 { 0165 delete m_dirWatch; 0166 } 0167 0168 mutable QDomDocument m_doc; 0169 mutable QDomDocument m_toolbarDoc; 0170 QString m_bookmarksFile; 0171 QString m_dbusObjectName; 0172 mutable bool m_docIsLoaded; 0173 bool m_update; 0174 bool m_dialogAllowed; 0175 QWidget *m_dialogParent; 0176 0177 bool m_browserEditor; 0178 QString m_editorCaption; 0179 0180 bool m_typeExternal; 0181 KDirWatch *m_dirWatch; // for external bookmark files 0182 0183 KBookmarkMap m_map; 0184 }; 0185 0186 // ################ 0187 // KBookmarkManager 0188 0189 static KBookmarkManager *lookupExisting(const QString &bookmarksFile) 0190 { 0191 for (KBookmarkManagerList::ConstIterator bmit = s_pSelf()->constBegin(), bmend = s_pSelf()->constEnd(); bmit != bmend; ++bmit) { 0192 if ((*bmit)->path() == bookmarksFile) { 0193 return *bmit; 0194 } 0195 } 0196 return nullptr; 0197 } 0198 0199 KBookmarkManager *KBookmarkManager::managerForFile(const QString &bookmarksFile, const QString &dbusObjectName) 0200 { 0201 KBookmarkManager *mgr(nullptr); 0202 { 0203 QReadLocker readLock(&s_pSelf()->lock); 0204 mgr = lookupExisting(bookmarksFile); 0205 if (mgr) { 0206 return mgr; 0207 } 0208 } 0209 0210 QWriteLocker writeLock(&s_pSelf()->lock); 0211 mgr = lookupExisting(bookmarksFile); 0212 if (mgr) { 0213 return mgr; 0214 } 0215 0216 mgr = new KBookmarkManager(bookmarksFile, dbusObjectName); 0217 s_pSelf()->append(mgr); 0218 return mgr; 0219 } 0220 0221 KBookmarkManager *KBookmarkManager::managerForExternalFile(const QString &bookmarksFile) 0222 { 0223 KBookmarkManager *mgr(nullptr); 0224 { 0225 QReadLocker readLock(&s_pSelf()->lock); 0226 mgr = lookupExisting(bookmarksFile); 0227 if (mgr) { 0228 return mgr; 0229 } 0230 } 0231 0232 QWriteLocker writeLock(&s_pSelf()->lock); 0233 mgr = lookupExisting(bookmarksFile); 0234 if (mgr) { 0235 return mgr; 0236 } 0237 0238 mgr = new KBookmarkManager(bookmarksFile); 0239 s_pSelf()->append(mgr); 0240 return mgr; 0241 } 0242 0243 // principally used for filtered toolbars 0244 KBookmarkManager *KBookmarkManager::createTempManager() 0245 { 0246 KBookmarkManager *mgr = new KBookmarkManager(); 0247 s_pSelf()->append(mgr); 0248 return mgr; 0249 } 0250 0251 static QDomElement createXbelTopLevelElement(QDomDocument &doc) 0252 { 0253 QDomElement topLevel = doc.createElement(QStringLiteral("xbel")); 0254 topLevel.setAttribute(QStringLiteral("xmlns:mime"), QStringLiteral("http://www.freedesktop.org/standards/shared-mime-info")); 0255 topLevel.setAttribute(QStringLiteral("xmlns:bookmark"), QStringLiteral("http://www.freedesktop.org/standards/desktop-bookmarks")); 0256 topLevel.setAttribute(QStringLiteral("xmlns:kdepriv"), QStringLiteral("http://www.kde.org/kdepriv")); 0257 doc.appendChild(topLevel); 0258 doc.insertBefore(doc.createProcessingInstruction(QStringLiteral("xml"), Strings::piData()), topLevel); 0259 return topLevel; 0260 } 0261 0262 KBookmarkManager::KBookmarkManager(const QString &bookmarksFile, const QString &dbusObjectName) 0263 : d(new KBookmarkManagerPrivate(false, dbusObjectName)) 0264 { 0265 if (dbusObjectName.isNull()) { // get dbusObjectName from file 0266 if (QFile::exists(d->m_bookmarksFile)) { 0267 parse(); // sets d->m_dbusObjectName 0268 } 0269 } 0270 0271 init(QLatin1String("/KBookmarkManager/") + d->m_dbusObjectName); 0272 0273 d->m_update = true; 0274 0275 Q_ASSERT(!bookmarksFile.isEmpty()); 0276 d->m_bookmarksFile = bookmarksFile; 0277 0278 if (!QFile::exists(d->m_bookmarksFile)) { 0279 QDomElement topLevel = createXbelTopLevelElement(d->m_doc); 0280 topLevel.setAttribute(QStringLiteral("dbusName"), dbusObjectName); 0281 d->m_docIsLoaded = true; 0282 } 0283 } 0284 0285 KBookmarkManager::KBookmarkManager(const QString &bookmarksFile) 0286 : d(new KBookmarkManagerPrivate(false)) 0287 { 0288 // use QFileSystemWatcher to monitor this bookmarks file 0289 d->m_typeExternal = true; 0290 d->m_update = true; 0291 0292 Q_ASSERT(!bookmarksFile.isEmpty()); 0293 d->m_bookmarksFile = bookmarksFile; 0294 0295 if (!QFile::exists(d->m_bookmarksFile)) { 0296 createXbelTopLevelElement(d->m_doc); 0297 } else { 0298 parse(); 0299 } 0300 d->m_docIsLoaded = true; 0301 0302 // start KDirWatch 0303 d->m_dirWatch = new KDirWatch; 0304 d->m_dirWatch->addFile(d->m_bookmarksFile); 0305 QObject::connect(d->m_dirWatch, &KDirWatch::dirty, this, &KBookmarkManager::slotFileChanged); 0306 QObject::connect(d->m_dirWatch, &KDirWatch::created, this, &KBookmarkManager::slotFileChanged); 0307 QObject::connect(d->m_dirWatch, &KDirWatch::deleted, this, &KBookmarkManager::slotFileChanged); 0308 0309 // qCDebug(KBOOKMARKS_LOG) << "starting KDirWatch for" << d->m_bookmarksFile; 0310 } 0311 0312 KBookmarkManager::KBookmarkManager() 0313 : d(new KBookmarkManagerPrivate(true)) 0314 { 0315 init(QStringLiteral("/KBookmarkManager/generated")); 0316 d->m_update = false; // TODO - make it read/write 0317 0318 createXbelTopLevelElement(d->m_doc); 0319 } 0320 0321 void KBookmarkManager::init(const QString &dbusPath) 0322 { 0323 #ifndef KBOOKMARKS_NO_DBUS 0324 // A KBookmarkManager without a dbus name is a temporary one, like those used by importers; 0325 // no need to register them to dbus 0326 if (dbusPath != QLatin1String("/KBookmarkManager/") && dbusPath != QLatin1String("/KBookmarkManager/generated")) { 0327 new KBookmarkManagerAdaptor(this); 0328 QDBusConnection::sessionBus().registerObject(dbusPath, this); 0329 0330 QDBusConnection::sessionBus().connect(QString(), 0331 dbusPath, 0332 Strings::bookmarkChangeNotifyInterface(), 0333 QStringLiteral("bookmarksChanged"), 0334 this, 0335 SLOT(notifyChanged(QString, QDBusMessage))); 0336 QDBusConnection::sessionBus() 0337 .connect(QString(), dbusPath, Strings::bookmarkChangeNotifyInterface(), QStringLiteral("bookmarkConfigChanged"), this, SLOT(notifyConfigChanged())); 0338 } 0339 #endif 0340 } 0341 0342 void KBookmarkManager::startKEditBookmarks(const QStringList &args) 0343 { 0344 bool success = false; 0345 const QString exec = QStandardPaths::findExecutable(QStringLiteral(KEDITBOOKMARKS_BINARY)); 0346 if (!exec.isEmpty()) { 0347 success = QProcess::startDetached(exec, args); 0348 } 0349 0350 if (!success) { 0351 QString err = 0352 tr("Cannot launch keditbookmarks.\n\n" 0353 "Most likely you do not have keditbookmarks currently installed"); 0354 0355 if (d->m_dialogAllowed && qobject_cast<QApplication *>(qApp) && QThread::currentThread() == qApp->thread()) { 0356 QMessageBox::warning(QApplication::activeWindow(), QApplication::applicationName(), err); 0357 } 0358 0359 qCWarning(KBOOKMARKS_LOG) << QStringLiteral("Failed to start keditbookmarks"); 0360 Q_EMIT this->error(err); 0361 } 0362 } 0363 0364 void KBookmarkManager::slotFileChanged(const QString &path) 0365 { 0366 if (path == d->m_bookmarksFile) { 0367 // qCDebug(KBOOKMARKS_LOG) << "file changed (KDirWatch) " << path ; 0368 // Reparse 0369 parse(); 0370 // Tell our GUI 0371 // (emit where group is "" to directly mark the root menu as dirty) 0372 Q_EMIT changed(QLatin1String(""), QString()); 0373 } 0374 } 0375 0376 KBookmarkManager::~KBookmarkManager() 0377 { 0378 if (!s_pSelf.isDestroyed()) { 0379 s_pSelf()->removeAll(this); 0380 } 0381 } 0382 0383 bool KBookmarkManager::autoErrorHandlingEnabled() const 0384 { 0385 return d->m_dialogAllowed; 0386 } 0387 0388 void KBookmarkManager::setAutoErrorHandlingEnabled(bool enable, QWidget *parent) 0389 { 0390 d->m_dialogAllowed = enable; 0391 d->m_dialogParent = parent; 0392 } 0393 0394 void KBookmarkManager::setUpdate(bool update) 0395 { 0396 d->m_update = update; 0397 } 0398 0399 QDomDocument KBookmarkManager::internalDocument() const 0400 { 0401 if (!d->m_docIsLoaded) { 0402 parse(); 0403 d->m_toolbarDoc.clear(); 0404 } 0405 return d->m_doc; 0406 } 0407 0408 void KBookmarkManager::parse() const 0409 { 0410 d->m_docIsLoaded = true; 0411 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::parse " << d->m_bookmarksFile; 0412 QFile file(d->m_bookmarksFile); 0413 if (!file.open(QIODevice::ReadOnly)) { 0414 qCWarning(KBOOKMARKS_LOG) << "Can't open" << d->m_bookmarksFile; 0415 d->m_doc = QDomDocument(QStringLiteral("xbel")); 0416 createXbelTopLevelElement(d->m_doc); 0417 return; 0418 } 0419 d->m_doc = QDomDocument(QStringLiteral("xbel")); 0420 d->m_doc.setContent(&file); 0421 0422 if (d->m_doc.documentElement().isNull()) { 0423 qCWarning(KBOOKMARKS_LOG) << "KBookmarkManager::parse : main tag is missing, creating default " << d->m_bookmarksFile; 0424 QDomElement element = d->m_doc.createElement(QStringLiteral("xbel")); 0425 d->m_doc.appendChild(element); 0426 } 0427 0428 QDomElement docElem = d->m_doc.documentElement(); 0429 0430 QString mainTag = docElem.tagName(); 0431 if (mainTag != QLatin1String("xbel")) { 0432 qCWarning(KBOOKMARKS_LOG) << "KBookmarkManager::parse : unknown main tag " << mainTag; 0433 } 0434 0435 if (d->m_dbusObjectName.isNull()) { 0436 d->m_dbusObjectName = docElem.attribute(QStringLiteral("dbusName")); 0437 } else if (docElem.attribute(QStringLiteral("dbusName")) != d->m_dbusObjectName) { 0438 docElem.setAttribute(QStringLiteral("dbusName"), d->m_dbusObjectName); 0439 save(); 0440 } 0441 0442 QDomNode n = d->m_doc.documentElement().previousSibling(); 0443 if (n.isProcessingInstruction()) { 0444 QDomProcessingInstruction pi = n.toProcessingInstruction(); 0445 pi.parentNode().removeChild(pi); 0446 } 0447 0448 QDomProcessingInstruction pi; 0449 pi = d->m_doc.createProcessingInstruction(QStringLiteral("xml"), Strings::piData()); 0450 d->m_doc.insertBefore(pi, docElem); 0451 0452 file.close(); 0453 0454 d->m_map.setNeedsUpdate(); 0455 } 0456 0457 bool KBookmarkManager::save(bool toolbarCache) const 0458 { 0459 return saveAs(d->m_bookmarksFile, toolbarCache); 0460 } 0461 0462 bool KBookmarkManager::saveAs(const QString &filename, bool toolbarCache) const 0463 { 0464 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::save " << filename; 0465 0466 // Save the bookmark toolbar folder for quick loading 0467 // but only when it will actually make things quicker 0468 const QString cacheFilename = filename + QLatin1String(".tbcache"); 0469 if (toolbarCache && !root().isToolbarGroup()) { 0470 QSaveFile cacheFile(cacheFilename); 0471 if (cacheFile.open(QIODevice::WriteOnly)) { 0472 QString str; 0473 QTextStream stream(&str, QIODevice::WriteOnly); 0474 stream << root().findToolbar(); 0475 const QByteArray cstr = str.toUtf8(); 0476 cacheFile.write(cstr.data(), cstr.length()); 0477 cacheFile.commit(); 0478 } 0479 } else { // remove any (now) stale cache 0480 QFile::remove(cacheFilename); 0481 } 0482 0483 // Create parent dirs 0484 QFileInfo info(filename); 0485 QDir().mkpath(info.absolutePath()); 0486 0487 QSaveFile file(filename); 0488 if (file.open(QIODevice::WriteOnly)) { 0489 KBackup::simpleBackupFile(file.fileName(), QString(), QStringLiteral(".bak")); 0490 QTextStream stream(&file); 0491 // In Qt6 it's UTF-8 by default 0492 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0493 stream.setCodec(QTextCodec::codecForName("UTF-8")); 0494 #endif 0495 stream << internalDocument().toString(); 0496 stream.flush(); 0497 if (file.commit()) { 0498 return true; 0499 } 0500 } 0501 0502 static int hadSaveError = false; 0503 if (!hadSaveError) { 0504 QString err = tr("Unable to save bookmarks in %1. Reported error was: %2. " 0505 "This error message will only be shown once. The cause " 0506 "of the error needs to be fixed as quickly as possible, " 0507 "which is most likely a full hard drive.") 0508 .arg(filename, file.errorString()); 0509 0510 if (d->m_dialogAllowed && qobject_cast<QApplication *>(qApp) && QThread::currentThread() == qApp->thread()) { 0511 QMessageBox::critical(QApplication::activeWindow(), QApplication::applicationName(), err); 0512 } 0513 0514 qCCritical(KBOOKMARKS_LOG) 0515 << QStringLiteral("Unable to save bookmarks in %1. File reported the following error-code: %2.").arg(filename).arg(file.error()); 0516 Q_EMIT const_cast<KBookmarkManager *>(this)->error(err); 0517 } 0518 hadSaveError = true; 0519 return false; 0520 } 0521 0522 QString KBookmarkManager::path() const 0523 { 0524 return d->m_bookmarksFile; 0525 } 0526 0527 KBookmarkGroup KBookmarkManager::root() const 0528 { 0529 return KBookmarkGroup(internalDocument().documentElement()); 0530 } 0531 0532 KBookmarkGroup KBookmarkManager::toolbar() 0533 { 0534 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::toolbar begin"; 0535 // Only try to read from a toolbar cache if the full document isn't loaded 0536 if (!d->m_docIsLoaded) { 0537 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::toolbar trying cache"; 0538 const QString cacheFilename = d->m_bookmarksFile + QLatin1String(".tbcache"); 0539 QFileInfo bmInfo(d->m_bookmarksFile); 0540 QFileInfo cacheInfo(cacheFilename); 0541 if (d->m_toolbarDoc.isNull() && QFile::exists(cacheFilename) && bmInfo.lastModified() < cacheInfo.lastModified()) { 0542 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::toolbar reading file"; 0543 QFile file(cacheFilename); 0544 0545 if (file.open(QIODevice::ReadOnly)) { 0546 d->m_toolbarDoc = QDomDocument(QStringLiteral("cache")); 0547 d->m_toolbarDoc.setContent(&file); 0548 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::toolbar opened"; 0549 } 0550 } 0551 if (!d->m_toolbarDoc.isNull()) { 0552 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::toolbar returning element"; 0553 QDomElement elem = d->m_toolbarDoc.firstChild().toElement(); 0554 return KBookmarkGroup(elem); 0555 } 0556 } 0557 0558 // Fallback to the normal way if there is no cache or if the bookmark file 0559 // is already loaded 0560 QDomElement elem = root().findToolbar(); 0561 if (elem.isNull()) { 0562 // Root is the bookmark toolbar if none has been set. 0563 // Make it explicit to speed up invocations of findToolbar() 0564 root().internalElement().setAttribute(QStringLiteral("toolbar"), QStringLiteral("yes")); 0565 return root(); 0566 } else { 0567 return KBookmarkGroup(elem); 0568 } 0569 } 0570 0571 KBookmark KBookmarkManager::findByAddress(const QString &address) 0572 { 0573 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::findByAddress " << address; 0574 KBookmark result = root(); 0575 // The address is something like /5/10/2+ 0576 static const QRegularExpression separator(QStringLiteral("[/+]")); 0577 const QStringList addresses = address.split(separator, Qt::SkipEmptyParts); 0578 // qCWarning(KBOOKMARKS_LOG) << addresses.join(","); 0579 for (QStringList::const_iterator it = addresses.begin(); it != addresses.end();) { 0580 bool append = ((*it) == QLatin1String("+")); 0581 uint number = (*it).toUInt(); 0582 Q_ASSERT(result.isGroup()); 0583 KBookmarkGroup group = result.toGroup(); 0584 KBookmark bk = group.first(); 0585 KBookmark lbk = bk; // last non-null bookmark 0586 for (uint i = 0; ((i < number) || append) && !bk.isNull(); ++i) { 0587 lbk = bk; 0588 bk = group.next(bk); 0589 // qCWarning(KBOOKMARKS_LOG) << i; 0590 } 0591 it++; 0592 // qCWarning(KBOOKMARKS_LOG) << "found section"; 0593 result = bk; 0594 } 0595 if (result.isNull()) { 0596 qCWarning(KBOOKMARKS_LOG) << "KBookmarkManager::findByAddress: couldn't find item " << address; 0597 } 0598 // qCWarning(KBOOKMARKS_LOG) << "found " << result.address(); 0599 return result; 0600 } 0601 0602 void KBookmarkManager::emitChanged() 0603 { 0604 emitChanged(root()); 0605 } 0606 0607 void KBookmarkManager::emitChanged(const KBookmarkGroup &group) 0608 { 0609 (void)save(); // KDE5 TODO: emitChanged should return a bool? Maybe rename it to saveAndEmitChanged? 0610 0611 // Tell the other processes too 0612 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::emitChanged : broadcasting change " << group.address(); 0613 0614 Q_EMIT bookmarksChanged(group.address()); 0615 0616 // We do get our own broadcast, so no need for this anymore 0617 // emit changed( group ); 0618 } 0619 0620 void KBookmarkManager::emitConfigChanged() 0621 { 0622 Q_EMIT bookmarkConfigChanged(); 0623 } 0624 0625 void KBookmarkManager::notifyCompleteChange(const QString &caller) // DBUS call 0626 { 0627 if (!d->m_update) { 0628 return; 0629 } 0630 0631 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::notifyCompleteChange"; 0632 // The bk editor tells us we should reload everything 0633 // Reparse 0634 parse(); 0635 // Tell our GUI 0636 // (emit where group is "" to directly mark the root menu as dirty) 0637 Q_EMIT changed(QLatin1String(""), caller); 0638 } 0639 0640 void KBookmarkManager::notifyConfigChanged() // DBUS call 0641 { 0642 // qCDebug(KBOOKMARKS_LOG) << "reloaded bookmark config!"; 0643 KBookmarkSettings::self()->readSettings(); 0644 parse(); // reload, and thusly recreate the menus 0645 Q_EMIT configChanged(); 0646 } 0647 0648 #ifndef KBOOKMARKS_NO_DBUS 0649 void KBookmarkManager::notifyChanged(const QString &groupAddress, const QDBusMessage &msg) // DBUS call 0650 { 0651 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::notifyChanged ( "<<groupAddress<<")"; 0652 if (!d->m_update) { 0653 return; 0654 } 0655 0656 // Reparse (the whole file, no other choice) 0657 // if someone else notified us 0658 if (msg.service() != QDBusConnection::sessionBus().baseService()) { 0659 parse(); 0660 } 0661 0662 // qCDebug(KBOOKMARKS_LOG) << "KBookmarkManager::notifyChanged " << groupAddress; 0663 // KBookmarkGroup group = findByAddress( groupAddress ).toGroup(); 0664 // Q_ASSERT(!group.isNull()); 0665 Q_EMIT changed(groupAddress, QString()); 0666 } 0667 #endif 0668 0669 void KBookmarkManager::setEditorOptions(const QString &caption, bool browser) 0670 { 0671 d->m_editorCaption = caption; 0672 d->m_browserEditor = browser; 0673 } 0674 0675 void KBookmarkManager::slotEditBookmarks() 0676 { 0677 QStringList args; 0678 if (!d->m_editorCaption.isEmpty()) { 0679 args << QStringLiteral("--customcaption") << d->m_editorCaption; 0680 } 0681 if (!d->m_browserEditor) { 0682 args << QStringLiteral("--nobrowser"); 0683 } 0684 if (!d->m_dbusObjectName.isEmpty()) { 0685 args << QStringLiteral("--dbusObjectName") << d->m_dbusObjectName; 0686 } 0687 args << d->m_bookmarksFile; 0688 startKEditBookmarks(args); 0689 } 0690 0691 void KBookmarkManager::slotEditBookmarksAtAddress(const QString &address) 0692 { 0693 QStringList args; 0694 if (!d->m_editorCaption.isEmpty()) { 0695 args << QStringLiteral("--customcaption") << d->m_editorCaption; 0696 } 0697 if (!d->m_browserEditor) { 0698 args << QStringLiteral("--nobrowser"); 0699 } 0700 if (!d->m_dbusObjectName.isEmpty()) { 0701 args << QStringLiteral("--dbusObjectName") << d->m_dbusObjectName; 0702 } 0703 args << QStringLiteral("--address") << address << d->m_bookmarksFile; 0704 startKEditBookmarks(args); 0705 } 0706 0707 /////// 0708 bool KBookmarkManager::updateAccessMetadata(const QString &url) 0709 { 0710 d->m_map.update(this); 0711 QList<KBookmark> list = d->m_map.find(url); 0712 if (list.isEmpty()) { 0713 return false; 0714 } 0715 0716 for (QList<KBookmark>::iterator it = list.begin(); it != list.end(); ++it) { 0717 (*it).updateAccessMetadata(); 0718 } 0719 0720 return true; 0721 } 0722 0723 void KBookmarkManager::updateFavicon(const QString &url, const QString & /*faviconurl*/) 0724 { 0725 d->m_map.update(this); 0726 QList<KBookmark> list = d->m_map.find(url); 0727 for (QList<KBookmark>::iterator it = list.begin(); it != list.end(); ++it) { 0728 // TODO - update favicon data based on faviconurl 0729 // but only when the previously used icon 0730 // isn't a manually set one. 0731 } 0732 } 0733 0734 KBookmarkManager *KBookmarkManager::userBookmarksManager() 0735 { 0736 const QString bookmarksFile = 0737 QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/konqueror/bookmarks.xml"); 0738 KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile, QStringLiteral("konqueror")); 0739 QString caption = QGuiApplication::applicationDisplayName(); 0740 if (caption.isEmpty()) { 0741 caption = QCoreApplication::applicationName(); 0742 } 0743 bookmarkManager->setEditorOptions(caption, true); 0744 return bookmarkManager; 0745 } 0746 0747 KBookmarkSettings *KBookmarkSettings::s_self = nullptr; 0748 0749 void KBookmarkSettings::readSettings() 0750 { 0751 KConfig config(QStringLiteral("kbookmarkrc"), KConfig::NoGlobals); 0752 KConfigGroup cg(&config, "Bookmarks"); 0753 0754 // add bookmark dialog usage - no reparse 0755 s_self->m_advancedaddbookmark = cg.readEntry("AdvancedAddBookmarkDialog", false); 0756 0757 // this one alters the menu, therefore it needs a reparse 0758 s_self->m_contextmenu = cg.readEntry("ContextMenuActions", true); 0759 } 0760 0761 KBookmarkSettings *KBookmarkSettings::self() 0762 { 0763 if (!s_self) { 0764 s_self = new KBookmarkSettings; 0765 readSettings(); 0766 } 0767 return s_self; 0768 } 0769 0770 #include "moc_kbookmarkmanager.cpp"