1/* This file is part of the KDE project
2 Copyright (C) 2007 Kevin Ottens <ervin@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17
18*/
19
20#include "kfileplacesitem_p.h"
21#include "kfileplacesmodel.h"
22
23#include <QtCore/QDateTime>
24
25#include <kbookmarkmanager.h>
26#include <kiconloader.h>
27#include <kdirlister.h>
28#include <klocale.h>
29#include <solid/block.h>
30#include <solid/opticaldisc.h>
31#include <solid/opticaldrive.h>
32#include <solid/storageaccess.h>
33#include <solid/storagevolume.h>
34#include <solid/storagedrive.h>
35#include <solid/portablemediaplayer.h>
36
37
38KFilePlacesItem::KFilePlacesItem(KBookmarkManager *manager,
39 const QString &address,
40 const QString &udi)
41 : m_manager(manager), m_lister(0), m_folderIsEmpty(true), m_isCdrom(false),
42 m_isAccessible(false), m_device(udi)
43{
44 setBookmark(m_manager->findByAddress(address));
45
46 if (udi.isEmpty() && m_bookmark.metaDataItem("ID").isEmpty()) {
47 m_bookmark.setMetaDataItem("ID", generateNewId());
48 } else if (udi.isEmpty()) {
49 if (hasFullIcon(m_bookmark)) {
50 // TODO if this is only for the trash, it would be much faster to just read trashrc
51 m_lister = new KDirLister(this);
52 m_lister->setAutoErrorHandlingEnabled(false, 0); // don't bother the user if trash:/ doesn't exist
53 m_lister->setDelayedMimeTypes(true); // we don't need the mimetypes, so don't penalize other KDirLister users
54 connect(m_lister, SIGNAL(completed()),
55 this, SLOT(onListerCompleted()));
56 m_lister->openUrl(m_bookmark.url());
57 }
58 } else if (!udi.isEmpty() && m_device.isValid()) {
59 m_access = m_device.as<Solid::StorageAccess>();
60 m_volume = m_device.as<Solid::StorageVolume>();
61 m_disc = m_device.as<Solid::OpticalDisc>();
62 m_mtp = m_device.as<Solid::PortableMediaPlayer>();
63 if (m_access) {
64 connect(m_access, SIGNAL(accessibilityChanged(bool,QString)),
65 this, SLOT(onAccessibilityChanged(bool)));
66 onAccessibilityChanged(m_access->isAccessible());
67 }
68 m_iconPath = m_device.icon();
69 m_emblems = m_device.emblems();
70 }
71}
72
73KFilePlacesItem::~KFilePlacesItem()
74{
75}
76
77QString KFilePlacesItem::id() const
78{
79 if (isDevice()) {
80 return bookmark().metaDataItem("UDI");
81 } else {
82 return bookmark().metaDataItem("ID");
83 }
84}
85
86bool KFilePlacesItem::isDevice() const
87{
88 return !bookmark().metaDataItem("UDI").isEmpty();
89}
90
91KBookmark KFilePlacesItem::bookmark() const
92{
93 return m_bookmark;
94}
95
96void KFilePlacesItem::setBookmark(const KBookmark &bookmark)
97{
98 m_bookmark = bookmark;
99
100 if (bookmark.metaDataItem("isSystemItem") == "true") {
101 // This context must stay as it is - the translated system bookmark names
102 // are created with 'KFile System Bookmarks' as their context, so this
103 // ensures the right string is picked from the catalog.
104 // (coles, 13th May 2009)
105
106 m_text = i18nc("KFile System Bookmarks", bookmark.text().toUtf8().data());
107 } else {
108 m_text = bookmark.text();
109 }
110}
111
112Solid::Device KFilePlacesItem::device() const
113{
114 if (m_device.udi().isEmpty()) {
115 m_device = Solid::Device(bookmark().metaDataItem("UDI"));
116 if (m_device.isValid()) {
117 m_access = m_device.as<Solid::StorageAccess>();
118 m_volume = m_device.as<Solid::StorageVolume>();
119 m_disc = m_device.as<Solid::OpticalDisc>();
120 m_mtp = m_device.as<Solid::PortableMediaPlayer>();
121 } else {
122 m_access = 0;
123 m_volume = 0;
124 m_disc = 0;
125 m_mtp = 0;
126 }
127 }
128 return m_device;
129}
130
131QVariant KFilePlacesItem::data(int role) const
132{
133 QVariant returnData;
134
135 if (role!=KFilePlacesModel::HiddenRole && role!=Qt::BackgroundRole && isDevice()) {
136 returnData = deviceData(role);
137 } else {
138 returnData = bookmarkData(role);
139 }
140
141 return returnData;
142}
143
144QVariant KFilePlacesItem::bookmarkData(int role) const
145{
146 KBookmark b = bookmark();
147
148 if (b.isNull()) return QVariant();
149
150 switch (role)
151 {
152 case Qt::DisplayRole:
153 return m_text;
154 case Qt::DecorationRole:
155 return KIcon(iconNameForBookmark(b));
156 case Qt::BackgroundRole:
157 if (b.metaDataItem("IsHidden")=="true") {
158 return Qt::lightGray;
159 } else {
160 return QVariant();
161 }
162 case KFilePlacesModel::UrlRole:
163 return QUrl(b.url());
164 case KFilePlacesModel::SetupNeededRole:
165 return false;
166 case KFilePlacesModel::HiddenRole:
167 return b.metaDataItem("IsHidden")=="true";
168 default:
169 return QVariant();
170 }
171}
172
173QVariant KFilePlacesItem::deviceData(int role) const
174{
175 Solid::Device d = device();
176
177 if (d.isValid()) {
178 switch (role)
179 {
180 case Qt::DisplayRole:
181 return d.description();
182 case Qt::DecorationRole:
183 return KIcon(m_iconPath, 0, m_emblems);
184 case KFilePlacesModel::UrlRole:
185 if (m_access) {
186 return QUrl(KUrl(m_access->filePath()));
187 } else if (m_disc && (m_disc->availableContent() & Solid::OpticalDisc::Audio)!=0) {
188 Solid::Block *block = d.as<Solid::Block>();
189 if (block) {
190 QString device = block->device();
191 return QUrl(QString("audiocd:/?device=%1").arg(device));
192 }
193 // We failed to get the block device. Assume audiocd:/ can
194 // figure it out, but cannot handle multiple disc drives.
195 // See https://bugs.kde.org/show_bug.cgi?id=314544#c40
196 return QUrl(QString("audiocd:/"));
197 } else if (m_mtp) {
198 return QUrl(QString("mtp:udi=%1").arg(d.udi()));
199 } else {
200 return QVariant();
201 }
202 case KFilePlacesModel::SetupNeededRole:
203 if (m_access) {
204 return !m_isAccessible;
205 } else {
206 return QVariant();
207 }
208
209 case KFilePlacesModel::FixedDeviceRole:
210 {
211 Solid::StorageDrive *drive = 0;
212 Solid::Device parentDevice = m_device;
213 while (parentDevice.isValid() && !drive) {
214 drive = parentDevice.as<Solid::StorageDrive>();
215 parentDevice = parentDevice.parent();
216 }
217 if (drive!=0) {
218 return !drive->isHotpluggable() && !drive->isRemovable();
219 }
220 return true;
221 }
222
223 case KFilePlacesModel::CapacityBarRecommendedRole:
224 return m_isAccessible && !m_isCdrom;
225
226 default:
227 return QVariant();
228 }
229 } else {
230 return QVariant();
231 }
232}
233
234KBookmark KFilePlacesItem::createBookmark(KBookmarkManager *manager,
235 const QString &label,
236 const KUrl &url,
237 const QString &iconName,
238 KFilePlacesItem *after)
239{
240 KBookmarkGroup root = manager->root();
241 if (root.isNull())
242 return KBookmark();
243 QString empty_icon = iconName;
244 if (url==KUrl("trash:/")) {
245 if (empty_icon.endsWith(QLatin1String("-full"))) {
246 empty_icon.chop(5);
247 } else if (empty_icon.isEmpty()) {
248 empty_icon = "user-trash";
249 }
250 }
251 KBookmark bookmark = root.addBookmark(label, url, empty_icon);
252 bookmark.setMetaDataItem("ID", generateNewId());
253
254 if (after) {
255 root.moveBookmark(bookmark, after->bookmark());
256 }
257
258 return bookmark;
259}
260
261KBookmark KFilePlacesItem::createSystemBookmark(KBookmarkManager *manager,
262 const QString &untranslatedLabel,
263 const QString &translatedLabel,
264 const KUrl &url,
265 const QString &iconName)
266{
267 Q_UNUSED(translatedLabel); // parameter is only necessary to force the caller
268 // providing a translated string for the label
269
270 KBookmark bookmark = createBookmark(manager, untranslatedLabel, url, iconName);
271 if (!bookmark.isNull())
272 bookmark.setMetaDataItem("isSystemItem", "true");
273 return bookmark;
274}
275
276
277KBookmark KFilePlacesItem::createDeviceBookmark(KBookmarkManager *manager,
278 const QString &udi)
279{
280 KBookmarkGroup root = manager->root();
281 if (root.isNull())
282 return KBookmark();
283 KBookmark bookmark = root.createNewSeparator();
284 bookmark.setMetaDataItem("UDI", udi);
285 bookmark.setMetaDataItem("isSystemItem", "true");
286 return bookmark;
287}
288
289QString KFilePlacesItem::generateNewId()
290{
291 static int count = 0;
292
293// return QString::number(count++);
294
295 return QString::number(QDateTime::currentDateTime().toTime_t())
296 + '/' + QString::number(count++);
297
298
299// return QString::number(QDateTime::currentDateTime().toTime_t())
300// + '/' + QString::number(qrand());
301}
302
303void KFilePlacesItem::onAccessibilityChanged(bool isAccessible)
304{
305 m_isAccessible = isAccessible;
306 m_isCdrom = m_device.is<Solid::OpticalDrive>() || m_device.parent().is<Solid::OpticalDrive>();
307 m_emblems = m_device.emblems();
308
309 emit itemChanged(id());
310}
311
312bool KFilePlacesItem::hasFullIcon(const KBookmark &bookmark) const
313{
314 return bookmark.url()==KUrl("trash:/");
315}
316
317QString KFilePlacesItem::iconNameForBookmark(const KBookmark &bookmark) const
318{
319 if (!m_folderIsEmpty && hasFullIcon(bookmark)) {
320 return bookmark.icon()+"-full";
321 } else {
322 return bookmark.icon();
323 }
324}
325
326void KFilePlacesItem::onListerCompleted()
327{
328 m_folderIsEmpty = m_lister->items().isEmpty();
329 emit itemChanged(id());
330}
331
332#include "kfileplacesitem_p.moc"
333