• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Applets

systemmodel.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright 2007 Robert Knight <robertknight@gmail.com>
00003     Copyright 2007 Kevin Ottens <ervin@kde.org>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "systemmodel.h"
00022 
00023 // Qt
00024 #include <QFile>
00025 #include <QHash>
00026 #include <QTimer>
00027 
00028 // KDE
00029 #include <KConfigGroup>
00030 #include <KDebug>
00031 #include <KDiskFreeSpaceInfo>
00032 #include <KLocalizedString>
00033 #include <KIcon>
00034 #include <KGlobal>
00035 #include <KUrl>
00036 #include <KServiceTypeTrader>
00037 #include <KStandardDirs>
00038 #include <KSycoca>
00039 #include <kfileplacesmodel.h>
00040 #include <solid/device.h>
00041 #include <solid/deviceinterface.h>
00042 #include <solid/devicenotifier.h>
00043 #include <solid/storageaccess.h>
00044 #include <solid/storagedrive.h>
00045 
00046 // Local
00047 #include "core/models.h"
00048 #include "core/systemmodel.h"
00049 
00050 using namespace Kickoff;
00051 
00052 static const int APPLICATIONS_ROW = 0;
00053 static const int BOOKMARKS_ROW = 1;
00054 static const int REMOVABLE_ROW = 2;
00055 static const int FIXED_ROW = 3;
00056 static const int LAST_ROW = FIXED_ROW;
00057 
00058 struct UsageInfo {
00059     UsageInfo()
00060             : used(0),
00061             available(0),
00062             dirty(true) {}
00063 
00064     quint64 used;
00065     quint64 available;
00066     bool dirty;
00067 };
00068 
00069 class SystemModel::Private
00070 {
00071 public:
00072     Private(SystemModel *parent)
00073             : q(parent)
00074             , placesModel(new KFilePlacesModel(parent)) {
00075         q->setSourceModel(placesModel);
00076 
00077         connect(placesModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
00078                 q, SLOT(sourceDataChanged(QModelIndex, QModelIndex)));
00079         connect(placesModel, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)),
00080                 q, SLOT(sourceRowsAboutToBeInserted(QModelIndex, int, int)));
00081         connect(placesModel, SIGNAL(rowsInserted(QModelIndex, int, int)),
00082                 q, SLOT(sourceRowsInserted(QModelIndex, int, int)));
00083         connect(placesModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)),
00084                 q, SLOT(sourceRowsAboutToBeRemoved(QModelIndex, int, int)));
00085         connect(placesModel, SIGNAL(rowsRemoved(QModelIndex, int, int)),
00086                 q, SLOT(sourceRowsRemoved(QModelIndex, int, int)));
00087 
00088         topLevelSections << i18n("Applications")
00089         << i18n("Places")
00090         << i18n("Removable Storage")
00091         << i18n("Storage");
00092         loadApplications();
00093         connect(&refreshTimer, SIGNAL(timeout()),
00094                 q, SLOT(startRefreshingUsageInfo()));
00095         refreshTimer.start(10000);
00096         QTimer::singleShot(0, q, SLOT(startRefreshingUsageInfo()));
00097         connect(KSycoca::self(), SIGNAL(databaseChanged()), q, SLOT(reloadApplications()));
00098     }
00099 
00100     void queryFreeSpace(const QString& mountPoint) {
00101         KDiskFreeSpaceInfo freeSpace = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint);
00102         if (freeSpace.isValid())
00103             q->freeSpaceInfoAvailable(freeSpace.mountPoint(), freeSpace.size() / 1024,
00104                                       freeSpace.used() / 1024, freeSpace.available() / 1024);
00105     }
00106 
00107     void loadApplications() {
00108         QStringList apps = Kickoff::systemApplicationList();
00109         appsList.clear();
00110 
00111         foreach(const QString &app, apps) {
00112             KService::Ptr service = KService::serviceByStorageId(app);
00113 
00114             if (!service) {
00115                 continue;
00116             }
00117 
00118             appsList << service;
00119         }
00120         //kDebug() << "*************" << appsList;
00121     }
00122 
00123     SystemModel * const q;
00124     KFilePlacesModel *placesModel;
00125     QStringList topLevelSections;
00126     KService::List appsList;
00127     QList<QString> mountPointsQueue;
00128     QMap<QString, UsageInfo> usageByMountpoint;
00129     QTimer refreshTimer;
00130 };
00131 
00132 SystemModel::SystemModel(QObject *parent)
00133         : KickoffProxyModel(parent)
00134         , d(new Private(this))
00135 {
00136 }
00137 
00138 SystemModel::~SystemModel()
00139 {
00140     delete d;
00141 }
00142 
00143 QModelIndex SystemModel::mapFromSource(const QModelIndex &sourceIndex) const
00144 {
00145     if (!sourceIndex.isValid()) return QModelIndex();
00146 
00147     QModelIndex parent;
00148 
00149     if (!d->placesModel->isDevice(sourceIndex)) {
00150         parent = index(BOOKMARKS_ROW, 0);
00151     } else {
00152         Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00153 
00154         Solid::StorageDrive *drive = 0;
00155         Solid::Device parentDevice = dev;
00156         while (parentDevice.isValid() && !drive) {
00157             drive = parentDevice.as<Solid::StorageDrive>();
00158             parentDevice = parentDevice.parent();
00159         }
00160 
00161         if (drive && (drive->isHotpluggable() || drive->isRemovable())) {
00162             parent = index(REMOVABLE_ROW, 0);
00163         } else {
00164             parent = index(FIXED_ROW, 0);
00165         }
00166     }
00167 
00168     return index(sourceIndex.row(), 0, parent);
00169 }
00170 
00171 QModelIndex SystemModel::mapToSource(const QModelIndex &proxyIndex) const
00172 {
00173     if (!proxyIndex.isValid() || !proxyIndex.parent().isValid()) {
00174         return QModelIndex();
00175     }
00176 
00177     return d->placesModel->index(proxyIndex.row(), proxyIndex.column());
00178 }
00179 
00180 QModelIndex SystemModel::index(int row, int column, const QModelIndex &parent) const
00181 {
00182     if (!parent.isValid()) {
00183         return createIndex(row, column, 0);
00184     }
00185 
00186     // We use the row+1 of the parent as internal Id.
00187     return createIndex(row, column, parent.row() + 1);
00188 }
00189 
00190 QModelIndex SystemModel::parent(const QModelIndex &item) const
00191 {
00192     if (item.internalId() > 0) {
00193         return index(item.internalId() - 1, 0);
00194     } else {
00195         return QModelIndex();
00196     }
00197 }
00198 
00199 int SystemModel::rowCount(const QModelIndex &parent) const
00200 {
00201     if (!parent.isValid()) {
00202         return LAST_ROW + 1;
00203     } else if (!parent.parent().isValid()) {
00204         switch (parent.row()) {
00205         case APPLICATIONS_ROW:
00206             return d->appsList.size();
00207             break;
00208         case BOOKMARKS_ROW:
00209             return d->placesModel->rowCount();
00210             break;
00211         case REMOVABLE_ROW:
00212             return d->placesModel->rowCount();
00213             break;
00214         default:
00215             return 0;
00216         }
00217     }
00218 
00219     return 0;
00220 }
00221 
00222 int SystemModel::columnCount(const QModelIndex &/*parent*/) const
00223 {
00224     return 1;
00225 }
00226 
00227 QVariant SystemModel::data(const QModelIndex &index, int role) const
00228 {
00229     if (!index.isValid()) {
00230         return QVariant();
00231     }
00232 
00233     if (index.internalId() == 0) {
00234         if (role == Qt::DisplayRole) {
00235             return d->topLevelSections[index.row()];
00236         } else {
00237             return QVariant();
00238         }
00239     }
00240 
00241     if (index.internalId() - 1 == APPLICATIONS_ROW) {
00242         if (d->appsList.count() <= index.row()) {
00243             return QVariant();
00244         }
00245 
00246         KService::Ptr service = d->appsList[index.row()];
00247 
00248         switch (role) {
00249         case Qt::DisplayRole:
00250             return service->name();
00251         case Qt::DecorationRole:
00252             return KIcon(service->icon());
00253         case SubTitleRole:
00254             return service->genericName();
00255         case UrlRole:
00256             return service->entryPath();
00257         default:
00258             return QVariant();
00259         }
00260     }
00261 
00262     if (role == UrlRole && !d->placesModel->isHidden(mapToSource(index))) {
00263         QModelIndex parent = index.parent();
00264         QModelIndex sourceIndex = mapToSource(index);
00265 
00266         bool isDevice = d->placesModel->isDevice(sourceIndex);
00267         bool wellPlaced = false;
00268 
00269         if (!isDevice && parent.row() == BOOKMARKS_ROW) {
00270             wellPlaced = true;
00271         } else if (isDevice) {
00272             Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00273 
00274             Solid::StorageDrive *drive = 0;
00275             Solid::Device parentDevice = dev;
00276             while (parentDevice.isValid() && !drive) {
00277                 drive = parentDevice.as<Solid::StorageDrive>();
00278                 parentDevice = parentDevice.parent();
00279             }
00280 
00281             bool fixed = !drive || (!drive->isHotpluggable() && !drive->isRemovable());
00282 
00283             if (!fixed && parent.row() == REMOVABLE_ROW) {
00284                 wellPlaced = true;
00285             } else if (fixed && parent.row() == FIXED_ROW) {
00286                 wellPlaced = true;
00287             }
00288         }
00289 
00290         if (wellPlaced) {
00291             return d->placesModel->url(sourceIndex).url();
00292         } else {
00293             return QVariant();
00294         }
00295     } else if (role == DeviceUdiRole) {
00296         QModelIndex sourceIndex = mapToSource(index);
00297 
00298         if (d->placesModel->isDevice(sourceIndex)) {
00299             Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00300             return dev.udi();
00301         } else {
00302             return QVariant();
00303         }
00304     } else if (role == SubTitleRole) {
00305         QModelIndex sourceIndex = mapToSource(index);
00306 
00307         if (d->placesModel->isDevice(sourceIndex)) {
00308             Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00309             Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
00310 
00311             if (access) {
00312                 return access->filePath();
00313             }
00314         } else if (index.parent().row() != APPLICATIONS_ROW) {
00315             KUrl url = d->placesModel->url(sourceIndex);
00316             return url.isLocalFile() ? url.path() : url.prettyUrl();
00317         }
00318 
00319         return QVariant();
00320     } else if (role == DiskUsedSpaceRole || role == DiskFreeSpaceRole) {
00321         QModelIndex sourceIndex = mapToSource(index);
00322         QString mp;
00323 
00324         if (d->placesModel->isDevice(sourceIndex)) {
00325             Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00326             Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
00327 
00328             if (access) {
00329                 mp = access->filePath();
00330             }
00331         }
00332 
00333         if (!mp.isEmpty() && d->usageByMountpoint.contains(mp)) {
00334             UsageInfo info = d->usageByMountpoint[mp];
00335 
00336             if (role == DiskUsedSpaceRole) {
00337                 return info.used;
00338             } else {
00339                 return info.available;
00340             }
00341         }
00342     }
00343 
00344     return d->placesModel->data(mapToSource(index), role);
00345 }
00346 
00347 void SystemModel::startRefreshingUsageInfo()
00348 {
00349     if (!d->mountPointsQueue.isEmpty()) {
00350         return;
00351     }
00352 
00353     int rowCount = d->placesModel->rowCount();
00354     for (int i = 0; i < rowCount; ++i) {
00355         QModelIndex index = d->placesModel->index(i, 0);
00356         if (d->placesModel->isDevice(index)) {
00357             Solid::Device dev = d->placesModel->deviceForIndex(index);
00358             Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
00359 
00360             if (access && !access->filePath().isEmpty()) {
00361                 d->mountPointsQueue << access->filePath();
00362             }
00363         }
00364     }
00365 
00366     if (!d->mountPointsQueue.isEmpty()) {
00367         d->queryFreeSpace(d->mountPointsQueue.takeFirst());
00368     }
00369 }
00370 
00371 void SystemModel::reloadApplications()
00372 {
00373     d->loadApplications();
00374 }
00375 
00376 void SystemModel::freeSpaceInfoAvailable(const QString& mountPoint, quint64,
00377         quint64 kbUsed, quint64 kbAvailable)
00378 {
00379     UsageInfo info;
00380     info.used = kbUsed;
00381     info.available = kbAvailable;
00382 
00383     d->usageByMountpoint[mountPoint] = info;
00384 
00385     // More to process
00386     if (!d->mountPointsQueue.isEmpty()) {
00387         d->queryFreeSpace(d->mountPointsQueue.takeFirst());
00388         return;
00389     }
00390 
00391     // We're done, let's emit the changes
00392     int rowCount = d->placesModel->rowCount();
00393     for (int i = 0; i < rowCount; ++i) {
00394         QModelIndex sourceIndex = d->placesModel->index(i, 0);
00395         if (d->placesModel->isDevice(sourceIndex)) {
00396             Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00397             Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
00398 
00399             if (access && d->usageByMountpoint.contains(access->filePath())) {
00400                 info = d->usageByMountpoint[access->filePath()];
00401 
00402                 if (info.dirty) {
00403                     info.dirty = false;
00404                     d->usageByMountpoint[access->filePath()] = info;
00405                 } else {
00406                     d->usageByMountpoint.remove(access->filePath());
00407                 }
00408 
00409                 QModelIndex index = mapFromSource(sourceIndex);
00410                 emit dataChanged(index, index);
00411             }
00412         }
00413     }
00414 }
00415 
00416 void Kickoff::SystemModel::sourceDataChanged(const QModelIndex &start, const QModelIndex &end)
00417 {
00418     if (start.parent().isValid()) return;
00419 
00420     for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
00421         QModelIndex section = index(row, 0);
00422 
00423         QModelIndex new_start = index(start.row(), start.column(), section);
00424         QModelIndex new_end = index(end.row(), end.column(), section);
00425         emit dataChanged(new_start, new_end);
00426     }
00427 }
00428 
00429 void Kickoff::SystemModel::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
00430 {
00431     if (parent.isValid()) return;
00432 
00433     for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
00434         QModelIndex section = index(row, 0);
00435         beginInsertRows(section, start, end);
00436     }
00437 }
00438 
00439 void Kickoff::SystemModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int /*end*/)
00440 {
00441     if (parent.isValid()) return;
00442 
00443     endInsertRows();
00444 }
00445 
00446 void Kickoff::SystemModel::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
00447 {
00448     if (parent.isValid()) return;
00449 
00450     for (int row = BOOKMARKS_ROW; row <= LAST_ROW; ++row) {
00451         QModelIndex section = index(row, 0);
00452         beginRemoveRows(section, start, end);
00453     }
00454 }
00455 
00456 void Kickoff::SystemModel::sourceRowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
00457 {
00458     if (parent.isValid()) return;
00459 
00460     endRemoveRows();
00461 }
00462 
00463 #include "systemmodel.moc"

Applets

Skip menu "Applets"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal