~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to plasma/desktop/applets/kickoff/core/systemmodel.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright 2007 Robert Knight <robertknight@gmail.com>
 
3
    Copyright 2007 Kevin Ottens <ervin@kde.org>
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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.
 
19
*/
 
20
 
 
21
#include "systemmodel.h"
 
22
 
 
23
// Qt
 
24
#include <QHash>
 
25
#include <QTimer>
 
26
 
 
27
// KDE
 
28
#include <KAuthorized>
 
29
#include <KDebug>
 
30
#include <KDiskFreeSpaceInfo>
 
31
#include <KIcon>
 
32
#include <KUrl>
 
33
#include <KSycoca>
 
34
#include <KFilePlacesModel>
 
35
#include <Solid/Device>
 
36
#include <Solid/DeviceInterface>
 
37
#include <Solid/DeviceNotifier>
 
38
#include <Solid/StorageAccess>
 
39
#include <Solid/StorageDrive>
 
40
 
 
41
// Local
 
42
#include "core/models.h"
 
43
#include "core/systemmodel.h"
 
44
 
 
45
using namespace Kickoff;
 
46
 
 
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;
 
52
 
 
53
struct UsageInfo {
 
54
    UsageInfo()
 
55
        : used(0),
 
56
          available(0)
 
57
     {}
 
58
 
 
59
    quint64 used;
 
60
    quint64 available;
 
61
};
 
62
 
 
63
class SystemModel::Private
 
64
{
 
65
public:
 
66
    Private(SystemModel *parent)
 
67
            : q(parent),
 
68
              placesModel(new KFilePlacesModel(parent)),
 
69
              currentPlacesModelUsageIndex(0)
 
70
    {
 
71
        q->setSourceModel(placesModel);
 
72
 
 
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)));
 
83
 
 
84
        topLevelSections << i18n("Applications")
 
85
        << i18n("Places")
 
86
        << i18n("Removable Storage")
 
87
        << i18n("Storage");
 
88
        connect(KSycoca::self(), SIGNAL(databaseChanged(const QStringList&)), q, SLOT(reloadApplications()));
 
89
    }
 
90
 
 
91
    SystemModel * const q;
 
92
    KFilePlacesModel *placesModel;
 
93
    QStringList topLevelSections;
 
94
    KService::List appsList;
 
95
    QMap<QString, UsageInfo> usageByMountpoint;
 
96
    int currentPlacesModelUsageIndex;
 
97
};
 
98
 
 
99
SystemModel::SystemModel(QObject *parent)
 
100
        : KickoffProxyModel(parent)
 
101
        , d(new Private(this))
 
102
{
 
103
    reloadApplications();
 
104
}
 
105
 
 
106
SystemModel::~SystemModel()
 
107
{
 
108
    delete d;
 
109
}
 
110
 
 
111
QModelIndex SystemModel::mapFromSource(const QModelIndex &sourceIndex) const
 
112
{
 
113
    if (!sourceIndex.isValid()) {
 
114
        return QModelIndex();
 
115
    }
 
116
 
 
117
    QModelIndex parent;
 
118
 
 
119
    if (!d->placesModel->isDevice(sourceIndex)) {
 
120
        parent = index(BOOKMARKS_ROW, 0);
 
121
    } else {
 
122
        bool isFixedDevice = d->placesModel->data(sourceIndex, KFilePlacesModel::FixedDeviceRole).toBool();
 
123
 
 
124
        if (!isFixedDevice) {
 
125
            parent = index(REMOVABLE_ROW, 0);
 
126
        } else {
 
127
            parent = index(FIXED_ROW, 0);
 
128
        }
 
129
    }
 
130
 
 
131
    return index(sourceIndex.row(), 0, parent);
 
132
}
 
133
 
 
134
QModelIndex SystemModel::mapToSource(const QModelIndex &proxyIndex) const
 
135
{
 
136
    if (!proxyIndex.isValid() || !proxyIndex.parent().isValid()) {
 
137
        return QModelIndex();
 
138
    }
 
139
 
 
140
    return d->placesModel->index(proxyIndex.row(), proxyIndex.column());
 
141
}
 
142
 
 
143
QModelIndex SystemModel::index(int row, int column, const QModelIndex &parent) const
 
144
{
 
145
    if (!parent.isValid()) {
 
146
        return createIndex(row, column, 0);
 
147
    }
 
148
 
 
149
    // We use the row+1 of the parent as internal Id.
 
150
    return createIndex(row, column, parent.row() + 1);
 
151
}
 
152
 
 
153
QModelIndex SystemModel::parent(const QModelIndex &item) const
 
154
{
 
155
    if (item.internalId() > 0) {
 
156
        return index(item.internalId() - 1, 0);
 
157
    } else {
 
158
        return QModelIndex();
 
159
    }
 
160
}
 
