1 /* This file is part of the KDE project
2     SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org>
3     SPDX-FileCopyrightText: 2006 Daniel Teske <teske@squorn.de>
4 
5     SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "konqbookmarkmenu.h"
9 #include "kbookmarkowner.h"
10 #include "kbookmarkaction.h"
11 
12 #include <QMenu>
13 #include <QFile>
14 
15 #include <kconfig.h>
16 #include <ksharedconfig.h>
17 #include <kconfiggroup.h>
18 #include <kactioncollection.h>
19 #include <kstringhandler.h>
20 
21 #include "kbookmarkimporter.h"
22 #include "kbookmarkimporter_opera.h"
23 #include "kbookmarkimporter_ie.h"
24 #include "kbookmarkmanager.h"
25 #include "konqbookmarkmenu_p.h"
26 #include "konqpixmapprovider.h"
27 
28 using namespace Konqueror;
29 
KImportedBookmarkMenu(KBookmarkManager * mgr,KBookmarkOwner * owner,QMenu * parentMenu,const QString & type,const QString & location)30 KImportedBookmarkMenu::KImportedBookmarkMenu(KBookmarkManager *mgr,
31         KBookmarkOwner *owner, QMenu *parentMenu,
32         const QString &type, const QString &location)
33     : KBookmarkMenu(mgr, owner, parentMenu, QString()), m_type(type), m_location(location)
34 {
35     connect(parentMenu, &QMenu::aboutToShow, this, &KImportedBookmarkMenu::slotNSLoad);
36 }
37 
KImportedBookmarkMenu(KBookmarkManager * mgr,KBookmarkOwner * owner,QMenu * parentMenu)38 KImportedBookmarkMenu::KImportedBookmarkMenu(KBookmarkManager *mgr,
39         KBookmarkOwner *owner, QMenu *parentMenu)
40     : KBookmarkMenu(mgr, owner, parentMenu, QString()), m_type(QString()), m_location(QString())
41 {
42 }
43 
~KImportedBookmarkMenu()44 KImportedBookmarkMenu::~KImportedBookmarkMenu()
45 {
46 }
47 
refill()48 void KImportedBookmarkMenu::refill()
49 {
50 }
51 
clear()52 void KImportedBookmarkMenu::clear()
53 {
54 }
55 
slotNSLoad()56 void KImportedBookmarkMenu::slotNSLoad()
57 {
58     // qCDebug(KBOOKMARKS_LOG)<<"**** slotNSLoad  ****"<<m_type<<"  "<<m_location;
59     // only fill menu once
60     disconnect(parentMenu(), &QMenu::aboutToShow, nullptr, nullptr);
61 
62     // not NSImporter, but kept old name for BC reasons
63     KBookmarkMenuImporter importer(manager(), this);
64     importer.openBookmarks(m_location, m_type);
65 }
66 
67 /********************************************************************/
68 
openBookmarks(const QString & location,const QString & type)69 void KBookmarkMenuImporter::openBookmarks(const QString &location, const QString &type)
70 {
71     mstack.push(m_menu);
72 
73     KBookmarkImporterBase *importer = KBookmarkImporterBase::factory(type);
74     if (!importer) {
75         return;
76     }
77     importer->setFilename(location);
78     connectToImporter(*importer);
79     importer->parse();
80 
81     delete importer;
82 }
83 
connectToImporter(const QObject & importer)84 void KBookmarkMenuImporter::connectToImporter(const QObject &importer)
85 {
86     connect(&importer, SIGNAL(newBookmark(QString,QString,QString)),
87             SLOT(newBookmark(QString,QString,QString)));
88     connect(&importer, SIGNAL(newFolder(QString,bool,QString)),
89             SLOT(newFolder(QString,bool,QString)));
90     connect(&importer, SIGNAL(newSeparator()), SLOT(newSeparator()));
91     connect(&importer, SIGNAL(endFolder()), SLOT(endFolder()));
92 }
93 
newBookmark(const QString & text,const QString & url,const QString &)94 void KBookmarkMenuImporter::newBookmark(const QString &text, const QString &url, const QString &)
95 {
96     KBookmark bm = KBookmark::standaloneBookmark(text, QUrl(url), QStringLiteral("html"));
97     QAction *action = new KBookmarkAction(bm, mstack.top()->owner(), this);
98     mstack.top()->parentMenu()->addAction(action);
99     mstack.top()->m_actions.append(action);
100 }
101 
newFolder(const QString & text,bool,const QString &)102 void KBookmarkMenuImporter::newFolder(const QString &text, bool, const QString &)
103 {
104     QString _text = KStringHandler::csqueeze(text).replace(QLatin1Char('&'), QLatin1String("&&"));
105     KActionMenu *actionMenu = new KImportedBookmarkActionMenu(QIcon::fromTheme(QStringLiteral("folder")), _text, this);
106     mstack.top()->parentMenu()->addAction(actionMenu);
107     mstack.top()->m_actions.append(actionMenu);
108     KImportedBookmarkMenu *subMenu = new KImportedBookmarkMenu(m_pManager, m_menu->owner(), actionMenu->menu());
109     mstack.top()->m_lstSubMenus.append(subMenu);
110 
111     mstack.push(subMenu);
112 }
113 
newSeparator()114 void KBookmarkMenuImporter::newSeparator()
115 {
116     mstack.top()->parentMenu()->addSeparator();
117 }
118 
endFolder()119 void KBookmarkMenuImporter::endFolder()
120 {
121     mstack.pop();
122 }
123 
124 /********************************************************************/
125 
KonqBookmarkContextMenu(const KBookmark & bm,KBookmarkManager * mgr,KBookmarkOwner * owner)126 KonqBookmarkContextMenu::KonqBookmarkContextMenu(const KBookmark &bm, KBookmarkManager *mgr, KBookmarkOwner *owner)
127     : KBookmarkContextMenu(bm, mgr, owner)
128 {
129 }
130 
~KonqBookmarkContextMenu()131 KonqBookmarkContextMenu::~KonqBookmarkContextMenu()
132 {
133 }
134 
addActions()135 void KonqBookmarkContextMenu::addActions()
136 {
137     KConfigGroup config = KSharedConfig::openConfig(QStringLiteral("kbookmarkrc"), KConfig::NoGlobals)->group("Bookmarks");
138     bool filteredToolbar = config.readEntry("FilteredToolbar", false);
139 
140     if (bookmark().isGroup()) {
141         addOpenFolderInTabs();
142         addBookmark();
143 
144         if (filteredToolbar) {
145             QString text = bookmark().showInToolbar() ? tr("Hide in toolbar") : tr("Show in toolbar");
146             addAction(text, this, &KonqBookmarkContextMenu::toggleShowInToolbar);
147         }
148 
149         addFolderActions();
150     } else {
151         if (owner()) {
152             addAction(QIcon::fromTheme(QStringLiteral("window-new")), tr("Open in New Window"), this, &KonqBookmarkContextMenu::openInNewWindow);
153             addAction(QIcon::fromTheme(QStringLiteral("tab-new")), tr("Open in New Tab"), this, &KonqBookmarkContextMenu::openInNewTab);
154         }
155         addBookmark();
156 
157         if (filteredToolbar) {
158             QString text = bookmark().showInToolbar() ? tr("Hide in toolbar") : tr("Show in toolbar");
159             addAction(text, this, &KonqBookmarkContextMenu::toggleShowInToolbar);
160         }
161 
162         addBookmarkActions();
163     }
164 }
165 
toggleShowInToolbar()166 void KonqBookmarkContextMenu::toggleShowInToolbar()
167 {
168     bookmark().setShowInToolbar(!bookmark().showInToolbar());
169     manager()->emitChanged(bookmark().parentGroup());
170 }
171 
openInNewTab()172 void KonqBookmarkContextMenu::openInNewTab()
173 {
174     owner()->openInNewTab(bookmark());
175 }
176 
openInNewWindow()177 void KonqBookmarkContextMenu::openInNewWindow()
178 {
179     owner()->openInNewWindow(bookmark());
180 }
181 
182 /******************************/
183 /******************************/
184 /******************************/
185 
fillDynamicBookmarks()186 void KonqBookmarkMenu::fillDynamicBookmarks()
187 {
188     if (isDirty()
189             && KBookmarkManager::userBookmarksManager()->path() == manager()->path()) {
190         bool haveSep = false;
191 
192         const QStringList keys = KonqBookmarkMenu::dynamicBookmarksList();
193         for (QStringList::const_iterator it = keys.begin(); it != keys.end(); ++it) {
194             DynMenuInfo info;
195             info = showDynamicBookmarks((*it));
196 
197             if (!info.show || !QFile::exists(info.location)) {
198                 continue;
199             }
200 
201             if (!haveSep) {
202                 parentMenu()->addSeparator();
203                 haveSep = true;
204             }
205 
206             KActionMenu *actionMenu;
207             actionMenu = new KActionMenu(QIcon::fromTheme(info.type), info.name, this);
208             m_actionCollection->addAction(QStringLiteral("kbookmarkmenu"), actionMenu);
209 
210             parentMenu()->addAction(actionMenu);
211             m_actions.append(actionMenu);
212 
213             KImportedBookmarkMenu *subMenu =
214                 new KImportedBookmarkMenu(manager(), owner(), actionMenu->menu(),
215                                           info.type, info.location);
216             m_lstSubMenus.append(subMenu);
217         }
218     }
219 }
220 
refill()221 void KonqBookmarkMenu::refill()
222 {
223     if (isRoot()) {
224         addActions();
225     }
226     fillDynamicBookmarks();
227     fillBookmarks();
228     if (!isRoot()) {
229         addActions();
230     }
231 }
232 
actionForBookmark(const KBookmark & _bm)233 QAction *KonqBookmarkMenu::actionForBookmark(const KBookmark &_bm)
234 {
235     //We need a non-const copy of it
236     KBookmark bm(_bm);
237     if (bm.isGroup()) {
238         // qCDebug(KBOOKMARKS_LOG) << "Creating Konq bookmark submenu named " << bm.text();
239         KBookmarkActionMenu *actionMenu = new KBookmarkActionMenu(bm, this);
240         m_actionCollection->addAction(QStringLiteral("kbookmarkmenu"), actionMenu);
241         m_actions.append(actionMenu);
242 
243         KBookmarkMenu *subMenu = new KonqBookmarkMenu(manager(), owner(), actionMenu, bm.address());
244 
245         m_lstSubMenus.append(subMenu);
246         return actionMenu;
247     } else if (bm.isSeparator()) {
248         return KBookmarkMenu::actionForBookmark(bm);
249     } else {
250         // qCDebug(KBOOKMARKS_LOG) << "Creating Konq bookmark action named " << bm.text();
251         QUrl host = bm.url().adjusted(QUrl::RemovePath | QUrl::RemoveQuery);
252             bm.setIcon(KonqPixmapProvider::self()->iconNameFor(host));
253         KBookmarkAction *action = new KBookmarkAction(bm, owner(), this);
254             connect(KonqPixmapProvider::self(), &KonqPixmapProvider::changed, action, [host, action]() {
255                 action->setIcon(KonqPixmapProvider::self()->iconForUrl(host));
256             });
257         KonqPixmapProvider::self()->downloadHostIcon(host);
258         m_actionCollection->addAction(action->objectName(), action);
259         m_actions.append(action);
260         return action;
261     }
262 }
263 
showDynamicBookmarks(const QString & id)264 KonqBookmarkMenu::DynMenuInfo KonqBookmarkMenu::showDynamicBookmarks(const QString &id)
265 {
266     KConfig bookmarkrc(QStringLiteral("kbookmarkrc"), KConfig::NoGlobals);
267     KConfigGroup config(&bookmarkrc, "Bookmarks");
268 
269     DynMenuInfo info;
270     info.show = false;
271     info.d = nullptr;
272 
273     if (!config.hasKey("DynamicMenus")) {
274         const QString dynamicMenuGroupId = QLatin1String("DynamicMenu-") + id;
275         if (bookmarkrc.hasGroup(dynamicMenuGroupId)) {
276             KConfigGroup dynGroup(&bookmarkrc, dynamicMenuGroupId);
277             info.show = dynGroup.readEntry("Show", false);
278             info.location = dynGroup.readPathEntry("Location", QString());
279             info.type = dynGroup.readEntry("Type");
280             info.name = dynGroup.readEntry("Name");
281         }
282     }
283     return info;
284 }
285 
dynamicBookmarksList()286 QStringList KonqBookmarkMenu::dynamicBookmarksList()
287 {
288     KConfigGroup config = KSharedConfig::openConfig(QStringLiteral("kbookmarkrc"), KConfig::NoGlobals)->group("Bookmarks");
289 
290     QStringList mlist;
291     if (config.hasKey("DynamicMenus")) {
292         mlist = config.readEntry("DynamicMenus", QStringList());
293     }
294 
295     return mlist;
296 }
297 
setDynamicBookmarks(const QString & id,const DynMenuInfo & newMenu)298 void KonqBookmarkMenu::setDynamicBookmarks(const QString &id, const DynMenuInfo &newMenu)
299 {
300     KSharedConfig::Ptr kbookmarkrc = KSharedConfig::openConfig(QStringLiteral("kbookmarkrc"), KConfig::NoGlobals);
301     KConfigGroup dynConfig = kbookmarkrc->group(QLatin1String("DynamicMenu-") + id);
302 
303     // add group unconditionally
304     dynConfig.writeEntry("Show", newMenu.show);
305     dynConfig.writePathEntry("Location", newMenu.location);
306     dynConfig.writeEntry("Type", newMenu.type);
307     dynConfig.writeEntry("Name", newMenu.name);
308 
309     QStringList elist;
310     KConfigGroup config = kbookmarkrc->group("Bookmarks");
311     if (config.hasKey("DynamicMenus")) {
312         elist = config.readEntry("DynamicMenus", QStringList());
313     }
314 
315     // make sure list includes type
316     if (!elist.contains(id)) {
317         elist << id;
318         config.writeEntry("DynamicMenus", elist);
319     }
320 
321     config.sync();
322 }
323 
contextMenu(QAction * action)324 QMenu *KonqBookmarkMenu::contextMenu(QAction *action)
325 {
326     KBookmarkActionInterface *act = dynamic_cast<KBookmarkActionInterface *>(action);
327     if (!act) {
328         return nullptr;
329     }
330     return new KonqBookmarkContextMenu(act->bookmark(), manager(), owner());
331 }
332 
333 #include "moc_konqbookmarkmenu.cpp"
334