]> cloud.milkyroute.net Git - dolphin.git/blob - src/panels/places/placespanel.cpp
Provide additional default groups for the Places Panel
[dolphin.git] / src / panels / places / placespanel.cpp
1 /***************************************************************************
2 * Copyright (C) 2008-2012 by Peter Penz <peter.penz19@gmail.com> *
3 * *
4 * Based on KFilePlacesModel from kdelibs: *
5 * Copyright (C) 2007 Kevin Ottens <ervin@kde.org> *
6 * Copyright (C) 2007 David Faure <faure@kde.org> *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
22 ***************************************************************************/
23
24 #include "placespanel.h"
25
26 #ifdef HAVE_NEPOMUK
27 #include <Nepomuk/ResourceManager>
28 #include <Nepomuk/Query/ComparisonTerm>
29 #include <Nepomuk/Query/LiteralTerm>
30 #include <Nepomuk/Query/Query>
31 #include <Nepomuk/Query/ResourceTypeTerm>
32 #include <Nepomuk/Vocabulary/NFO>
33 #include <Nepomuk/Vocabulary/NIE>
34 #endif
35
36 #include <KBookmark>
37 #include <KBookmarkGroup>
38 #include <KBookmarkManager>
39 #include <KComponentData>
40 #include <KDebug>
41 #include <KIcon>
42 #include <KLocale>
43 #include <kitemviews/kitemlistcontainer.h>
44 #include <kitemviews/kitemlistcontroller.h>
45 #include <kitemviews/kstandarditem.h>
46 #include <kitemviews/kstandarditemlistview.h>
47 #include <kitemviews/kstandarditemmodel.h>
48 #include <KStandardDirs>
49 #include <KUser>
50 #include "placesitemlistgroupheader.h"
51 #include <views/draganddrophelper.h>
52 #include <QDir>
53 #include <QVBoxLayout>
54 #include <QShowEvent>
55
56 PlacesPanel::PlacesPanel(QWidget* parent) :
57 Panel(parent),
58 m_nepomukRunning(false),
59 m_controller(0),
60 m_model(0),
61 m_availableDevices(),
62 m_bookmarkManager(0),
63 m_defaultBookmarks(),
64 m_defaultBookmarksIndexes()
65 {
66 }
67
68 PlacesPanel::~PlacesPanel()
69 {
70 }
71
72 bool PlacesPanel::urlChanged()
73 {
74 return true;
75 }
76
77 void PlacesPanel::showEvent(QShowEvent* event)
78 {
79 if (event->spontaneous()) {
80 Panel::showEvent(event);
81 return;
82 }
83
84 if (!m_controller) {
85 // Postpone the creating of the controller to the first show event.
86 // This assures that no performance and memory overhead is given when the folders panel is not
87 // used at all and stays invisible.
88 #ifdef HAVE_NEPOMUK
89 m_nepomukRunning = (Nepomuk::ResourceManager::instance()->initialized());
90 #endif
91 createDefaultBookmarks();
92
93 const QString file = KStandardDirs::locateLocal("data", "kfileplaces/bookmarks.xml");
94 m_bookmarkManager = KBookmarkManager::managerForFile(file, "kfilePlaces");
95 m_model = new KStandardItemModel(this);
96 m_model->setGroupedSorting(true);
97 m_model->setSortRole("group");
98 loadBookmarks();
99
100 KStandardItemListView* view = new KStandardItemListView();
101 view->setGroupHeaderCreator(new KItemListGroupHeaderCreator<PlacesItemListGroupHeader>());
102
103 m_controller = new KItemListController(m_model, view, this);
104 m_controller->setSelectionBehavior(KItemListController::SingleSelection);
105 connect(m_controller, SIGNAL(itemActivated(int)), this, SLOT(slotItemActivated(int)));
106 connect(m_controller, SIGNAL(itemMiddleClicked(int)), this, SLOT(slotItemMiddleClicked(int)));
107 connect(m_controller, SIGNAL(itemContextMenuRequested(int,QPointF)), this, SLOT(slotItemContextMenuRequested(int,QPointF)));
108 connect(m_controller, SIGNAL(viewContextMenuRequested(QPointF)), this, SLOT(slotViewContextMenuRequested(QPointF)));
109
110 KItemListContainer* container = new KItemListContainer(m_controller, this);
111 container->setEnabledFrame(false);
112
113 QVBoxLayout* layout = new QVBoxLayout(this);
114 layout->setMargin(0);
115 layout->addWidget(container);
116 }
117
118 Panel::showEvent(event);
119 }
120
121 void PlacesPanel::slotItemActivated(int index)
122 {
123 const KUrl url = urlForIndex(index);
124 if (!url.isEmpty()) {
125 emit placeActivated(url);
126 }
127 }
128
129 void PlacesPanel::slotItemMiddleClicked(int index)
130 {
131 const KUrl url = urlForIndex(index);
132 if (!url.isEmpty()) {
133 emit placeMiddleClicked(url);
134 }
135 }
136
137 void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos)
138 {
139 Q_UNUSED(index);
140 Q_UNUSED(pos);
141 }
142
143 void PlacesPanel::slotViewContextMenuRequested(const QPointF& pos)
144 {
145 Q_UNUSED(pos);
146 }
147
148 void PlacesPanel::slotUrlsDropped(const KUrl& dest, QDropEvent* event, QWidget* parent)
149 {
150 Q_UNUSED(parent);
151 DragAndDropHelper::dropUrls(KFileItem(), dest, event);
152 }
153
154 void PlacesPanel::createDefaultBookmarks()
155 {
156 Q_ASSERT(m_defaultBookmarks.isEmpty());
157 Q_ASSERT(m_defaultBookmarksIndexes.isEmpty());
158
159 const QString placesGroup = i18nc("@item", "Places");
160 const QString recentlyAccessedGroup = i18nc("@item", "Recently Accessed");
161 const QString searchForGroup = i18nc("@item", "Search For");
162 const QString timeLineIcon = "package_utility_time"; // TODO: Ask the Oxygen team to create
163 // a custom icon for the timeline-protocol
164
165 m_defaultBookmarks.append(DefaultBookmarkData(KUrl(KUser().homeDir()),
166 "user-home",
167 i18nc("@item", "Home"),
168 placesGroup));
169 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("remote:/"),
170 "network-workgroup",
171 i18nc("@item", "Network"),
172 placesGroup));
173 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("/"),
174 "folder-red",
175 i18nc("@item", "Root"),
176 placesGroup));
177 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("trash:/"),
178 "user-trash",
179 i18nc("@item", "Trash"),
180 placesGroup));
181
182 if (m_nepomukRunning) {
183 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("timeline:/today"),
184 timeLineIcon,
185 i18nc("@item Recently Accessed", "Today"),
186 recentlyAccessedGroup));
187 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("timeline:/yesterday"),
188 timeLineIcon,
189 i18nc("@item Recently Accessed", "Yesterday"),
190 recentlyAccessedGroup));
191 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("timeline:/thismonth"),
192 timeLineIcon,
193 i18nc("@item Recently Accessed", "This Month"),
194 recentlyAccessedGroup));
195 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("timeline:/lastmonth"),
196 timeLineIcon,
197 i18nc("@item Recently Accessed", "Last Month"),
198 recentlyAccessedGroup));
199 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("search:/documents"),
200 "folder-txt",
201 i18nc("@item Commonly Accessed", "Documents"),
202 searchForGroup));
203 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("search:/images"),
204 "folder-image",
205 i18nc("@item Commonly Accessed", "Images"),
206 searchForGroup));
207 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("search:/music"),
208 "folder-sound",
209 i18nc("@item Commonly Accessed", "Music"),
210 searchForGroup));
211 m_defaultBookmarks.append(DefaultBookmarkData(KUrl("search:/videos"),
212 "folder-video",
213 i18nc("@item Commonly Accessed", "Videos"),
214 searchForGroup));
215 }
216
217 for (int i = 0; i < m_defaultBookmarks.count(); ++i) {
218 m_defaultBookmarksIndexes.insert(m_defaultBookmarks[i].url, i);
219 }
220 }
221
222 void PlacesPanel::loadBookmarks()
223 {
224 KBookmarkGroup root = m_bookmarkManager->root();
225 KBookmark bookmark = root.first();
226 QSet<QString> devices = m_availableDevices;
227
228 QSet<KUrl> missingDefaultBookmarks;
229 foreach (const DefaultBookmarkData& data, m_defaultBookmarks) {
230 missingDefaultBookmarks.insert(data.url);
231 }
232
233 while (!bookmark.isNull()) {
234 const QString udi = bookmark.metaDataItem("UDI");
235 const KUrl url = bookmark.url();
236 const QString appName = bookmark.metaDataItem("OnlyInApp");
237 const bool deviceAvailable = devices.remove(udi);
238
239 const bool allowedHere = (appName.isEmpty() || appName == KGlobal::mainComponent().componentName())
240 && (m_nepomukRunning || url.protocol() != QLatin1String("timeline"));
241
242 if ((udi.isEmpty() && allowedHere) || deviceAvailable) {
243 KStandardItem* item = new KStandardItem();
244 item->setIcon(KIcon(bookmark.icon()));
245 item->setDataValue("address", bookmark.address());
246 item->setDataValue("url", url);
247
248 if (missingDefaultBookmarks.contains(url)) {
249 missingDefaultBookmarks.remove(url);
250 // Always apply the translated text to the default bookmarks, otherwise an outdated
251 // translation might be shown.
252 const int index = m_defaultBookmarksIndexes.value(url);
253 item->setText(m_defaultBookmarks[index].text);
254 } else {
255 item->setText(bookmark.text());
256 }
257
258 if (deviceAvailable) {
259 item->setDataValue("udi", udi);
260 item->setGroup(i18nc("@item", "Devices"));
261 } else {
262 item->setGroup(i18nc("@item", "Places"));
263 }
264
265 m_model->appendItem(item);
266 }
267
268 bookmark = root.next(bookmark);
269 }
270
271 if (!missingDefaultBookmarks.isEmpty()) {
272 foreach (const DefaultBookmarkData& data, m_defaultBookmarks) {
273 if (missingDefaultBookmarks.contains(data.url)) {
274 KStandardItem* item = new KStandardItem();
275 item->setIcon(KIcon(data.icon));
276 item->setText(data.text);
277 item->setDataValue("url", data.url);
278 item->setGroup(data.group);
279 m_model->appendItem(item);
280 }
281 }
282 }
283 }
284
285 KUrl PlacesPanel::urlForIndex(int index) const
286 {
287 const KStandardItem* item = m_model->item(index);
288 if (!item) {
289 return KUrl();
290 }
291
292 KUrl url = item->dataValue("url").value<KUrl>();
293 if (url.protocol() == QLatin1String("timeline")) {
294 url = createTimelineUrl(url);
295 } else if (url.protocol() == QLatin1String("search")) {
296 url = createSearchUrl(url);
297 }
298
299 return url;
300 }
301
302 KUrl PlacesPanel::createTimelineUrl(const KUrl& url)
303 {
304 // TODO: Clarify with the Nepomuk-team whether it makes sense
305 // provide default-timeline-URLs like 'yesterday', 'this month'
306 // and 'last month'.
307 KUrl timelineUrl;
308
309 const QString path = url.pathOrUrl();
310 if (path.endsWith("yesterday")) {
311 const QDate date = QDate::currentDate().addDays(-1);
312 const int year = date.year();
313 const int month = date.month();
314 const int day = date.day();
315 timelineUrl = "timeline:/" + timelineDateString(year, month) +
316 '/' + timelineDateString(year, month, day);
317 } else if (path.endsWith("thismonth")) {
318 const QDate date = QDate::currentDate();
319 timelineUrl = "timeline:/" + timelineDateString(date.year(), date.month());
320 } else if (path.endsWith("lastmonth")) {
321 const QDate date = QDate::currentDate().addMonths(-1);
322 timelineUrl = "timeline:/" + timelineDateString(date.year(), date.month());
323 } else {
324 Q_ASSERT(path.endsWith("today"));
325 timelineUrl= url;
326 }
327
328 return timelineUrl;
329 }
330
331 QString PlacesPanel::timelineDateString(int year, int month, int day)
332 {
333 QString date = QString::number(year) + '-';
334 if (month < 10) {
335 date += '0';
336 }
337 date += QString::number(month);
338
339 if (day >= 1) {
340 date += '-';
341 if (day < 10) {
342 date += '0';
343 }
344 date += QString::number(day);
345 }
346
347 return date;
348 }
349
350 KUrl PlacesPanel::createSearchUrl(const KUrl& url)
351 {
352 KUrl searchUrl;
353
354 #ifdef HAVE_NEPOMUK
355 const QString path = url.pathOrUrl();
356 if (path.endsWith("documents")) {
357 searchUrl = searchUrlForTerm(Nepomuk::Query::ResourceTypeTerm(Nepomuk::Vocabulary::NFO::Document()));
358 } else if (path.endsWith("images")) {
359 searchUrl = searchUrlForTerm(Nepomuk::Query::ResourceTypeTerm(Nepomuk::Vocabulary::NFO::Image()));
360 } else if (path.endsWith("music")) {
361 searchUrl = searchUrlForTerm(Nepomuk::Query::ComparisonTerm(Nepomuk::Vocabulary::NIE::mimeType(),
362 Nepomuk::Query::LiteralTerm("audio")));
363 } else if (path.endsWith("videos")) {
364 searchUrl = searchUrlForTerm(Nepomuk::Query::ComparisonTerm(Nepomuk::Vocabulary::NIE::mimeType(),
365 Nepomuk::Query::LiteralTerm("video")));
366 } else {
367 Q_ASSERT(false);
368 }
369 #endif
370
371 return searchUrl;
372 }
373
374 #ifdef HAVE_NEPOMUK
375 KUrl PlacesPanel::searchUrlForTerm(const Nepomuk::Query::Term& term)
376 {
377 const Nepomuk::Query::Query query(term);
378 return query.toSearchUrl();
379 }
380 #endif
381
382 #include "placespanel.moc"