1 | /* |
2 | This file is part of the KDE project |
3 | SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org> |
4 | SPDX-FileCopyrightText: 2006 Daniel Teske <teske@squorn.de> |
5 | |
6 | SPDX-License-Identifier: LGPL-2.0-or-later |
7 | */ |
8 | |
9 | #include "kbookmarkmenu.h" |
10 | #include "kbookmarkmenu_p.h" |
11 | |
12 | #include "../kbookmarksettings_p.h" |
13 | #include "kbookmarkaction.h" |
14 | #include "kbookmarkaction_p.h" |
15 | #include "kbookmarkactionmenu.h" |
16 | #include "kbookmarkcontextmenu.h" |
17 | #include "kbookmarkdialog.h" |
18 | #include "kbookmarkmanager.h" |
19 | #include "kbookmarkowner.h" |
20 | #include "kbookmarkswidgets_debug.h" |
21 | #include "keditbookmarks_p.h" |
22 | |
23 | #include <KAuthorized> |
24 | #include <KStandardActions> |
25 | |
26 | #include <QApplication> |
27 | #include <QMenu> |
28 | #include <QMessageBox> |
29 | #include <QMouseEvent> |
30 | #include <QPointer> |
31 | #include <QStandardPaths> |
32 | |
33 | class : public QObject |
34 | { |
35 | public: |
36 | (KBookmarkMenu *, QMenu *const ) |
37 | : bookmarkMenu(bMenu) |
38 | , parentMenu(qMenu) |
39 | { |
40 | parentMenu->installEventFilter(filterObj: this); |
41 | } |
42 | |
43 | () |
44 | { |
45 | if (parentMenu) { |
46 | parentMenu->removeEventFilter(obj: this); |
47 | } |
48 | } |
49 | |
50 | bool (QObject *watched, QEvent *event) override |
51 | { |
52 | Q_ASSERT(watched == parentMenu); |
53 | |
54 | if (inFilter) { |
55 | return false; |
56 | } |
57 | |
58 | if (event->type() != QEvent::MouseButtonRelease) { |
59 | return false; |
60 | } |
61 | |
62 | const auto *me = static_cast<QMouseEvent *>(event); |
63 | |
64 | QAction *action = parentMenu->actionAt(me->position().toPoint()); |
65 | KBookmarkAction *bAction = dynamic_cast<KBookmarkAction *>(action); |
66 | if (!bAction) { |
67 | return false; |
68 | } |
69 | |
70 | KBookmarkActionPrivate *bActionPrivate = KBookmarkActionPrivate::get(a: bAction); |
71 | bActionPrivate->buttons = me->button() | me->buttons(); |
72 | inFilter = true; |
73 | QCoreApplication::sendEvent(receiver: parentMenu, event); |
74 | inFilter = false; |
75 | bActionPrivate->buttons = Qt::NoButton; |
76 | |
77 | return true; |
78 | } |
79 | |
80 | bool = false; |
81 | KBookmarkMenu *const ; |
82 | QPointer<QMenu> ; |
83 | }; |
84 | |
85 | class |
86 | { |
87 | public: |
88 | (KBookmarkMenu *, QMenu *const ) |
89 | : parentMenu(menu) |
90 | , eventFilter(bookmarkMenu, menu) |
91 | { |
92 | } |
93 | |
94 | QAction * = nullptr; |
95 | QAction * = nullptr; |
96 | QAction * = nullptr; |
97 | QAction * = nullptr; |
98 | bool = false; |
99 | bool ; |
100 | bool ; |
101 | KBookmarkManager *; |
102 | KBookmarkOwner *; |
103 | QMenu *const ; |
104 | QString ; |
105 | KBookmarkMenuEventFilter ; |
106 | }; |
107 | |
108 | KBookmarkMenu::(KBookmarkManager *manager, KBookmarkOwner *_owner, QMenu *) |
109 | : QObject() |
110 | , d(new KBookmarkMenuPrivate(this, _parentMenu)) |
111 | { |
112 | d->isRoot = true; |
113 | d->manager = manager; |
114 | d->owner = _owner; |
115 | d->parentAddress = QString(); // TODO KBookmarkAdress::root |
116 | // TODO KDE5 find a QMenu equvalnet for this one |
117 | // m_parentMenu->setKeyboardShortcutsEnabled( true ); |
118 | |
119 | init(); |
120 | } |
121 | |
122 | void KBookmarkMenu::() |
123 | { |
124 | connect(sender: d->parentMenu, signal: &QMenu::aboutToShow, context: this, slot: &KBookmarkMenu::slotAboutToShow); |
125 | |
126 | if (KBookmarkSettings::self()->m_contextmenu) { |
127 | d->parentMenu->setContextMenuPolicy(Qt::CustomContextMenu); |
128 | connect(sender: d->parentMenu, signal: &QWidget::customContextMenuRequested, context: this, slot: &KBookmarkMenu::slotCustomContextMenu); |
129 | } |
130 | |
131 | connect(sender: d->manager, signal: &KBookmarkManager::changed, context: this, slot: &KBookmarkMenu::slotBookmarksChanged); |
132 | |
133 | d->dirty = true; |
134 | addActions(); |
135 | } |
136 | |
137 | void KBookmarkMenu::() |
138 | { |
139 | if (d->isRoot) { |
140 | addAddBookmark(); |
141 | addAddBookmarksList(); |
142 | addNewFolder(); |
143 | addEditBookmarks(); |
144 | } else { |
145 | if (!d->parentMenu->actions().isEmpty()) { |
146 | d->parentMenu->addSeparator(); |
147 | } |
148 | |
149 | addOpenInTabs(); |
150 | addAddBookmark(); |
151 | addAddBookmarksList(); |
152 | addNewFolder(); |
153 | } |
154 | } |
155 | |
156 | KBookmarkMenu::(KBookmarkManager *mgr, KBookmarkOwner *_owner, QMenu *, const QString &parentAddress) |
157 | : QObject() |
158 | , d(new KBookmarkMenuPrivate(this, _parentMenu)) |
159 | { |
160 | d->isRoot = false; |
161 | d->manager = mgr; |
162 | d->owner = _owner; |
163 | d->parentAddress = parentAddress; |
164 | |
165 | connect(sender: _parentMenu, signal: &QMenu::aboutToShow, context: this, slot: &KBookmarkMenu::slotAboutToShow); |
166 | if (KBookmarkSettings::self()->m_contextmenu) { |
167 | d->parentMenu->setContextMenuPolicy(Qt::CustomContextMenu); |
168 | connect(sender: d->parentMenu, signal: &QWidget::customContextMenuRequested, context: this, slot: &KBookmarkMenu::slotCustomContextMenu); |
169 | } |
170 | d->dirty = true; |
171 | } |
172 | |
173 | KBookmarkMenu::() |
174 | { |
175 | qDeleteAll(c: m_lstSubMenus); |
176 | qDeleteAll(c: m_actions); |
177 | } |
178 | |
179 | void KBookmarkMenu::() |
180 | { |
181 | slotAboutToShow(); |
182 | } |
183 | |
184 | void KBookmarkMenu::() |
185 | { |
186 | // Did the bookmarks change since the last time we showed them ? |
187 | if (d->dirty) { |
188 | d->dirty = false; |
189 | clear(); |
190 | refill(); |
191 | d->parentMenu->adjustSize(); |
192 | } |
193 | } |
194 | |
195 | void KBookmarkMenu::(const QPoint &pos) |
196 | { |
197 | QAction *action = d->parentMenu->actionAt(pos); |
198 | QMenu * = contextMenu(action); |
199 | if (!menu) { |
200 | return; |
201 | } |
202 | menu->setAttribute(Qt::WA_DeleteOnClose); |
203 | menu->popup(pos: d->parentMenu->mapToGlobal(pos)); |
204 | } |
205 | |
206 | QMenu *KBookmarkMenu::(QAction *action) |
207 | { |
208 | KBookmarkActionInterface *act = dynamic_cast<KBookmarkActionInterface *>(action); |
209 | if (!act) { |
210 | return nullptr; |
211 | } |
212 | return new KBookmarkContextMenu(act->bookmark(), d->manager, d->owner); |
213 | } |
214 | |
215 | bool KBookmarkMenu::() const |
216 | { |
217 | return d->isRoot; |
218 | } |
219 | |
220 | bool KBookmarkMenu::() const |
221 | { |
222 | return d->dirty; |
223 | } |
224 | |
225 | QString KBookmarkMenu::() const |
226 | { |
227 | return d->parentAddress; |
228 | } |
229 | |
230 | KBookmarkManager *KBookmarkMenu::() const |
231 | { |
232 | return d->manager; |
233 | } |
234 | |
235 | KBookmarkOwner *KBookmarkMenu::() const |
236 | { |
237 | return d->owner; |
238 | } |
239 | |
240 | QMenu *KBookmarkMenu::() const |
241 | { |
242 | return d->parentMenu; |
243 | } |
244 | |
245 | void KBookmarkMenu::(const QString &groupAddress) |
246 | { |
247 | qCDebug(KBOOKMARKSWIDGETS_LOG) << "KBookmarkMenu::slotBookmarksChanged groupAddress: " << groupAddress; |
248 | if (groupAddress == d->parentAddress) { |
249 | // qCDebug(KBOOKMARKS_LOG) << "KBookmarkMenu::slotBookmarksChanged -> setting m_bDirty on " << groupAddress; |
250 | d->dirty = true; |
251 | } else { |
252 | // Iterate recursively into child menus |
253 | for (QList<KBookmarkMenu *>::iterator it = m_lstSubMenus.begin(), end = m_lstSubMenus.end(); it != end; ++it) { |
254 | (*it)->slotBookmarksChanged(groupAddress); |
255 | } |
256 | } |
257 | } |
258 | |
259 | void KBookmarkMenu::() |
260 | { |
261 | qDeleteAll(c: m_lstSubMenus); |
262 | m_lstSubMenus.clear(); |
263 | |
264 | for (QList<QAction *>::iterator it = m_actions.begin(), end = m_actions.end(); it != end; ++it) { |
265 | d->parentMenu->removeAction(action: *it); |
266 | delete *it; |
267 | } |
268 | |
269 | d->parentMenu->clear(); |
270 | m_actions.clear(); |
271 | } |
272 | |
273 | void KBookmarkMenu::() |
274 | { |
275 | // qCDebug(KBOOKMARKS_LOG) << "KBookmarkMenu::refill()"; |
276 | if (d->isRoot) { |
277 | addActions(); |
278 | } |
279 | fillBookmarks(); |
280 | if (!d->isRoot) { |
281 | addActions(); |
282 | } |
283 | } |
284 | |
285 | void KBookmarkMenu::() |
286 | { |
287 | if (!d->owner || !d->owner->supportsTabs() || !KAuthorized::authorizeAction(QStringLiteral("bookmarks" ))) { |
288 | return; |
289 | } |
290 | |
291 | const QString title = tr(s: "Open Folder in Tabs" , c: "@action:inmenu" ); |
292 | |
293 | QAction *paOpenFolderInTabs = new QAction(title, this); |
294 | paOpenFolderInTabs->setIcon(QIcon::fromTheme(QStringLiteral("tab-new" ))); |
295 | paOpenFolderInTabs->setToolTip(tr(s: "Open all bookmarks in this folder as a new tab" , c: "@info:tooltip" )); |
296 | paOpenFolderInTabs->setStatusTip(paOpenFolderInTabs->toolTip()); |
297 | connect(sender: paOpenFolderInTabs, signal: &QAction::triggered, context: this, slot: &KBookmarkMenu::slotOpenFolderInTabs); |
298 | |
299 | d->parentMenu->addAction(action: paOpenFolderInTabs); |
300 | m_actions.append(t: paOpenFolderInTabs); |
301 | } |
302 | |
303 | void KBookmarkMenu::() |
304 | { |
305 | if (!d->owner || !d->owner->enableOption(option: KBookmarkOwner::ShowAddBookmark) || !d->owner->supportsTabs() |
306 | || !KAuthorized::authorizeAction(QStringLiteral("bookmarks" ))) { |
307 | return; |
308 | } |
309 | |
310 | if (!d->bookmarksToFolderAction) { |
311 | const QString title = tr(s: "Bookmark Tabs as Folder…" , c: "@action:inmenu" ); |
312 | d->bookmarksToFolderAction = new QAction(title, this); |
313 | |
314 | if (d->isRoot) { |
315 | d->bookmarksToFolderAction->setObjectName(QStringLiteral("add_bookmarks_list" )); |
316 | } |
317 | |
318 | d->bookmarksToFolderAction->setIcon(QIcon::fromTheme(QStringLiteral("bookmark-new-list" ))); |
319 | d->bookmarksToFolderAction->setToolTip(tr(s: "Add a folder of bookmarks for all open tabs" , c: "@info:tooltip" )); |
320 | d->bookmarksToFolderAction->setStatusTip(d->bookmarksToFolderAction->toolTip()); |
321 | connect(sender: d->bookmarksToFolderAction, signal: &QAction::triggered, context: this, slot: &KBookmarkMenu::slotAddBookmarksList); |
322 | } |
323 | |
324 | d->parentMenu->addAction(action: d->bookmarksToFolderAction); |
325 | } |
326 | |
327 | void KBookmarkMenu::() |
328 | { |
329 | if (!d->owner || !d->owner->enableOption(option: KBookmarkOwner::ShowAddBookmark) || !KAuthorized::authorizeAction(QStringLiteral("bookmarks" ))) { |
330 | return; |
331 | } |
332 | |
333 | if (!d->addBookmarkAction) { |
334 | d->addBookmarkAction = KStandardActions::addBookmark(recvr: this, slot: &KBookmarkMenu::slotAddBookmark, parent: this); |
335 | if (d->isRoot) { |
336 | d->addBookmarkAction->setObjectName(QStringLiteral("add_bookmark" )); |
337 | } |
338 | |
339 | if (!d->isRoot) { |
340 | d->addBookmarkAction->setShortcut(QKeySequence()); |
341 | } |
342 | } |
343 | |
344 | d->parentMenu->addAction(action: d->addBookmarkAction); |
345 | } |
346 | |
347 | void KBookmarkMenu::() |
348 | { |
349 | if ((d->owner && !d->owner->enableOption(option: KBookmarkOwner::ShowEditBookmark)) |
350 | || QStandardPaths::findExecutable(QStringLiteral(KEDITBOOKMARKS_BINARY)).isEmpty() || !KAuthorized::authorizeAction(QStringLiteral("bookmarks" ))) { |
351 | return; |
352 | } |
353 | |
354 | d->editBookmarksAction = KStandardActions::editBookmarks(recvr: this, slot: &KBookmarkMenu::slotEditBookmarks, parent: this); |
355 | d->editBookmarksAction->setObjectName(QStringLiteral("edit_bookmarks" )); |
356 | |
357 | d->parentMenu->addAction(action: d->editBookmarksAction); |
358 | d->editBookmarksAction->setToolTip(tr(s: "Edit your bookmark collection in a separate window" , c: "@info:tooltip" )); |
359 | d->editBookmarksAction->setStatusTip(d->editBookmarksAction->toolTip()); |
360 | } |
361 | |
362 | void KBookmarkMenu::() |
363 | { |
364 | KEditBookmarks editBookmarks; |
365 | editBookmarks.setBrowserMode(d->browserMode); |
366 | auto result = editBookmarks.openForFile(file: d->manager->path()); |
367 | |
368 | if (!result.sucess()) { |
369 | QMessageBox::critical(parent: QApplication::activeWindow(), title: QApplication::applicationDisplayName(), text: result.errorMessage()); |
370 | } |
371 | } |
372 | |
373 | void KBookmarkMenu::() |
374 | { |
375 | if (!d->owner || !d->owner->enableOption(option: KBookmarkOwner::ShowAddBookmark) || !KAuthorized::authorizeAction(QStringLiteral("bookmarks" ))) { |
376 | return; |
377 | } |
378 | |
379 | if (!d->newBookmarkFolderAction) { |
380 | d->newBookmarkFolderAction = new QAction(tr(s: "New Bookmark Folder…" , c: "@action:inmenu" ), this); |
381 | d->newBookmarkFolderAction->setIcon(QIcon::fromTheme(QStringLiteral("folder-new" ))); |
382 | d->newBookmarkFolderAction->setToolTip(tr(s: "Create a new bookmark folder in this menu" , c: "@info:tooltip" )); |
383 | d->newBookmarkFolderAction->setStatusTip(d->newBookmarkFolderAction->toolTip()); |
384 | |
385 | if (d->isRoot) { |
386 | d->newBookmarkFolderAction->setObjectName(QStringLiteral("new_bookmark_folder" )); |
387 | } |
388 | |
389 | connect(sender: d->newBookmarkFolderAction, signal: &QAction::triggered, context: this, slot: &KBookmarkMenu::slotNewFolder); |
390 | } |
391 | |
392 | d->parentMenu->addAction(action: d->newBookmarkFolderAction); |
393 | } |
394 | |
395 | void KBookmarkMenu::() |
396 | { |
397 | KBookmarkGroup parentBookmark = d->manager->findByAddress(address: d->parentAddress).toGroup(); |
398 | Q_ASSERT(!parentBookmark.isNull()); |
399 | |
400 | if (d->isRoot && !parentBookmark.first().isNull()) { // at least one bookmark |
401 | d->parentMenu->addSeparator(); |
402 | } |
403 | |
404 | for (KBookmark bm = parentBookmark.first(); !bm.isNull(); bm = parentBookmark.next(current: bm)) { |
405 | d->parentMenu->addAction(action: actionForBookmark(bm)); |
406 | } |
407 | } |
408 | |
409 | QAction *KBookmarkMenu::(const KBookmark &bm) |
410 | { |
411 | if (bm.isGroup()) { |
412 | // qCDebug(KBOOKMARKS_LOG) << "Creating bookmark submenu named " << bm.text(); |
413 | KActionMenu * = new KBookmarkActionMenu(bm, this); |
414 | m_actions.append(t: actionMenu); |
415 | KBookmarkMenu * = new KBookmarkMenu(d->manager, d->owner, actionMenu->menu(), bm.address()); |
416 | m_lstSubMenus.append(t: subMenu); |
417 | return actionMenu; |
418 | } else if (bm.isSeparator()) { |
419 | QAction *sa = new QAction(this); |
420 | sa->setSeparator(true); |
421 | m_actions.append(t: sa); |
422 | return sa; |
423 | } else { |
424 | // qCDebug(KBOOKMARKS_LOG) << "Creating bookmark menu item for " << bm.text(); |
425 | QAction *action = new KBookmarkAction(bm, d->owner, this); |
426 | m_actions.append(t: action); |
427 | return action; |
428 | } |
429 | } |
430 | |
431 | void KBookmarkMenu::() |
432 | { |
433 | if (!d->owner || !d->owner->supportsTabs()) { |
434 | return; |
435 | } |
436 | |
437 | KBookmarkGroup parentBookmark = d->manager->findByAddress(address: d->parentAddress).toGroup(); |
438 | |
439 | KBookmarkDialog *dlg = new KBookmarkDialog(d->manager, QApplication::activeWindow()); |
440 | dlg->addBookmarks(list: d->owner->currentBookmarkList(), name: QLatin1String("" ), parent: parentBookmark); |
441 | delete dlg; |
442 | } |
443 | |
444 | void KBookmarkMenu::() |
445 | { |
446 | if (!d->owner) { |
447 | return; |
448 | } |
449 | if (d->owner->currentTitle().isEmpty() && d->owner->currentUrl().isEmpty()) { |
450 | return; |
451 | } |
452 | KBookmarkGroup parentBookmark = d->manager->findByAddress(address: d->parentAddress).toGroup(); |
453 | |
454 | if (KBookmarkSettings::self()->m_advancedaddbookmark) { |
455 | KBookmarkDialog *dlg = new KBookmarkDialog(d->manager, QApplication::activeWindow()); |
456 | dlg->addBookmark(title: d->owner->currentTitle(), url: d->owner->currentUrl(), icon: d->owner->currentIcon(), parent: parentBookmark); |
457 | delete dlg; |
458 | } else { |
459 | parentBookmark.addBookmark(text: d->owner->currentTitle(), url: d->owner->currentUrl(), icon: d->owner->currentIcon()); |
460 | d->manager->emitChanged(group: parentBookmark); |
461 | } |
462 | } |
463 | |
464 | void KBookmarkMenu::() |
465 | { |
466 | d->owner->openFolderinTabs(bm: d->manager->findByAddress(address: d->parentAddress).toGroup()); |
467 | } |
468 | |
469 | void KBookmarkMenu::() |
470 | { |
471 | if (!d->owner) { |
472 | return; // this view doesn't handle bookmarks... |
473 | } |
474 | KBookmarkGroup parentBookmark = d->manager->findByAddress(address: d->parentAddress).toGroup(); |
475 | Q_ASSERT(!parentBookmark.isNull()); |
476 | KBookmarkDialog *dlg = new KBookmarkDialog(d->manager, QApplication::activeWindow()); |
477 | dlg->createNewFolder(name: QLatin1String("" ), parent: parentBookmark); |
478 | delete dlg; |
479 | } |
480 | |
481 | QAction *KBookmarkMenu::() const |
482 | { |
483 | return d->addBookmarkAction; |
484 | } |
485 | |
486 | QAction *KBookmarkMenu::() const |
487 | { |
488 | return d->bookmarksToFolderAction; |
489 | } |
490 | |
491 | QAction *KBookmarkMenu::() const |
492 | { |
493 | return d->newBookmarkFolderAction; |
494 | } |
495 | |
496 | QAction *KBookmarkMenu::() const |
497 | { |
498 | return d->editBookmarksAction; |
499 | } |
500 | |
501 | void KBookmarkMenu::(bool browserMode) |
502 | { |
503 | d->browserMode = browserMode; |
504 | } |
505 | |
506 | bool KBookmarkMenu::() const |
507 | { |
508 | return d->browserMode; |
509 | } |
510 | |
511 | #include "moc_kbookmarkmenu.cpp" |
512 | |