161
 
 
162
int SystemModel::rowCount(const QModelIndex &parent) const
 
163
{
 
164
    if (!parent.isValid()) {
 
165
        return LAST_ROW + 1;
 
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;
 
171
            } else {
 
172
                return d->appsList.size();
 
173
            }
 
174
            break;
 
175
        case BOOKMARKS_ROW:
 
176
            return d->placesModel->rowCount();
 
177
            break;
 
178
        case REMOVABLE_ROW:
 
179
            return d->placesModel->rowCount();
 
180
            break;
 
181
        default:
 
182
            return 0;
 
183
        }
 
184
    }
 
185
 
 
186
    return 0;
 
187
}
 
188
 
 
189
int SystemModel::columnCount(const QModelIndex &/*parent*/) const
 
190
{
 
191
    return 1;
 
192
}
 
193
 
 
194
QVariant SystemModel::data(const QModelIndex &index, int role) const
 
195
{
 
196
    if (!index.isValid()) {
 
197
        return QVariant();
 
198
    }
 
199
 
 
200
    if (index.internalId() == 0) {
 
201
        if (role == Qt::DisplayRole) {
 
202
            return d->topLevelSections[index.row()];
 
203
        } else {
 
204
            return QVariant();
 
205
        }
 
206
    }
 
207
 
 
208
    if (index.internalId() - 1 == APPLICATIONS_ROW) {
 
209
        if (d->appsList.count() < index.row()) {
 
210
            return QVariant();
 
211
        } else if (d->appsList.count() == index.row()) {
 
212
            // "Run Command"
 
213
            switch (role) {
 
214
                case Qt::DisplayRole:
 
215
                    return i18n("Run Command...");
 
216
                case Qt::DecorationRole:
 
217
                    return KIcon("system-run");
 
218
                case SubTitleRole:
 
219
                    return i18n("Run a command or a search query");
 
220
                case UrlRole:
 
221
                    return "run:/";
 
222
                default:
 
223
                    return QVariant();
 
224
            }
 
225
        }
 
226
 
 
227
        KService::Ptr service = d->appsList[index.row()];
 
228
 
 
229
        switch (role) {
 
230
        case Qt::DisplayRole:
 
231
            return service->name();
 
232
        case Qt::DecorationRole:
 
233
            return KIcon(service->icon());
 
234
        case SubTitleRole:
 
235
            return service->genericName();
 
236
        case UrlRole:
 
237
            return service->entryPath();
 
238
        default:
 
239
            return QVariant();
 
240
        }
 
241
    }
 
242
 
 
243
    if (role == UrlRole && !d->placesModel->isHidden(mapToSource(index))) {
 
244
        QModelIndex parent = index.parent();
 
245
        QModelIndex sourceIndex = mapToSource(index);
 
246
 
 
247
        bool isDevice = d->placesModel->isDevice(sourceIndex);
 
248
        bool wellPlaced = false;
 
249
 
 
250
        if (!isDevice && parent.row() == BOOKMARKS_ROW) {
 
251
            wellPlaced = true;
 
252
        } else if (isDevice) {
 
253
            bool fixed = d->placesModel->data(sourceIndex, KFilePlacesModel::FixedDeviceRole).toBool();
 
254
 
 
255
            if (!fixed && parent.row() == REMOVABLE_ROW) {
 
256
                wellPlaced = true;
 
257
            } else if (fixed && parent.row() == FIXED_ROW) {
 
258
                wellPlaced = true;
 
259
            }
 
260
        }
 
261
 
 
262
        if (wellPlaced) {
 
263
            return d->placesModel->url(sourceIndex).url();
 
264
        } else {
 
265
            return QVariant();
 
266
        }
 
267
    } else if (role == DeviceUdiRole) {
 
268
        QModelIndex sourceIndex = mapToSource(index);
 
269
 
 
270
        if (d->placesModel->isDevice(sourceIndex)) {
 
271
            Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
 
272
            return dev.udi();
 
273
        } else {
 
274
            return QVariant();
 
275
        }
 
276
    } else if (role == SubTitleRole) {
 
277
        QModelIndex sourceIndex = mapToSource(index);
 
278
 
 
279
        if (d->placesModel->isDevice(sourceIndex)) {
 
280
            Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
 
281
            Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
 
282
 
 
283
            if (access) {
 
284
                return access->filePath();
 
285
            }
 
286
        } else if (index.parent().row() != APPLICATIONS_ROW) {
 
287
            KUrl url = d->placesModel->url(sourceIndex);
 
288
            return url.isLocalFile() ? url.toLocalFile() : url.prettyUrl();
 
289
        }
 
290
 
 
291
        return QVariant();
 
292
    } else if (role == DiskUsedSpaceRole || role == DiskFreeSpaceRole) {
 
293
        QModelIndex sourceIndex = mapToSource(index);
 
294
        QString mp;
 
295
 
 
296
        if (d->placesModel->isDevice(sourceIndex)) {
 
297
            Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
 
298
            Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
 
299
 
 
300
            if (access) {
 
301
                mp = access->filePath();
 
302
            }
 
303
        }
 
304
 
 
305
        if (!mp.isEmpty() && d->usageByMountpoint.contains(mp)) {
 
306
            UsageInfo info = d->usageByMountpoint[mp];
 
307
 
 
308
            if (role == DiskUsedSpaceRole) {
 
309
                return info.used;
 
310
            } else {
 
311
                return info.available;
 
312
            }
 
313
        }
 
314
    }
 
315
 
 
316
    return d->placesModel->data(mapToSource(index), role);
 
317
}
 
