• Skip to content
  • Skip to link menu
KDE 4.1 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 <KDiskFreeSpace>
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 {
00060     UsageInfo()
00061         : used(0),
00062           available(0),
00063           dirty(true) {}
00064 
00065     quint64 used;
00066     quint64 available;
00067     bool dirty;
00068 };
00069 
00070 class SystemModel::Private
00071 {
00072 public:
00073     Private(SystemModel *parent)
00074         :q(parent)
00075         ,placesModel(new KFilePlacesModel(parent))
00076     {
00077         q->setSourceModel(placesModel);
00078 
00079         connect(placesModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
00080                 q, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
00081         connect(placesModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
00082                 q, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)));
00083         connect(placesModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
00084                 q, SLOT(sourceRowsInserted(QModelIndex,int,int)));
00085         connect(placesModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
00086                 q, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
00087         connect(placesModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
00088                 q, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
00089 
00090         topLevelSections << i18n("Applications")
00091                          << i18n("Places")
00092                          << i18n("Removable Storage")
00093                          << i18n("Storage");
00094         loadApplications();
00095         connect(&refreshTimer, SIGNAL(timeout()),
00096                 q, SLOT(startRefreshingUsageInfo()));
00097         refreshTimer.start(10000);
00098         QTimer::singleShot(0, q, SLOT(startRefreshingUsageInfo()));
00099         connect(KSycoca::self(), SIGNAL(databaseChanged()), q, SLOT(reloadApplications()));
00100     }
00101 
00102     void queryFreeSpace(const QString& mountPoint)
00103     {
00104         KDiskFreeSpace *freeSpace = KDiskFreeSpace::findUsageInfo(mountPoint);
00105         connect(freeSpace, SIGNAL(foundMountPoint(QString,quint64,quint64,quint64)),
00106                 q, SLOT(freeSpaceInfoAvailable(QString,quint64,quint64,quint64)));
00107     }
00108 
00109     void loadApplications()
00110     {
00111         QStringList apps = Kickoff::systemApplicationList();
00112         appsList.clear();
00113 
00114         foreach (const QString &app, apps) {
00115             KService::Ptr service = KService::serviceByStorageId(app);
00116 
00117             if (!service) {
00118                 continue;
00119             }
00120 
00121             appsList << service;
00122         }
00123         //kDebug() << "*************" << appsList;
00124     }
00125 
00126     SystemModel * const q;
00127     KFilePlacesModel *placesModel;
00128     QStringList topLevelSections;
00129     KService::List appsList;
00130     QList<QString> mountPointsQueue;
00131     QMap<QString, UsageInfo> usageByMountpoint;
00132     QTimer refreshTimer;
00133 };
00134 
00135 SystemModel::SystemModel(QObject *parent)
00136     : KickoffProxyModel(parent)
00137     , d(new Private(this))
00138 {
00139 }
00140 
00141 SystemModel::~SystemModel()
00142 {
00143     delete d;
00144 }
00145 
00146 QModelIndex SystemModel::mapFromSource(const QModelIndex &sourceIndex) const
00147 {
00148     if (!sourceIndex.isValid()) return QModelIndex();
00149 
00150     QModelIndex parent;
00151 
00152     if (!d->placesModel->isDevice(sourceIndex)) {
00153         parent = index(BOOKMARKS_ROW, 0);
00154     } else {
00155         Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00156 
00157         Solid::StorageDrive *drive = 0;
00158         Solid::Device parentDevice = dev;
00159         while (parentDevice.isValid() && !drive) {
00160             drive = parentDevice.as<Solid::StorageDrive>();
00161             parentDevice = parentDevice.parent();
00162         }
00163 
00164         if (drive && (drive->isHotpluggable() || drive->isRemovable())) {
00165             parent = index(REMOVABLE_ROW, 0);
00166         } else {
00167             parent = index(FIXED_ROW, 0);
00168         }
00169     }
00170 
00171     return index(sourceIndex.row(), 0, parent);
00172 }
00173 
00174 QModelIndex SystemModel::mapToSource(const QModelIndex &proxyIndex) const
00175 {
00176     if (!proxyIndex.isValid() || !proxyIndex.parent().isValid()) {
00177         return QModelIndex();
00178     }
00179 
00180     return d->placesModel->index(proxyIndex.row(), proxyIndex.column());
00181 }
00182 
00183 QModelIndex SystemModel::index(int row, int column, const QModelIndex &parent) const
00184 {
00185     if (!parent.isValid()) {
00186         return createIndex(row, column, 0);
00187     }
00188 
00189     // We use the row+1 of the parent as internal Id.
00190     return createIndex(row, column, parent.row()+1);
00191 }
00192 
00193 QModelIndex SystemModel::parent(const QModelIndex &item) const
00194 {
00195     if (item.internalId()>0) {
00196         return index(item.internalId()-1, 0);
00197     } else {
00198         return QModelIndex();
00199     }
00200 }
00201 
00202 int SystemModel::rowCount(const QModelIndex &parent) const
00203 {
00204     if (!parent.isValid()) {
00205         return LAST_ROW + 1;
00206     } else if (!parent.parent().isValid()) {
00207         switch (parent.row()) {
00208             case APPLICATIONS_ROW:
00209                 return d->appsList.size();
00210                 break;
00211             case BOOKMARKS_ROW:
00212                 return d->placesModel->rowCount();
00213                 break;
00214             case REMOVABLE_ROW:
00215                 return d->placesModel->rowCount();
00216                 break;
00217             default:
00218                 return 0;
00219         }
00220     }
00221 
00222     return 0;
00223 }
00224 
00225 int SystemModel::columnCount(const QModelIndex &/*parent*/) const
00226 {
00227     return 1;
00228 }
00229 
00230 QVariant SystemModel::data(const QModelIndex &index, int role) const
00231 {
00232     if (!index.isValid()) {
00233         return QVariant();
00234     }
00235 
00236     if (index.internalId() == 0) {
00237         if (role == Qt::DisplayRole) {
00238             return d->topLevelSections[index.row()];
00239         } else {
00240             return QVariant();
00241         }
00242     }
00243 
00244     if (index.internalId() - 1 == APPLICATIONS_ROW) {
00245         if (d->appsList.count() <= index.row()) {
00246             return QVariant();
00247         }
00248 
00249         KService::Ptr service = d->appsList[index.row()];
00250 
00251         switch(role) {
00252         case Qt::DisplayRole:
00253             return service->name();
00254         case Qt::DecorationRole:
00255             return KIcon(service->icon());
00256         case SubTitleRole:
00257             return service->genericName();
00258         case UrlRole:
00259             return service->entryPath();
00260         default:
00261             return QVariant();
00262         }
00263     }
00264 
00265     if (role==UrlRole && !d->placesModel->isHidden(mapToSource(index))) {
00266         QModelIndex parent = index.parent();
00267         QModelIndex sourceIndex = mapToSource(index);
00268 
00269         bool isDevice = d->placesModel->isDevice(sourceIndex);
00270         bool wellPlaced = false;
00271 
00272         if (!isDevice && parent.row()==BOOKMARKS_ROW) {
00273             wellPlaced = true;
00274         } else if (isDevice) {
00275             Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00276 
00277             Solid::StorageDrive *drive = 0;
00278             Solid::Device parentDevice = dev;
00279             while (parentDevice.isValid() && !drive) {
00280                 drive = parentDevice.as<Solid::StorageDrive>();
00281                 parentDevice = parentDevice.parent();
00282             }
00283 
00284             bool fixed = !drive || (!drive->isHotpluggable() && !drive->isRemovable());
00285 
00286             if (!fixed && parent.row()==REMOVABLE_ROW) {
00287                 wellPlaced = true;
00288             } else if (fixed && parent.row()==FIXED_ROW) {
00289                 wellPlaced = true;
00290             }
00291         }
00292 
00293         if (wellPlaced) {
00294             return d->placesModel->url(sourceIndex).url();
00295         } else {
00296             return QVariant();
00297         }
00298     } else if (role==DeviceUdiRole) {
00299         QModelIndex sourceIndex = mapToSource(index);
00300 
00301         if (d->placesModel->isDevice(sourceIndex)) {
00302             Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00303             return dev.udi();
00304         } else {
00305             return QVariant();
00306         }
00307     } else if (role==SubTitleRole) {
00308         QModelIndex sourceIndex = mapToSource(index);
00309 
00310         if (d->placesModel->isDevice(sourceIndex)) {
00311             Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00312             Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
00313 
00314             if (access) {
00315                 return access->filePath();
00316             }
00317         } else if (index.parent().row()!=APPLICATIONS_ROW) {
00318             KUrl url = d->placesModel->url(sourceIndex);
00319             return url.isLocalFile() ? url.path() : url.prettyUrl();
00320         }
00321 
00322         return QVariant();
00323     } else if (role==DiskUsedSpaceRole || role== DiskFreeSpaceRole) {
00324         QModelIndex sourceIndex = mapToSource(index);
00325         QString mp;
00326 
00327         if (d->placesModel->isDevice(sourceIndex)) {
00328             Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00329             Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
00330 
00331             if (access) {
00332                 mp = access->filePath();
00333             }
00334         }
00335 
00336         if (!mp.isEmpty() && d->usageByMountpoint.contains(mp)) {
00337             UsageInfo info = d->usageByMountpoint[mp];
00338 
00339             if (role==DiskUsedSpaceRole) {
00340                 return info.used;
00341             } else {
00342                 return info.available;
00343             }
00344         }
00345     }
00346 
00347     return d->placesModel->data(mapToSource(index), role);
00348 }
00349 
00350 void SystemModel::startRefreshingUsageInfo()
00351 {
00352     if (!d->mountPointsQueue.isEmpty()) {
00353         return;
00354     }
00355 
00356     int rowCount = d->placesModel->rowCount();
00357     for (int i=0; i<rowCount; ++i) {
00358         QModelIndex index = d->placesModel->index(i, 0);
00359         if (d->placesModel->isDevice(index)) {
00360             Solid::Device dev = d->placesModel->deviceForIndex(index);
00361             Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
00362 
00363             if (access && !access->filePath().isEmpty()) {
00364                 d->mountPointsQueue << access->filePath();
00365             }
00366         }
00367     }
00368 
00369     if (!d->mountPointsQueue.isEmpty()) {
00370         d->queryFreeSpace(d->mountPointsQueue.takeFirst());
00371     }
00372 }
00373 
00374 void SystemModel::reloadApplications()
00375 {
00376     d->loadApplications();
00377 }
00378 
00379 void SystemModel::freeSpaceInfoAvailable(const QString& mountPoint, quint64,
00380                                          quint64 kbUsed, quint64 kbAvailable)
00381 {
00382     UsageInfo info;
00383     info.used = kbUsed;
00384     info.available = kbAvailable;
00385 
00386     d->usageByMountpoint[mountPoint] = info;
00387 
00388     // More to process
00389     if (!d->mountPointsQueue.isEmpty()) {
00390         d->queryFreeSpace(d->mountPointsQueue.takeFirst());
00391         return;
00392     }
00393 
00394     // We're done, let's emit the changes
00395     int rowCount = d->placesModel->rowCount();
00396     for (int i=0; i<rowCount; ++i) {
00397         QModelIndex sourceIndex = d->placesModel->index(i, 0);
00398         if (d->placesModel->isDevice(sourceIndex)) {
00399             Solid::Device dev = d->placesModel->deviceForIndex(sourceIndex);
00400             Solid::StorageAccess *access = dev.as<Solid::StorageAccess>();
00401 
00402             if (access && d->usageByMountpoint.contains(access->filePath())) {
00403                 info = d->usageByMountpoint[access->filePath()];
00404 
00405                 if (info.dirty) {
00406                     info.dirty = false;
00407                     d->usageByMountpoint[access->filePath()] = info;
00408                 } else {
00409                     d->usageByMountpoint.remove(access->filePath());
00410                 }
00411 
00412                 QModelIndex index = mapFromSource(sourceIndex);
00413                 emit dataChanged(index, index);
00414             }
00415         }
00416     }
00417 }
00418 
00419 void Kickoff::SystemModel::sourceDataChanged(const QModelIndex &start, const QModelIndex &end)
00420 {
00421     if (start.parent().isValid()) return;
00422 
00423     for (int row = BOOKMARKS_ROW; row<=LAST_ROW; ++row) {
00424         QModelIndex section = index(row, 0);
00425 
00426         QModelIndex new_start = index(start.row(), start.column(), section);
00427         QModelIndex new_end = index(end.row(), end.column(), section);
00428         emit dataChanged(new_start, new_end);
00429     }
00430 }
00431 
00432 void Kickoff::SystemModel::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
00433 {
00434     if (parent.isValid()) return;
00435 
00436     for (int row = BOOKMARKS_ROW; row<=LAST_ROW; ++row) {
00437         QModelIndex section = index(row, 0);
00438         beginInsertRows(section, start, end);
00439     }
00440 }
00441 
00442 void Kickoff::SystemModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int /*end*/)
00443 {
00444     if (parent.isValid()) return;
00445 
00446     endInsertRows();
00447 }
00448 
00449 void Kickoff::SystemModel::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
00450 {
00451     if (parent.isValid()) return;
00452 
00453     for (int row = BOOKMARKS_ROW; row<=LAST_ROW; ++row) {
00454         QModelIndex section = index(row, 0);
00455         beginRemoveRows(section, start, end);
00456     }
00457 }
00458 
00459 void Kickoff::SystemModel::sourceRowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
00460 {
00461     if (parent.isValid()) return;
00462 
00463     endRemoveRows();
00464 }
00465 
00466 #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
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
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