2
Copyright 2007 Robert Knight <robertknight@gmail.com>
3
Copyright 2007 Kevin Ottens <ervin@kde.org>
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License as published by the Free Software Foundation; either
8
version 2 of the License, or (at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to
17
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
Boston, MA 02110-1301, USA.
21
#include "systemmodel.h"
28
#include <KAuthorized>
30
#include <KDiskFreeSpaceInfo>
34
#include <KFilePlacesModel>
35
#include <Solid/Device>
36
#include <Solid/DeviceInterface>
37
#include <Solid/DeviceNotifier>
38
#include <Solid/StorageAccess>
39
#include <Solid/StorageDrive>
42
#include "core/models.h"
43
#include "core/systemmodel.h"
45
using namespace Kickoff;
47
static const int APPLICATIONS_ROW = 0;
48
static const int BOOKMARKS_ROW = 1;
49
static const int REMOVABLE_ROW = 2;
50
static const int FIXED_ROW = 3;
51
static const int LAST_ROW = FIXED_ROW;
63
class SystemModel::Private
66
Private(SystemModel *parent)
68
placesModel(new KFilePlacesModel(parent)),
69
currentPlacesModelUsageIndex(0)
71
q->setSourceModel(placesModel);
73
connect(placesModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
74
q, SLOT(sourceDataChanged(QModelIndex, QModelIndex)));
75
connect(placesModel, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)),
76
q, SLOT(sourceRowsAboutToBeInserted(QModelIndex, int, int)));
77
connect(placesModel, SIGNAL(rowsInserted(QModelIndex, int, int)),
78
q, SLOT(sourceRowsInserted(QModelIndex, int, int)));
79
connect(placesModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)),
80
q, SLOT(sourceRowsAboutToBeRemoved(QModelIndex, int, int)));
81
connect(placesModel, SIGNAL(rowsRemoved(QModelIndex, int, int)),
82
q, SLOT(sourceRowsRemoved(QModelIndex, int, int)));
84
topLevelSections << i18n("Applications")
86
<< i18n("Removable Storage")
88
connect(KSycoca::self(), SIGNAL(databaseChanged(const QStringList&)), q, SLOT(reloadApplications()));
91
SystemModel * const q;
92
KFilePlacesModel *placesModel;
93
QStringList topLevelSections;
94
KService::List appsList;
95
QMap<QString, UsageInfo> usageByMountpoint;
96
int currentPlacesModelUsageIndex;
99
SystemModel::SystemModel(QObject *parent)
100
: KickoffProxyModel(parent)
101
, d(new Private(this))
103
reloadApplications();
106
SystemModel::~SystemModel()
111
QModelIndex SystemModel::mapFromSource(const QModelIndex &sourceIndex) const
113
if (!sourceIndex.isValid()) {
114
return QModelIndex();
119
if (!d->placesModel->isDevice(sourceIndex)) {
120
parent = index(BOOKMARKS_ROW, 0);
122
bool isFixedDevice = d->placesModel->data(sourceIndex, KFilePlacesModel::FixedDeviceRole).toBool();
124
if (!isFixedDevice) {
125
parent = index(REMOVABLE_ROW, 0);
127
parent = index(FIXED_ROW, 0);
131
return index(sourceIndex.row(), 0, parent);
134
QModelIndex SystemModel::mapToSource(const QModelIndex &proxyIndex) const
136
if (!proxyIndex.isValid() || !proxyIndex.parent().isValid()) {
137
return QModelIndex();
140
return d->placesModel->index(proxyIndex.row(), proxyIndex.column());
143
QModelIndex SystemModel::index(int row, int column, const QModelIndex &parent) const
145
if (!parent.isValid()) {
146
return createIndex(row, column, 0);
149
// We use the row+1 of the parent as internal Id.
150
return createIndex(row, column, parent.row() + 1);
153
QModelIndex SystemModel::parent(const QModelIndex &item) const
155
if (item.internalId() > 0) {
156
return index(item.internalId() - 1, 0);
158
return QModelIndex();
162
int SystemModel::rowCount(const QModelIndex &parent) const
164
if (!parent.isValid()) {
166
} else if (!parent.parent().isValid()) {
167
switch (parent.row()) {
168
case APPLICATIONS_ROW:
169
if (KAuthorized::authorize("run_command")) {
170
return d->appsList.size() + 1;
172
return d->appsList.size();
176
return d->placesModel->rowCount();
179
return d->placesModel->rowCount();
189
int SystemModel::columnCount(const QModelIndex &/*parent*/) const
194
QVariant SystemModel::data(const QModelIndex &index, int role) const
196
if (!index.isValid()) {
200
if (index.internalId() == 0) {
201
if (role == Qt::DisplayRole) {
202
return d->topLevelSections[index.row()];
208
if (index.internalId() - 1 == APPLICATIONS_ROW) {
209
if (d->appsList.count() < index.row()) {
211
} else if (d->appsList.count() == index.row()) {
214
case Qt::DisplayRole:
215
return i18n("Run Command...");
216
case Qt::DecorationRole:
217
return KIcon("system-run");
219
return i18n("Run a command or a search query");
227
KService::Ptr service = d->appsList[index.row()];
230
case Qt::DisplayRole:
231
return service->name();
232
case Qt::DecorationRole:
233
return KIcon(service->icon());
235
return service->genericName();
237
return service->entryPath();
243
if (role == UrlRole && !d->placesModel->isHidden(mapToSource(index))) {
244
QModelIndex parent = index.parent();
245
QModelIndex sourceIndex = mapToSource(index);
247
bool isDevice = d->placesModel->isDevice(sourceIndex);
248
bool wellPlaced = false;
250
if (!isDevice && parent.row() == BOOKMARKS_ROW) {
252
} else if (isDevice) {
253
bool fixed = d->placesModel->data(sourceIndex, KFilePlacesModel::FixedDeviceRole).toBool();
255
if (!fixed && parent.row() == REMOVABLE_ROW) {
257
} else if (fixed && parent.row() == FIXED_ROW) {
263
return d->placesModel->url(sourceIndex).url();
267
} else if (role == DeviceUdiRole) {
268
QModelIndex sourceIndex = mapToSource(index);
270
if (d->placesModel->isDevice(sourceIndex)) {
271
Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
276
} else if (role == SubTitleRole) {
277
QModelIndex sourceIndex = mapToSource(index);
279
if (d->placesModel->isDevice(sourceIndex)) {
280
Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
281
Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
284
return access->filePath();
286
} else if (index.parent().row() != APPLICATIONS_ROW) {
287
KUrl url = d->placesModel->url(sourceIndex);
288
return url.isLocalFile() ? url.toLocalFile() : url.prettyUrl();
292
} else if (role == DiskUsedSpaceRole || role == DiskFreeSpaceRole) {
293
QModelIndex sourceIndex = mapToSource(index);
296
if (d->placesModel->isDevice(sourceIndex)) {
297
Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
298
Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
301
mp = access->filePath();
305
if (!mp.isEmpty() && d->usageByMountpoint.contains(mp)) {
306
UsageInfo info = d->usageByMountpoint[mp];
308
if (role == DiskUsedSpaceRole) {
311
return info.available;
316
return d->placesModel->data(mapToSource(index), role);
319
QVariant SystemModel::headerData(int section, Qt::Orientation orientation, int role) const
321
if (orientation != Qt::Horizontal || section != 0) {
326
case Qt::DisplayRole:
327
return i18n("Computer");
334
void SystemModel::refreshUsageInfo()
336
d->currentPlacesModelUsageIndex = 0;
337
QTimer::singleShot(100, this, SLOT(refreshNextUsageInfo()));
340
void SystemModel::stopRefreshingUsageInfo()
342
d->currentPlacesModelUsageIndex = d->placesModel->rowCount();
345
void SystemModel::refreshNextUsageInfo()
347
if (d->currentPlacesModelUsageIndex >= d->placesModel->rowCount()) {
351
QModelIndex sourceIndex = d->placesModel->index(d->currentPlacesModelUsageIndex, 0);
352
if (d->placesModel->isDevice(sourceIndex)) {
353
Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
354
Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
356
if (access && !access->filePath().isEmpty()) {
357
KDiskFreeSpaceInfo freeSpace = KDiskFreeSpaceInfo::freeSpaceInfo(access->filePath());
358
if (freeSpace.isValid()) {
360
info.used = freeSpace.used() / 1024;
361
info.available = freeSpace.available() / 1024;
363
d->usageByMountpoint[freeSpace.mountPoint()] = info;
364
QModelIndex index = mapFromSource(sourceIndex);
365
emit dataChanged(index, index);
370
++d->currentPlacesModelUsageIndex;
371
QTimer::singleShot(0, this, SLOT(refreshNextUsageInfo()));
374
void SystemModel::reloadApplications()
376
const QStringList apps = Kickoff::systemApplicationList();
379
foreach (const QString &app, apps) {
380
KService::Ptr service = KService::serviceByStorageId(app);
383
d->appsList << service;
388
void Kickoff::SystemModel::sourceDataChanged(const QModelIndex &start, const QModelIndex &end)
390
if (start.parent().isValid()) return;
392
for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
393
QModelIndex section = index(row, 0);
395
QModelIndex new_start = index(start.row(), start.column(), section);
396
QModelIndex new_end = index(end.row(), end.column(), section);
397
emit dataChanged(new_start, new_end);
401
void Kickoff::SystemModel::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
403
if (parent.isValid()) return;
405
for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
406
QModelIndex section = index(row, 0);
407
beginInsertRows(section, start, end);
411
void Kickoff::SystemModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int /*end*/)
413
if (parent.isValid()) return;
418
void Kickoff::SystemModel::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
420
if (parent.isValid()) return;
422
for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
423
QModelIndex section = index(row, 0);
424
beginRemoveRows(section, start, end);
428
void Kickoff::SystemModel::sourceRowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
430
if (parent.isValid()) return;
435
#include "systemmodel.moc"