318
 
 
319
QVariant SystemModel::headerData(int section, Qt::Orientation orientation, int role) const
 
320
{
 
321
    if (orientation != Qt::Horizontal || section != 0) {
 
322
        return QVariant();
 
323
    }
 
324
 
 
325
    switch (role) {
 
326
    case Qt::DisplayRole:
 
327
        return i18n("Computer");
 
328
        break;
 
329
    default:
 
330
        return QVariant();
 
331
    }
 
332
}
 
333
 
 
334
void SystemModel::refreshUsageInfo()
 
335
{
 
336
    d->currentPlacesModelUsageIndex = 0;
 
337
    QTimer::singleShot(100, this, SLOT(refreshNextUsageInfo()));
 
338
}
 
339
 
 
340
void SystemModel::stopRefreshingUsageInfo()
 
341
{
 
342
    d->currentPlacesModelUsageIndex = d->placesModel->rowCount();
 
343
}
 
344
 
 
345
void SystemModel::refreshNextUsageInfo()
 
346
{
 
347
    if (d->currentPlacesModelUsageIndex >= d->placesModel->rowCount()) {
 
348
        return;
 
349
    }
 
350
 
 
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>();
 
355
 
 
356
        if (access && !access->filePath().isEmpty()) {
 
357
            KDiskFreeSpaceInfo freeSpace = KDiskFreeSpaceInfo::freeSpaceInfo(access->filePath());
 
358
            if (freeSpace.isValid()) {
 
359
                UsageInfo info;
 
360
                info.used = freeSpace.used() / 1024;
 
361
                info.available = freeSpace.available() / 1024;
 
362
 
 
363
                d->usageByMountpoint[freeSpace.mountPoint()] = info;
 
364
                QModelIndex index = mapFromSource(sourceIndex);
 
365
                emit dataChanged(index, index);
 
366
            }
 
367
        }
 
368
    }
 
369
 
 
370
    ++d->currentPlacesModelUsageIndex;
 
371
    QTimer::singleShot(0, this, SLOT(refreshNextUsageInfo()));
 
372
}
 
373
 
 
374
void SystemModel::reloadApplications()
 
375
{
 
376
    const QStringList apps = Kickoff::systemApplicationList();
 
377
    d->appsList.clear();
 
378
 
 
379
    foreach (const QString &app, apps) {
 
380
        KService::Ptr service = KService::serviceByStorageId(app);
 
381
 
 
382
        if (service) {
 
383
            d->appsList << service;
 
384
        }
 
385
    }
 
386
}
 
387
 
 
388
void Kickoff::SystemModel::sourceDataChanged(const QModelIndex &start, const QModelIndex &end)
 
389
{
 
390
    if (start.parent().isValid()) return;
 
391
 
 
392
    for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
 
393
        QModelIndex section = index(row, 0);
 
394
 
 
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);
 
398
    }
 
399
}
 
400
 
 
401
void Kickoff::SystemModel::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
 
402
{
 
403
    if (parent.isValid()) return;
 
404
 
 
405
    for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
 
406
        QModelIndex section = index(row, 0);
 
407
        beginInsertRows(section, start, end);
 
408
    }
 
409
}
 
410
 
 
411
void Kickoff::SystemModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int /*end*/)
 
412
{
 
413
    if (parent.isValid()) return;
 
414
 
 
415
    endInsertRows();
 
416
}
 
417
 
 
418
void Kickoff::SystemModel::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
 
419
{
 
420
    if (parent.isValid()) return;
 
421
 
 
422
    for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
 
423
        QModelIndex section = index(row, 0);
 
424
        beginRemoveRows(section, start, end);
 
425
    }
 
426
}
 
427
 
 
428
void Kickoff::SystemModel::sourceRowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
 
429
{
 
430
    if (parent.isValid()) return;
 
431
 
 
432
    endRemoveRows();
 
433
}
 
434
 
 
435
#include "systemmodel.moc"