1 /***************************************************************************
2 * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
4 * Based on KFilePlacesModel from kdelibs: *
5 * Copyright (C) 2007 Kevin Ottens <ervin@kde.org> *
6 * Copyright (C) 2007 David Faure <faure@kde.org> *
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. *
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. *
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 ***************************************************************************/
24 #include "placesitemmodel.h"
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>
37 #include <KBookmarkGroup>
38 #include <KBookmarkManager>
39 #include <KComponentData>
42 #include <kitemviews/kstandarditem.h>
44 #include <KStandardDirs>
48 PlacesItemModel::PlacesItemModel(QObject
* parent
) :
49 KStandardItemModel(parent
),
50 m_nepomukRunning(false),
51 m_hiddenItemsShown(false),
55 m_systemBookmarksIndexes(),
59 m_nepomukRunning
= (Nepomuk::ResourceManager::instance()->initialized());
61 const QString file
= KStandardDirs::locateLocal("data", "kfileplaces/bookmarks.xml");
62 m_bookmarkManager
= KBookmarkManager::managerForFile(file
, "kfilePlaces");
64 createSystemBookmarks();
68 PlacesItemModel::~PlacesItemModel()
70 qDeleteAll(m_hiddenItems
);
71 m_hiddenItems
.clear();
74 int PlacesItemModel::hiddenCount() const
77 foreach (const KStandardItem
* item
, m_hiddenItems
) {
86 void PlacesItemModel::setItemHidden(int index
, bool hide
)
88 if (index
>= 0 && index
< count()) {
89 KStandardItem
* shownItem
= this->item(index
);
90 shownItem
->setDataValue("isHidden", hide
);
91 if (!m_hiddenItemsShown
&& hide
) {
92 const int newIndex
= hiddenIndex(index
);
93 KStandardItem
* hiddenItem
= new KStandardItem(*shownItem
);
95 m_hiddenItems
.insert(newIndex
, hiddenItem
);
97 #ifdef PLACESITEMMODEL_DEBUG
98 kDebug() << "Changed hide-state from" << index
<< "to" << hide
;
104 bool PlacesItemModel::isItemHidden(int index
) const
106 return (index
>= 0 && index
< count()) ? m_hiddenItems
[index
] != 0 : false;
109 void PlacesItemModel::setHiddenItemsShown(bool show
)
111 if (m_hiddenItemsShown
!= show
) {
112 m_hiddenItemsShown
= show
;
116 bool PlacesItemModel::hiddenItemsShown() const
118 return m_hiddenItemsShown
;
121 bool PlacesItemModel::isSystemItem(int index
) const
123 if (index
>= 0 && index
< count()) {
124 const KUrl url
= data(index
).value("url").value
<KUrl
>();
125 return m_systemBookmarksIndexes
.contains(url
);
130 int PlacesItemModel::closestItem(const KUrl
& url
) const
135 for (int i
= 0; i
< count(); ++i
) {
136 const KUrl itemUrl
= data(i
).value("url").value
<KUrl
>();
137 if (itemUrl
.isParentOf(url
)) {
138 const int length
= itemUrl
.prettyUrl().length();
139 if (length
> maxLength
) {
149 QString
PlacesItemModel::groupName(const KUrl
&url
) const
151 const QString protocol
= url
.protocol();
153 if (protocol
.contains(QLatin1String("search"))) {
154 return searchForGroupName();
157 if (protocol
== QLatin1String("timeline")) {
158 return recentlyAccessedGroupName();
161 return placesGroupName();
164 QAction
* PlacesItemModel::ejectAction(int index
) const
170 QAction
* PlacesItemModel::tearDownAction(int index
) const
176 void PlacesItemModel::onItemInserted(int index
)
178 if (index
== count() - 1) {
179 m_hiddenItems
.append(0);
181 m_hiddenItems
.insert(hiddenIndex(index
), 0);
185 void PlacesItemModel::onItemRemoved(int index
)
187 const int removeIndex
= hiddenIndex(index
);
188 Q_ASSERT(!m_hiddenItems
[removeIndex
]);
189 m_hiddenItems
.removeAt(removeIndex
);
190 #ifdef PLACESITEMMODEL_DEBUG
191 kDebug() << "Removed item" << index
;
196 void PlacesItemModel::loadBookmarks()
198 KBookmarkGroup root
= m_bookmarkManager
->root();
199 KBookmark bookmark
= root
.first();
200 QSet
<QString
> devices
= m_availableDevices
;
202 QSet
<KUrl
> missingSystemBookmarks
;
203 foreach (const SystemBookmarkData
& data
, m_systemBookmarks
) {
204 missingSystemBookmarks
.insert(data
.url
);
207 while (!bookmark
.isNull()) {
208 const QString udi
= bookmark
.metaDataItem("UDI");
209 const KUrl url
= bookmark
.url();
210 const QString appName
= bookmark
.metaDataItem("OnlyInApp");
211 const bool deviceAvailable
= devices
.remove(udi
);
213 const bool allowedHere
= (appName
.isEmpty() || appName
== KGlobal::mainComponent().componentName())
214 && (m_nepomukRunning
|| url
.protocol() != QLatin1String("timeline"));
216 if ((udi
.isEmpty() && allowedHere
) || deviceAvailable
) {
217 KStandardItem
* item
= new KStandardItem();
218 item
->setIcon(KIcon(bookmark
.icon()));
219 item
->setDataValue("address", bookmark
.address());
220 item
->setDataValue("url", url
);
222 if (missingSystemBookmarks
.contains(url
)) {
223 missingSystemBookmarks
.remove(url
);
224 // Apply the translated text to the system bookmarks, otherwise an outdated
225 // translation might be shown.
226 const int index
= m_systemBookmarksIndexes
.value(url
);
227 item
->setText(m_systemBookmarks
[index
].text
);
229 // The system bookmarks don't contain "real" queries stored as URLs, so
230 // they must be translated first.
231 item
->setDataValue("url", translatedSystemBookmarkUrl(url
));
233 item
->setText(bookmark
.text());
236 if (deviceAvailable
) {
237 item
->setDataValue("udi", udi
);
238 item
->setGroup(i18nc("@item", "Devices"));
240 item
->setGroup(i18nc("@item", "Places"));
243 if (bookmark
.metaDataItem("IsHidden") == QLatin1String("true")) {
244 m_hiddenItems
.append(item
);
250 bookmark
= root
.next(bookmark
);
253 if (!missingSystemBookmarks
.isEmpty()) {
254 foreach (const SystemBookmarkData
& data
, m_systemBookmarks
) {
255 if (missingSystemBookmarks
.contains(data
.url
)) {
256 KStandardItem
* item
= new KStandardItem();
257 item
->setIcon(KIcon(data
.icon
));
258 item
->setText(data
.text
);
259 item
->setDataValue("url", translatedSystemBookmarkUrl(data
.url
));
260 item
->setGroup(data
.group
);
266 #ifdef PLACESITEMMODEL_DEBUG
267 kDebug() << "Loaded bookmarks";
272 void PlacesItemModel::createSystemBookmarks()
274 Q_ASSERT(m_systemBookmarks
.isEmpty());
275 Q_ASSERT(m_systemBookmarksIndexes
.isEmpty());
277 const QString placesGroup
= placesGroupName();
278 const QString recentlyAccessedGroup
= recentlyAccessedGroupName();
279 const QString searchForGroup
= searchForGroupName();
280 const QString timeLineIcon
= "package_utility_time"; // TODO: Ask the Oxygen team to create
281 // a custom icon for the timeline-protocol
283 m_systemBookmarks
.append(SystemBookmarkData(KUrl(KUser().homeDir()),
285 i18nc("@item", "Home"),
287 m_systemBookmarks
.append(SystemBookmarkData(KUrl("remote:/"),
289 i18nc("@item", "Network"),
291 m_systemBookmarks
.append(SystemBookmarkData(KUrl("/"),
293 i18nc("@item", "Root"),
295 m_systemBookmarks
.append(SystemBookmarkData(KUrl("trash:/"),
297 i18nc("@item", "Trash"),
300 if (m_nepomukRunning
) {
301 m_systemBookmarks
.append(SystemBookmarkData(KUrl("timeline:/today"),
303 i18nc("@item Recently Accessed", "Today"),
304 recentlyAccessedGroup
));
305 m_systemBookmarks
.append(SystemBookmarkData(KUrl("timeline:/yesterday"),
307 i18nc("@item Recently Accessed", "Yesterday"),
308 recentlyAccessedGroup
));
309 m_systemBookmarks
.append(SystemBookmarkData(KUrl("timeline:/thismonth"),
311 i18nc("@item Recently Accessed", "This Month"),
312 recentlyAccessedGroup
));
313 m_systemBookmarks
.append(SystemBookmarkData(KUrl("timeline:/lastmonth"),
315 i18nc("@item Recently Accessed", "Last Month"),
316 recentlyAccessedGroup
));
317 m_systemBookmarks
.append(SystemBookmarkData(KUrl("search:/documents"),
319 i18nc("@item Commonly Accessed", "Documents"),
321 m_systemBookmarks
.append(SystemBookmarkData(KUrl("search:/images"),
323 i18nc("@item Commonly Accessed", "Images"),
325 m_systemBookmarks
.append(SystemBookmarkData(KUrl("search:/audio"),
327 i18nc("@item Commonly Accessed", "Audio"),
329 m_systemBookmarks
.append(SystemBookmarkData(KUrl("search:/videos"),
331 i18nc("@item Commonly Accessed", "Videos"),
335 for (int i
= 0; i
< m_systemBookmarks
.count(); ++i
) {
336 const KUrl url
= translatedSystemBookmarkUrl(m_systemBookmarks
[i
].url
);
337 m_systemBookmarksIndexes
.insert(url
, i
);
341 int PlacesItemModel::hiddenIndex(int index
) const
344 int visibleItemIndex
= 0;
345 while (hiddenIndex
< m_hiddenItems
.count()) {
346 if (!m_hiddenItems
[hiddenIndex
]) {
347 if (visibleItemIndex
== index
) {
355 return hiddenIndex
>= m_hiddenItems
.count() ? -1 : hiddenIndex
;
358 QString
PlacesItemModel::placesGroupName()
360 return i18nc("@item", "Places");
363 QString
PlacesItemModel::recentlyAccessedGroupName()
365 return i18nc("@item", "Recently Accessed");
368 QString
PlacesItemModel::searchForGroupName()
370 return i18nc("@item", "Search For");
373 KUrl
PlacesItemModel::translatedSystemBookmarkUrl(const KUrl
& url
)
375 KUrl translatedUrl
= url
;
376 if (url
.protocol() == QLatin1String("timeline")) {
377 translatedUrl
= createTimelineUrl(url
);
378 } else if (url
.protocol() == QLatin1String("search")) {
379 translatedUrl
= createSearchUrl(url
);
382 return translatedUrl
;
385 KUrl
PlacesItemModel::createTimelineUrl(const KUrl
& url
)
387 // TODO: Clarify with the Nepomuk-team whether it makes sense
388 // provide default-timeline-URLs like 'yesterday', 'this month'
392 const QString path
= url
.pathOrUrl();
393 if (path
.endsWith("yesterday")) {
394 const QDate date
= QDate::currentDate().addDays(-1);
395 const int year
= date
.year();
396 const int month
= date
.month();
397 const int day
= date
.day();
398 timelineUrl
= "timeline:/" + timelineDateString(year
, month
) +
399 '/' + timelineDateString(year
, month
, day
);
400 } else if (path
.endsWith("thismonth")) {
401 const QDate date
= QDate::currentDate();
402 timelineUrl
= "timeline:/" + timelineDateString(date
.year(), date
.month());
403 } else if (path
.endsWith("lastmonth")) {
404 const QDate date
= QDate::currentDate().addMonths(-1);
405 timelineUrl
= "timeline:/" + timelineDateString(date
.year(), date
.month());
407 Q_ASSERT(path
.endsWith("today"));
414 QString
PlacesItemModel::timelineDateString(int year
, int month
, int day
)
416 QString date
= QString::number(year
) + '-';
420 date
+= QString::number(month
);
427 date
+= QString::number(day
);
433 KUrl
PlacesItemModel::createSearchUrl(const KUrl
& url
)
438 const QString path
= url
.pathOrUrl();
439 if (path
.endsWith("documents")) {
440 searchUrl
= searchUrlForTerm(Nepomuk::Query::ResourceTypeTerm(Nepomuk::Vocabulary::NFO::Document()));
441 } else if (path
.endsWith("images")) {
442 searchUrl
= searchUrlForTerm(Nepomuk::Query::ResourceTypeTerm(Nepomuk::Vocabulary::NFO::Image()));
443 } else if (path
.endsWith("audio")) {
444 searchUrl
= searchUrlForTerm(Nepomuk::Query::ComparisonTerm(Nepomuk::Vocabulary::NIE::mimeType(),
445 Nepomuk::Query::LiteralTerm("audio")));
446 } else if (path
.endsWith("videos")) {
447 searchUrl
= searchUrlForTerm(Nepomuk::Query::ComparisonTerm(Nepomuk::Vocabulary::NIE::mimeType(),
448 Nepomuk::Query::LiteralTerm("video")));
460 KUrl
PlacesItemModel::searchUrlForTerm(const Nepomuk::Query::Term
& term
)
462 const Nepomuk::Query::Query
query(term
);
463 return query
.toSearchUrl();
467 #ifdef PLACESITEMMODEL_DEBUG
468 void PlacesItemModel::showModelState()
470 kDebug() << "hidden-index model-index text";
472 for (int i
= 0; i
< m_hiddenItems
.count(); ++i
) {
473 if (m_hiddenItems
[i
]) {
474 kDebug() << i
<< "(Hidden) " << " " << m_hiddenItems
[i
]->dataValue("text").toString();
476 kDebug() << i
<< " " << j
<< " " << item(j
)->dataValue("text").toString();
483 #include "placesitemmodel.moc"