File indexing completed on 2024-04-21 14:53:28

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