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

Applets

applicationmodel.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright 2007 Pino Toscano <pino@kde.org>
00003     Copyright 2007 Robert Knight <robertknight@gmail.com>
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 // Own
00022 #include "applicationmodel.h"
00023 
00024 // Qt
00025 #include <QtCore/QtAlgorithms>
00026 #include <QtCore/QList>
00027 #include <QtGui/QLabel>
00028 #include <QtGui/QLayout>
00029 #include <QtGui/QCheckBox>
00030 
00031 // KDE
00032 #include <kauthorized.h>
00033 #include <khistorycombobox.h>
00034 #include <kdesktopfile.h>
00035 #include <klineedit.h>
00036 #include <klocale.h>
00037 #include <kiconloader.h>
00038 #include <krun.h>
00039 #include <kstandarddirs.h>
00040 #include <kstringhandler.h>
00041 #include <kmimetypetrader.h>
00042 #include <kurlcompletion.h>
00043 #include <kurlrequester.h>
00044 #include <kmimetype.h>
00045 #include <kservicegroup.h>
00046 #include <ksycoca.h>
00047 #include <kdebug.h>
00048 
00049 #include <assert.h>
00050 #include <stdlib.h>
00051 #include <kbuildsycocaprogressdialog.h>
00052 #include <kconfiggroup.h>
00053 #include "kickoffadaptor.h"
00054 // Local
00055 #include "core/models.h"
00056 
00057 template <> inline
00058 void KConfigGroup::writeEntry( const char *pKey,
00059                               const KGlobalSettings::Completion& aValue,
00060                               KConfigBase::WriteConfigFlags flags)
00061 {
00062   writeEntry(pKey, int(aValue), flags);
00063 }
00064 
00065 namespace Kickoff
00066 {
00067 
00068 class AppNode
00069 {
00070 public:
00071     AppNode()
00072         : isDir(false), parent(0), fetched(false)
00073     {
00074     }
00075     ~AppNode()
00076     {
00077         qDeleteAll(children);
00078     }
00079 
00080     QIcon icon;
00081     QString genericName;
00082     QString appName;
00083     QString relPath;
00084     QString desktopEntry;
00085     bool isDir;
00086 
00087     AppNode *parent;
00088     bool fetched;
00089 
00090     QList<AppNode*> children;
00091 };
00092 
00093 class ApplicationModelPrivate
00094 {
00095 public:
00096     ApplicationModelPrivate(ApplicationModel *qq)
00097         : q(qq),
00098           root(new AppNode()),
00099           duplicatePolicy(ApplicationModel::ShowDuplicatesPolicy),
00100           sortOrder(Qt::AscendingOrder),
00101           sortColumn(Qt::DisplayRole)
00102     {
00103         systemApplications = Kickoff::systemApplicationList();
00104     }
00105 
00106     ~ApplicationModelPrivate()
00107     {
00108         delete root;
00109     }
00110 
00111     static bool AppNodeLessThan(AppNode *n1, AppNode *n2);
00112     void fillNode(const QString &relPath, AppNode *node);
00113     static QHash<QString,QString> iconNameMap();
00114 
00115     ApplicationModel *q;
00116     AppNode *root;
00117     ApplicationModel::DuplicatePolicy duplicatePolicy;
00118     Qt::SortOrder sortOrder;
00119     int sortColumn;
00120     QStringList systemApplications;
00121 };
00122 
00123 bool ApplicationModelPrivate::AppNodeLessThan(AppNode *n1, AppNode *n2)
00124 {
00125     if (n1->isDir != n2->isDir) {
00126         return n1->isDir;
00127     }
00128 
00129     const QString s1 = n1->genericName.isEmpty() ? n1->appName : n1->genericName;
00130     const QString s2 = n2->genericName.isEmpty() ? n2->appName : n2->genericName;
00131 
00132     return s1.compare(s2, Qt::CaseInsensitive) < 0;
00133 }
00134 
00135 void ApplicationModelPrivate::fillNode(const QString &_relPath, AppNode *node)
00136 {
00137    KServiceGroup::Ptr root = KServiceGroup::group(_relPath);
00138    if (!root || !root->isValid()) return;
00139 
00140    KServiceGroup::List list = root->entries();
00141 
00142    // application name <-> service map for detecting duplicate entries
00143    QHash<QString,KService::Ptr> existingServices;
00144    for (KServiceGroup::List::ConstIterator it = list.begin();
00145         it != list.end(); ++it)
00146    {
00147       QString icon;
00148       QString appName;
00149       QString genericName;
00150       QString relPath = _relPath;
00151       QString desktopEntry;
00152       bool isDir = false;
00153       const KSycocaEntry::Ptr p = (*it);
00154       if (p->isType(KST_KService))
00155       {
00156          const KService::Ptr service = KService::Ptr::staticCast(p);
00157 
00158          if (service->noDisplay())
00159             continue;
00160 
00161          icon = service->icon();
00162          appName = service->name();
00163          genericName = service->genericName();
00164          desktopEntry = service->entryPath();
00165 
00166          // check for duplicates (eg. KDE 3 and KDE 4 versions of application
00167          // both present)
00168          if (duplicatePolicy == ApplicationModel::ShowLatestOnlyPolicy &&
00169              existingServices.contains(appName)
00170             ) {
00171                 if (Kickoff::isLaterVersion(existingServices[appName],service)) {
00172                     continue;
00173                 } else {
00174                     // find and remove the existing entry with the same name
00175                     for (int i = 0 ; i < node->children.count() ; i++) {
00176                         if ( node->children[i]->appName == appName ) {
00177                             delete node->children.takeAt(i);
00178                         }
00179                     }
00180                 }
00181          }
00182          // don't duplicate applications that are configured to appear in the System tab
00183          // in the Applications tab
00184          if ( systemApplications.contains( service->desktopEntryName() ) ) {
00185              continue;
00186          }
00187 
00188          existingServices[appName] = service;
00189       }
00190       else if (p->isType(KST_KServiceGroup))
00191       {
00192          const KServiceGroup::Ptr serviceGroup = KServiceGroup::Ptr::staticCast(p);
00193 
00194          if (serviceGroup->noDisplay() || serviceGroup->childCount() == 0)
00195             continue;
00196 
00197          kDebug(250) << "Service group" << serviceGroup->entryPath() << serviceGroup->icon()
00198              << serviceGroup->relPath() << serviceGroup->directoryEntryPath();
00199 
00200          icon = serviceGroup->icon();
00201          if (iconNameMap().contains(icon)) {
00202             icon = iconNameMap().value(icon);
00203          }
00204 
00205          genericName = serviceGroup->caption();
00206          relPath = serviceGroup->relPath();
00207          appName = serviceGroup->comment();
00208          isDir = true;
00209       }
00210       else
00211       {
00212          kWarning(250) << "KServiceGroup: Unexpected object in list!";
00213          continue;
00214       }
00215 
00216       AppNode *newnode = new AppNode();
00217       newnode->icon = KIcon(icon);
00218       newnode->appName = appName;
00219       newnode->genericName = genericName;
00220       newnode->relPath = relPath;
00221       newnode->desktopEntry = desktopEntry;
00222       newnode->isDir = isDir;
00223       newnode->parent = node;
00224       node->children.append(newnode);
00225    }
00226 
00227    qStableSort(node->children.begin(), node->children.end(), ApplicationModelPrivate::AppNodeLessThan);
00228 }
00229 
00230 ApplicationModel::ApplicationModel(QObject *parent)
00231     : KickoffAbstractModel(parent), d(new ApplicationModelPrivate(this))
00232 {
00233     QDBusConnection dbus = QDBusConnection::sessionBus();
00234     (void)new KickoffAdaptor(this);
00235     QDBusConnection::sessionBus().registerObject("/kickoff", this);
00236     dbus.connect(QString(), "/kickoff", "org.kde.plasma", "reloadMenu", this, SLOT(slotReloadMenu()));
00237     connect(KSycoca::self(), SIGNAL(databaseChanged()), this, SLOT(checkSycocaChange()));
00238     d->fillNode(QString(), d->root);
00239 }
00240 
00241 ApplicationModel::~ApplicationModel()
00242 {
00243     delete d;
00244 }
00245 
00246 bool ApplicationModel::canFetchMore(const QModelIndex &parent) const
00247 {
00248     if (!parent.isValid())
00249         return false;
00250 
00251     AppNode *node = static_cast<AppNode*>(parent.internalPointer());
00252     return node->isDir && !node->fetched;
00253 }
00254 
00255 int ApplicationModel::columnCount(const QModelIndex &parent) const
00256 {
00257     Q_UNUSED(parent)
00258     return 1;
00259 }
00260 
00261 QVariant ApplicationModel::data(const QModelIndex &index, int role) const
00262 {
00263     if (!index.isValid())
00264         return QVariant();
00265 
00266     AppNode *node = static_cast<AppNode*>(index.internalPointer());
00267 
00268     switch (role) {
00269     case Qt::DisplayRole:
00270         if (!node->genericName.isEmpty()) {
00271             return node->genericName;
00272         } else {
00273             return node->appName;
00274         }
00275         break;
00276     case Kickoff::SubTitleRole:
00277         if(!node->genericName.isEmpty()) {
00278             return node->appName;
00279         }
00280         break;
00281     case Kickoff::UrlRole:
00282         return node->desktopEntry;
00283     case Qt::DecorationRole:
00284         return node->icon;
00285         break;
00286     default:
00287         ;
00288     }
00289     return QVariant();
00290 }
00291 
00292 void ApplicationModel::fetchMore(const QModelIndex &parent)
00293 {
00294     if (!parent.isValid())
00295         return;
00296 
00297     AppNode *node = static_cast<AppNode*>(parent.internalPointer());
00298     if (!node->isDir)
00299         return;
00300 
00301     emit layoutAboutToBeChanged();
00302     d->fillNode(node->relPath, node);
00303     node->fetched = true;
00304     emit layoutChanged();
00305 }
00306 
00307 bool ApplicationModel::hasChildren(const QModelIndex &parent) const
00308 {
00309     if (!parent.isValid())
00310         return true;
00311 
00312     AppNode *node = static_cast<AppNode*>(parent.internalPointer());
00313     return node->isDir;
00314 }
00315 
00316 QVariant ApplicationModel::headerData(int section, Qt::Orientation orientation, int role) const
00317 {
00318     if (orientation != Qt::Horizontal || section != 0)
00319         return QVariant();
00320 
00321     switch (role) {
00322     case Qt::DisplayRole:
00323         return i18n("Known Applications");
00324         break;
00325     default:
00326         return QVariant();
00327     }
00328 }
00329 
00330 QModelIndex ApplicationModel::index(int row, int column, const QModelIndex &parent) const
00331 {
00332     if (row < 0 || column != 0)
00333         return QModelIndex();
00334 
00335     AppNode *node = d->root;
00336     if (parent.isValid())
00337         node = static_cast<AppNode*>(parent.internalPointer());
00338 
00339     if (row >= node->children.count())
00340         return QModelIndex();
00341     else
00342         return createIndex(row, 0, node->children.at(row));
00343 }
00344 
00345 QModelIndex ApplicationModel::parent(const QModelIndex &index) const
00346 {
00347     if (!index.isValid())
00348         return QModelIndex();
00349 
00350     AppNode *node = static_cast<AppNode*>(index.internalPointer());
00351     if (node->parent->parent) {
00352         int id = node->parent->parent->children.indexOf(node->parent);
00353 
00354         if (id >= 0 && id < node->parent->parent->children.count())
00355            return createIndex(id, 0, node->parent);
00356         else
00357             return QModelIndex();
00358     }
00359     else
00360         return QModelIndex();
00361 }
00362 
00363 int ApplicationModel::rowCount(const QModelIndex &parent) const
00364 {
00365     if (!parent.isValid())
00366         return d->root->children.count();
00367 
00368     AppNode *node = static_cast<AppNode*>(parent.internalPointer());
00369     return node->children.count();
00370 }
00371 
00372 void ApplicationModel::setDuplicatePolicy(DuplicatePolicy policy)
00373 {
00374     delete d->root;
00375     d->duplicatePolicy = policy;
00376     d->root = new AppNode();
00377     d->fillNode(QString(), d->root);
00378     reset();
00379 }
00380 
00381 void ApplicationModel::slotReloadMenu()
00382 {
00383     delete d->root;
00384     d->root = new AppNode();
00385     d->fillNode(QString(), d->root);
00386     reset();
00387 }
00388 
00389 void ApplicationModel::checkSycocaChange()
00390 {
00391     if (KSycoca::self()->isChanged("services")) {
00392         slotReloadMenu();
00393     }
00394 }
00395 
00396 ApplicationModel::DuplicatePolicy ApplicationModel::duplicatePolicy() const
00397 {
00398     return d->duplicatePolicy;
00399 }
00400 
00412 QHash<QString,QString> ApplicationModelPrivate::iconNameMap()
00413 {
00414     static QHash<QString,QString> map;
00415     if (map.isEmpty()) {
00416         map.insert("gnome-util","applications-accessories");
00417         // accessibility Oxygen icon was missing when this list was compiled
00418         map.insert("accessibility-directory","applications-other");
00419         map.insert("gnome-devel","applications-development");
00420         map.insert("package_edutainment","applications-education");
00421         map.insert("gnome-joystick","applications-games");
00422         map.insert("gnome-graphics","applications-graphics");
00423         map.insert("gnome-globe","applications-internet");
00424         map.insert("gnome-multimedia","applications-multimedia");
00425         map.insert("gnome-applications","applications-office");
00426         map.insert("gnome-system","applications-system");
00427     }
00428     return map;
00429 }
00430 
00431 } // namespace Kickoff
00432 
00433 
00434 #include "applicationmodel.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