File indexing completed on 2024-05-19 03:55:15

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org>
0004     SPDX-FileCopyrightText: 2006 Daniel Teske <teske@squorn.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "kbookmarkmenu.h"
0010 #include "kbookmarkmenu_p.h"
0011 
0012 #include "../kbookmarksettings_p.h"
0013 #include "kbookmarkaction.h"
0014 #include "kbookmarkactionmenu.h"
0015 #include "kbookmarkcontextmenu.h"
0016 #include "kbookmarkdialog.h"
0017 #include "kbookmarkmanager.h"
0018 #include "kbookmarkowner.h"
0019 #include "kbookmarkswidgets_debug.h"
0020 #include "keditbookmarks_p.h"
0021 
0022 #include <KAuthorized>
0023 #include <KStandardAction>
0024 
0025 #include <QApplication>
0026 #include <QMenu>
0027 #include <QMessageBox>
0028 #include <QStandardPaths>
0029 
0030 /********************************************************************/
0031 /********************************************************************/
0032 /********************************************************************/
0033 class KBookmarkMenuPrivate
0034 {
0035 public:
0036     QAction *newBookmarkFolderAction = nullptr;
0037     QAction *addBookmarkAction = nullptr;
0038     QAction *bookmarksToFolderAction = nullptr;
0039     QAction *editBookmarksAction = nullptr;
0040     bool browserMode = false;
0041     bool isRoot;
0042     bool dirty;
0043     KBookmarkManager *manager;
0044     KBookmarkOwner *owner;
0045     QMenu *parentMenu;
0046     QString parentAddress;
0047 };
0048 
0049 KBookmarkMenu::KBookmarkMenu(KBookmarkManager *manager, KBookmarkOwner *_owner, QMenu *_parentMenu)
0050     : QObject()
0051     , d(new KBookmarkMenuPrivate())
0052 {
0053     d->isRoot = true;
0054     d->manager = manager;
0055     d->owner = _owner;
0056     d->parentMenu = _parentMenu;
0057     d->parentAddress = QString(); // TODO KBookmarkAdress::root
0058     // TODO KDE5 find a QMenu equvalnet for this one
0059     // m_parentMenu->setKeyboardShortcutsEnabled( true );
0060 
0061     init();
0062 }
0063 
0064 void KBookmarkMenu::init()
0065 {
0066     connect(d->parentMenu, &QMenu::aboutToShow, this, &KBookmarkMenu::slotAboutToShow);
0067 
0068     if (KBookmarkSettings::self()->m_contextmenu) {
0069         d->parentMenu->setContextMenuPolicy(Qt::CustomContextMenu);
0070         connect(d->parentMenu, &QWidget::customContextMenuRequested, this, &KBookmarkMenu::slotCustomContextMenu);
0071     }
0072 
0073     connect(d->manager, &KBookmarkManager::changed, this, &KBookmarkMenu::slotBookmarksChanged);
0074 
0075     d->dirty = true;
0076     addActions();
0077 }
0078 
0079 void KBookmarkMenu::addActions()
0080 {
0081     if (d->isRoot) {
0082         addAddBookmark();
0083         addAddBookmarksList();
0084         addNewFolder();
0085         addEditBookmarks();
0086     } else {
0087         if (!d->parentMenu->actions().isEmpty()) {
0088             d->parentMenu->addSeparator();
0089         }
0090 
0091         addOpenInTabs();
0092         addAddBookmark();
0093         addAddBookmarksList();
0094         addNewFolder();
0095     }
0096 }
0097 
0098 KBookmarkMenu::KBookmarkMenu(KBookmarkManager *mgr, KBookmarkOwner *_owner, QMenu *_parentMenu, const QString &parentAddress)
0099     : QObject()
0100     , d(new KBookmarkMenuPrivate())
0101 {
0102     d->isRoot = false;
0103     d->manager = mgr;
0104     d->owner = _owner;
0105     d->parentMenu = _parentMenu;
0106     d->parentAddress = parentAddress;
0107 
0108     connect(_parentMenu, &QMenu::aboutToShow, this, &KBookmarkMenu::slotAboutToShow);
0109     if (KBookmarkSettings::self()->m_contextmenu) {
0110         d->parentMenu->setContextMenuPolicy(Qt::CustomContextMenu);
0111         connect(d->parentMenu, &QWidget::customContextMenuRequested, this, &KBookmarkMenu::slotCustomContextMenu);
0112     }
0113     d->dirty = true;
0114 }
0115 
0116 KBookmarkMenu::~KBookmarkMenu()
0117 {
0118     qDeleteAll(m_lstSubMenus);
0119     qDeleteAll(m_actions);
0120 }
0121 
0122 void KBookmarkMenu::ensureUpToDate()
0123 {
0124     slotAboutToShow();
0125 }
0126 
0127 void KBookmarkMenu::slotAboutToShow()
0128 {
0129     // Did the bookmarks change since the last time we showed them ?
0130     if (d->dirty) {
0131         d->dirty = false;
0132         clear();
0133         refill();
0134         d->parentMenu->adjustSize();
0135     }
0136 }
0137 
0138 void KBookmarkMenu::slotCustomContextMenu(const QPoint &pos)
0139 {
0140     QAction *action = d->parentMenu->actionAt(pos);
0141     QMenu *menu = contextMenu(action);
0142     if (!menu) {
0143         return;
0144     }
0145     menu->setAttribute(Qt::WA_DeleteOnClose);
0146     menu->popup(d->parentMenu->mapToGlobal(pos));
0147 }
0148 
0149 QMenu *KBookmarkMenu::contextMenu(QAction *action)
0150 {
0151     KBookmarkActionInterface *act = dynamic_cast<KBookmarkActionInterface *>(action);
0152     if (!act) {
0153         return nullptr;
0154     }
0155     return new KBookmarkContextMenu(act->bookmark(), d->manager, d->owner);
0156 }
0157 
0158 bool KBookmarkMenu::isRoot() const
0159 {
0160     return d->isRoot;
0161 }
0162 
0163 bool KBookmarkMenu::isDirty() const
0164 {
0165     return d->dirty;
0166 }
0167 
0168 QString KBookmarkMenu::parentAddress() const
0169 {
0170     return d->parentAddress;
0171 }
0172 
0173 KBookmarkManager *KBookmarkMenu::manager() const
0174 {
0175     return d->manager;
0176 }
0177 
0178 KBookmarkOwner *KBookmarkMenu::owner() const
0179 {
0180     return d->owner;
0181 }
0182 
0183 QMenu *KBookmarkMenu::parentMenu() const
0184 {
0185     return d->parentMenu;
0186 }
0187 
0188 /********************************************************************/
0189 /********************************************************************/
0190 /********************************************************************/
0191 
0192 /********************************************************************/
0193 /********************************************************************/
0194 /********************************************************************/
0195 
0196 void KBookmarkMenu::slotBookmarksChanged(const QString &groupAddress)
0197 {
0198     qCDebug(KBOOKMARKSWIDGETS_LOG) << "KBookmarkMenu::slotBookmarksChanged groupAddress: " << groupAddress;
0199     if (groupAddress == d->parentAddress) {
0200         // qCDebug(KBOOKMARKS_LOG) << "KBookmarkMenu::slotBookmarksChanged -> setting m_bDirty on " << groupAddress;
0201         d->dirty = true;
0202     } else {
0203         // Iterate recursively into child menus
0204         for (QList<KBookmarkMenu *>::iterator it = m_lstSubMenus.begin(), end = m_lstSubMenus.end(); it != end; ++it) {
0205             (*it)->slotBookmarksChanged(groupAddress);
0206         }
0207     }
0208 }
0209 
0210 void KBookmarkMenu::clear()
0211 {
0212     qDeleteAll(m_lstSubMenus);
0213     m_lstSubMenus.clear();
0214 
0215     for (QList<QAction *>::iterator it = m_actions.begin(), end = m_actions.end(); it != end; ++it) {
0216         d->parentMenu->removeAction(*it);
0217         delete *it;
0218     }
0219 
0220     d->parentMenu->clear();
0221     m_actions.clear();
0222 }
0223 
0224 void KBookmarkMenu::refill()
0225 {
0226     // qCDebug(KBOOKMARKS_LOG) << "KBookmarkMenu::refill()";
0227     if (d->isRoot) {
0228         addActions();
0229     }
0230     fillBookmarks();
0231     if (!d->isRoot) {
0232         addActions();
0233     }
0234 }
0235 
0236 void KBookmarkMenu::addOpenInTabs()
0237 {
0238     if (!d->owner || !d->owner->supportsTabs() || !KAuthorized::authorizeAction(QStringLiteral("bookmarks"))) {
0239         return;
0240     }
0241 
0242     const QString title = tr("Open Folder in Tabs", "@action:inmenu");
0243 
0244     QAction *paOpenFolderInTabs = new QAction(title, this);
0245     paOpenFolderInTabs->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
0246     paOpenFolderInTabs->setToolTip(tr("Open all bookmarks in this folder as a new tab", "@info:tooltip"));
0247     paOpenFolderInTabs->setStatusTip(paOpenFolderInTabs->toolTip());
0248     connect(paOpenFolderInTabs, &QAction::triggered, this, &KBookmarkMenu::slotOpenFolderInTabs);
0249 
0250     d->parentMenu->addAction(paOpenFolderInTabs);
0251     m_actions.append(paOpenFolderInTabs);
0252 }
0253 
0254 void KBookmarkMenu::addAddBookmarksList()
0255 {
0256     if (!d->owner || !d->owner->enableOption(KBookmarkOwner::ShowAddBookmark) || !d->owner->supportsTabs()
0257         || !KAuthorized::authorizeAction(QStringLiteral("bookmarks"))) {
0258         return;
0259     }
0260 
0261     if (!d->bookmarksToFolderAction) {
0262         const QString title = tr("Bookmark Tabs as Folder...", "@action:inmenu");
0263         d->bookmarksToFolderAction = new QAction(title, this);
0264 
0265         if (d->isRoot) {
0266             d->bookmarksToFolderAction->setObjectName(QStringLiteral("add_bookmarks_list"));
0267         }
0268 
0269         d->bookmarksToFolderAction->setIcon(QIcon::fromTheme(QStringLiteral("bookmark-new-list")));
0270         d->bookmarksToFolderAction->setToolTip(tr("Add a folder of bookmarks for all open tabs", "@info:tooltip"));
0271         d->bookmarksToFolderAction->setStatusTip(d->bookmarksToFolderAction->toolTip());
0272         connect(d->bookmarksToFolderAction, &QAction::triggered, this, &KBookmarkMenu::slotAddBookmarksList);
0273     }
0274 
0275     d->parentMenu->addAction(d->bookmarksToFolderAction);
0276 }
0277 
0278 void KBookmarkMenu::addAddBookmark()
0279 {
0280     if (!d->owner || !d->owner->enableOption(KBookmarkOwner::ShowAddBookmark) || !KAuthorized::authorizeAction(QStringLiteral("bookmarks"))) {
0281         return;
0282     }
0283 
0284     if (!d->addBookmarkAction) {
0285         d->addBookmarkAction = KStandardAction::addBookmark(this, &KBookmarkMenu::slotAddBookmark, this);
0286         if (d->isRoot) {
0287             d->addBookmarkAction->setObjectName(QStringLiteral("add_bookmark"));
0288         }
0289 
0290         if (!d->isRoot) {
0291             d->addBookmarkAction->setShortcut(QKeySequence());
0292         }
0293     }
0294 
0295     d->parentMenu->addAction(d->addBookmarkAction);
0296 }
0297 
0298 void KBookmarkMenu::addEditBookmarks()
0299 {
0300     if ((d->owner && !d->owner->enableOption(KBookmarkOwner::ShowEditBookmark))
0301         || QStandardPaths::findExecutable(QStringLiteral(KEDITBOOKMARKS_BINARY)).isEmpty() || !KAuthorized::authorizeAction(QStringLiteral("bookmarks"))) {
0302         return;
0303     }
0304 
0305     d->editBookmarksAction = KStandardAction::editBookmarks(this, &KBookmarkMenu::slotEditBookmarks, this);
0306     d->editBookmarksAction->setObjectName(QStringLiteral("edit_bookmarks"));
0307 
0308     d->parentMenu->addAction(d->editBookmarksAction);
0309     d->editBookmarksAction->setToolTip(tr("Edit your bookmark collection in a separate window", "@info:tooltip"));
0310     d->editBookmarksAction->setStatusTip(d->editBookmarksAction->toolTip());
0311 }
0312 
0313 void KBookmarkMenu::slotEditBookmarks()
0314 {
0315     KEditBookmarks editBookmarks;
0316     editBookmarks.setBrowserMode(d->browserMode);
0317     auto result = editBookmarks.openForFile(d->manager->path());
0318 
0319     if (!result.sucess()) {
0320         QMessageBox::critical(QApplication::activeWindow(), QApplication::applicationDisplayName(), result.errorMessage());
0321     }
0322 }
0323 
0324 void KBookmarkMenu::addNewFolder()
0325 {
0326     if (!d->owner || !d->owner->enableOption(KBookmarkOwner::ShowAddBookmark) || !KAuthorized::authorizeAction(QStringLiteral("bookmarks"))) {
0327         return;
0328     }
0329 
0330     if (!d->newBookmarkFolderAction) {
0331         d->newBookmarkFolderAction = new QAction(tr("New Bookmark Folder...", "@action:inmenu"), this);
0332         d->newBookmarkFolderAction->setIcon(QIcon::fromTheme(QStringLiteral("folder-new")));
0333         d->newBookmarkFolderAction->setToolTip(tr("Create a new bookmark folder in this menu", "@info:tooltip"));
0334         d->newBookmarkFolderAction->setStatusTip(d->newBookmarkFolderAction->toolTip());
0335 
0336         if (d->isRoot) {
0337             d->newBookmarkFolderAction->setObjectName(QStringLiteral("new_bookmark_folder"));
0338         }
0339 
0340         connect(d->newBookmarkFolderAction, &QAction::triggered, this, &KBookmarkMenu::slotNewFolder);
0341     }
0342 
0343     d->parentMenu->addAction(d->newBookmarkFolderAction);
0344 }
0345 
0346 void KBookmarkMenu::fillBookmarks()
0347 {
0348     KBookmarkGroup parentBookmark = d->manager->findByAddress(d->parentAddress).toGroup();
0349     Q_ASSERT(!parentBookmark.isNull());
0350 
0351     if (d->isRoot && !parentBookmark.first().isNull()) { // at least one bookmark
0352         d->parentMenu->addSeparator();
0353     }
0354 
0355     for (KBookmark bm = parentBookmark.first(); !bm.isNull(); bm = parentBookmark.next(bm)) {
0356         d->parentMenu->addAction(actionForBookmark(bm));
0357     }
0358 }
0359 
0360 QAction *KBookmarkMenu::actionForBookmark(const KBookmark &bm)
0361 {
0362     if (bm.isGroup()) {
0363         // qCDebug(KBOOKMARKS_LOG) << "Creating bookmark submenu named " << bm.text();
0364         KActionMenu *actionMenu = new KBookmarkActionMenu(bm, this);
0365         m_actions.append(actionMenu);
0366         KBookmarkMenu *subMenu = new KBookmarkMenu(d->manager, d->owner, actionMenu->menu(), bm.address());
0367         m_lstSubMenus.append(subMenu);
0368         return actionMenu;
0369     } else if (bm.isSeparator()) {
0370         QAction *sa = new QAction(this);
0371         sa->setSeparator(true);
0372         m_actions.append(sa);
0373         return sa;
0374     } else {
0375         // qCDebug(KBOOKMARKS_LOG) << "Creating bookmark menu item for " << bm.text();
0376         QAction *action = new KBookmarkAction(bm, d->owner, this);
0377         m_actions.append(action);
0378         return action;
0379     }
0380 }
0381 
0382 void KBookmarkMenu::slotAddBookmarksList()
0383 {
0384     if (!d->owner || !d->owner->supportsTabs()) {
0385         return;
0386     }
0387 
0388     KBookmarkGroup parentBookmark = d->manager->findByAddress(d->parentAddress).toGroup();
0389 
0390     KBookmarkDialog *dlg = new KBookmarkDialog(d->manager, QApplication::activeWindow());
0391     dlg->addBookmarks(d->owner->currentBookmarkList(), QLatin1String(""), parentBookmark);
0392     delete dlg;
0393 }
0394 
0395 void KBookmarkMenu::slotAddBookmark()
0396 {
0397     if (!d->owner) {
0398         return;
0399     }
0400     if (d->owner->currentTitle().isEmpty() && d->owner->currentUrl().isEmpty()) {
0401         return;
0402     }
0403     KBookmarkGroup parentBookmark = d->manager->findByAddress(d->parentAddress).toGroup();
0404 
0405     if (KBookmarkSettings::self()->m_advancedaddbookmark) {
0406         KBookmarkDialog *dlg = new KBookmarkDialog(d->manager, QApplication::activeWindow());
0407         dlg->addBookmark(d->owner->currentTitle(), d->owner->currentUrl(), d->owner->currentIcon(), parentBookmark);
0408         delete dlg;
0409     } else {
0410         parentBookmark.addBookmark(d->owner->currentTitle(), d->owner->currentUrl(), d->owner->currentIcon());
0411         d->manager->emitChanged(parentBookmark);
0412     }
0413 }
0414 
0415 void KBookmarkMenu::slotOpenFolderInTabs()
0416 {
0417     d->owner->openFolderinTabs(d->manager->findByAddress(d->parentAddress).toGroup());
0418 }
0419 
0420 void KBookmarkMenu::slotNewFolder()
0421 {
0422     if (!d->owner) {
0423         return; // this view doesn't handle bookmarks...
0424     }
0425     KBookmarkGroup parentBookmark = d->manager->findByAddress(d->parentAddress).toGroup();
0426     Q_ASSERT(!parentBookmark.isNull());
0427     KBookmarkDialog *dlg = new KBookmarkDialog(d->manager, QApplication::activeWindow());
0428     dlg->createNewFolder(QLatin1String(""), parentBookmark);
0429     delete dlg;
0430 }
0431 
0432 QAction *KBookmarkMenu::addBookmarkAction() const
0433 {
0434     return d->addBookmarkAction;
0435 }
0436 
0437 QAction *KBookmarkMenu::bookmarkTabsAsFolderAction() const
0438 {
0439     return d->bookmarksToFolderAction;
0440 }
0441 
0442 QAction *KBookmarkMenu::newBookmarkFolderAction() const
0443 {
0444     return d->newBookmarkFolderAction;
0445 }
0446 
0447 QAction *KBookmarkMenu::editBookmarksAction() const
0448 {
0449     return d->editBookmarksAction;
0450 }
0451 
0452 void KBookmarkMenu::setBrowserMode(bool browserMode)
0453 {
0454     d->browserMode = browserMode;
0455 }
0456 
0457 bool KBookmarkMenu::browserMode() const
0458 {
0459     return d->browserMode;
0460 }
0461 
0462 #include "moc_kbookmarkmenu.cpp"