1 /*
2 SPDX-FileCopyrightText: 2008 Xavier Vello <xavier.vello@gmail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5
6 */
7
8 #include "kio_bookmarks.h"
9
10 #include <stdio.h>
11 #include <stdlib.h>
12
13 #include <QRegularExpression>
14 #include <qtextdocument.h>
15 #include <qurlquery.h>
16
17 #include <kshell.h>
18
19 #include <KLocalizedString>
20 #include <kconfig.h>
21 #include <kconfiggroup.h>
22 #include <kbookmark.h>
23 #include <kbookmarkmanager.h>
24 #include <kimagecache.h>
25 #include <qdebug.h>
26 #include <kfileplacesmodel.h>
27 #include <solid/device.h>
28 #include <solid/deviceinterface.h>
29 #include <QGuiApplication>
30 #include <KIO/ApplicationLauncherJob>
31
32 using namespace KIO;
33
34 // Pseudo plugin class to embed meta data
35 class KIOPluginForMetaData : public QObject
36 {
37 Q_OBJECT
38 Q_PLUGIN_METADATA(IID "org.kde.kio.slave.bookmarks" FILE "bookmarks.json")
39 };
40
BookmarksProtocol(const QByteArray & pool,const QByteArray & app)41 BookmarksProtocol::BookmarksProtocol( const QByteArray &pool, const QByteArray &app )
42 : SlaveBase( "bookmarks", pool, app )
43 {
44 manager = KBookmarkManager::userBookmarksManager();
45 cfg = new KConfig( "kiobookmarksrc" );
46 config = cfg->group("General");
47 cache = new KImageCache("kio_bookmarks", config.readEntry("CacheSize", 5 * 1024) * 1024);
48 cache->setPixmapCaching(false);
49
50 indent = 0;
51 totalsize = 0;
52 columns = 4;
53 }
54
~BookmarksProtocol()55 BookmarksProtocol::~BookmarksProtocol()
56 {
57 delete manager;
58 delete cache;
59 delete cfg;
60 }
61
parseTree()62 void BookmarksProtocol::parseTree()
63 {
64 totalsize = 0;
65
66 cfg->reparseConfiguration();
67 columns = config.readEntry("Columns", 4);
68 if (columns < 1)
69 columns = 1;
70
71 manager->notifyCompleteChange("kio_bookmarks");
72 tree = manager->root();
73
74 if(tree.first().isNull())
75 return;
76
77 if(config.readEntry("FlattenTree", false))
78 flattenTree(tree);
79
80 KBookmarkGroup root;
81 if(config.readEntry("ShowRoot", true))
82 {
83 root = tree.createNewFolder(i18n("Root"));
84 tree.moveBookmark(root, KBookmark());
85 root.setIcon("konqueror");
86 }
87
88 KBookmark bm = tree.first();
89 KBookmark next;
90 while(!bm.isNull())
91 {
92 next = tree.next(bm);
93 if (bm.isSeparator())
94 tree.deleteBookmark(bm);
95 else if (bm.isGroup())
96 totalsize += sizeOfGroup(bm.toGroup());
97 else
98 {
99 if(config.readEntry("ShowRoot", true))
100 root.addBookmark(bm);
101
102 tree.deleteBookmark(bm);
103 }
104 bm = next;
105 }
106 if(config.readEntry("ShowRoot", true))
107 totalsize += sizeOfGroup(root);
108
109 if(config.readEntry("ShowPlaces", true))
110 totalsize += addPlaces();
111 }
112
addPlaces()113 int BookmarksProtocol::addPlaces()
114 {
115 KFilePlacesModel placesModel;
116 KBookmarkGroup folder = tree.createNewFolder(i18n("Places"));
117 QList<Solid::Device> batteryList = Solid::Device::listFromType(Solid::DeviceInterface::Battery, QString());
118
119 if (batteryList.isEmpty()) {
120 folder.setIcon("computer");
121 } else {
122 folder.setIcon("computer-laptop");
123 }
124
125 for (int row = 0; row < placesModel.rowCount(); ++row) {
126 QModelIndex index = placesModel.index(row, 0);
127
128 if (!placesModel.isHidden(index))
129 folder.addBookmark(placesModel.bookmarkForIndex(index));
130 }
131 return sizeOfGroup(folder);
132 }
133
flattenTree(const KBookmarkGroup & folder)134 void BookmarksProtocol::flattenTree( const KBookmarkGroup &folder )
135 {
136 KBookmark bm = folder.first();
137 KBookmark prev = folder;
138 KBookmark next;
139 while (!bm.isNull())
140 {
141 if (bm.isGroup()) {
142 flattenTree(bm.toGroup());
143 }
144
145 next = tree.next(bm);
146
147 if (bm.isGroup() && bm.parentGroup().hasParent()) {
148 bm.setFullText("| " + bm.parentGroup().fullText() + " > " + bm.fullText());
149 tree.moveBookmark(bm, prev);
150 prev = bm;
151 }
152 bm = next;
153 }
154 }
155
156 // Should really go to KBookmarkGroup
sizeOfGroup(const KBookmarkGroup & folder,bool real)157 int BookmarksProtocol::sizeOfGroup( const KBookmarkGroup &folder, bool real )
158 {
159 int size = 1; // counting the title line
160 for (KBookmark bm = folder.first(); !bm.isNull(); bm = folder.next(bm))
161 {
162 if (bm.isGroup())
163 size += sizeOfGroup(bm.toGroup());
164 else
165 size += 1;
166 }
167
168 // CSS sets a min-height for toplevel folders
169 if (folder.parentGroup() == tree && size < 8 && real == false)
170 size = 8;
171
172 return size;
173 }
174
get(const QUrl & url)175 void BookmarksProtocol::get( const QUrl& url )
176 {
177 QString path = url.path();
178 const QRegularExpression regexp(QStringLiteral("^/(background|icon)/([\\S]+)"));
179 QRegularExpressionMatch rmatch;
180
181 if (path.isEmpty() || path == "/") {
182 echoIndex();
183 } else if (path == "/config") {
184 const KService::Ptr bookmarksKCM = KService::serviceByDesktopName(QStringLiteral("bookmarks"));
185 if (bookmarksKCM) {
186 auto job = new KIO::ApplicationLauncherJob(bookmarksKCM);
187 job->start();
188 } else {
189 error(KIO::ERR_SLAVE_DEFINED, i18n("Could not find bookmarks config"));
190 }
191 echoHead("bookmarks:/");
192 } else if (path == "/editbookmarks") {
193 const KService::Ptr keditbookmarks = KService::serviceByDesktopName(QStringLiteral("org.kde.keditbookmarks"));
194 if (keditbookmarks) {
195 auto job = new KIO::ApplicationLauncherJob(keditbookmarks);
196 job->start();
197 } else {
198 error(KIO::ERR_SLAVE_DEFINED, i18n("Could not find bookmarks editor"));
199 }
200 echoHead("bookmarks:/");
201 } else if (path.indexOf(regexp, 0, &rmatch) >= 0) {
202 echoImage(rmatch.captured(1), rmatch.captured(2), QUrlQuery(url).queryItemValue("size"));
203 } else {
204 echoHead();
205 echo("<p class=\"message\">" + i18n("Wrong request: %1", url.toDisplayString().toHtmlEscaped()) + "</p>");
206 }
207 finished();
208 }
209
kdemain(int argc,char ** argv)210 extern "C" int Q_DECL_EXPORT kdemain(int argc, char **argv)
211 {
212 QGuiApplication app(argc, argv);
213 app.setApplicationName(QLatin1String("kio_bookmarks"));
214
215 if (argc != 4) {
216 qCritical() << "Usage: kio_bookmarks protocol domain-socket1 domain-socket2";
217 exit(-1);
218 }
219
220 BookmarksProtocol slave(argv[2], argv[3]);
221 slave.dispatchLoop();
222
223 return 0;
224 }
225
226 #include "kio_bookmarks.moc"
227