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

libplasma

package.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *   Copyright 2007 by Aaron Seigo <aseigo@kde.org>                            *
00003 *   Copyright 2007 by Riccardo Iaconelli <riccardo@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 "package.h"
00022 
00023 #include <QDir>
00024 #include <QFile>
00025 
00026 #include <KArchiveDirectory>
00027 #include <KArchiveEntry>
00028 #include <KComponentData>
00029 #include <KDesktopFile>
00030 #include <KIO/CopyJob>
00031 #include <KIO/FileCopyJob>
00032 #include <KIO/Job>
00033 #include <KPluginInfo>
00034 #include <KStandardDirs>
00035 #include <KTempDir>
00036 #include <KTemporaryFile>
00037 #include <KZip>
00038 #include <KDebug>
00039 
00040 #include "packagemetadata.h"
00041 
00042 namespace Plasma
00043 {
00044 
00045 class PackagePrivate
00046 {
00047 public:
00048     PackagePrivate(const PackageStructure::Ptr st, const QString& p)
00049         : structure(st),
00050           basePath(p),
00051           valid(QFile::exists(basePath)),
00052           metadata(0)
00053     {
00054         if (valid && basePath[basePath.length() - 1] != '/') {
00055             basePath.append('/');
00056         }
00057     }
00058 
00059     ~PackagePrivate()
00060     {
00061         delete metadata;
00062     }
00063 
00064     PackageStructure::Ptr structure;
00065     QString basePath;
00066     bool valid;
00067     PackageMetadata *metadata;
00068 };
00069 
00070 Package::Package(const QString& packageRoot, const QString& package, PackageStructure::Ptr structure)
00071     : d(new PackagePrivate(structure, packageRoot + '/' + package))
00072 {
00073     structure->setPath(d->basePath);
00074 }
00075 
00076 Package::Package(const QString &packagePath, PackageStructure::Ptr structure)
00077     : d(new PackagePrivate(structure, packagePath))
00078 {
00079     structure->setPath(d->basePath);
00080 }
00081 
00082 Package::~Package()
00083 {
00084     delete d;
00085 }
00086 
00087 bool Package::isValid() const
00088 {
00089     if (!d->valid) {
00090         return false;
00091     }
00092 
00093     foreach (const char *dir, d->structure->requiredDirectories()) {
00094         if (!QFile::exists(d->basePath + d->structure->contentsPrefix() + d->structure->path(dir))) {
00095             kWarning(505) << "Could not find required directory" << dir;
00096             d->valid = false;
00097             return false;
00098         }
00099     }
00100 
00101     foreach (const char *file, d->structure->requiredFiles()) {
00102         if (!QFile::exists(d->basePath + d->structure->contentsPrefix() + d->structure->path(file))) {
00103             kWarning(505) << "Could not find required file" << file << ", look in"
00104                           << d->basePath + d->structure->contentsPrefix() + d->structure->path(file) << endl;
00105             d->valid = false;
00106             return false;
00107         }
00108     }
00109 
00110     return true;
00111 }
00112 
00113 QString Package::filePath(const char* fileType, const QString& filename) const
00114 {
00115     if (!d->valid) {
00116         kDebug() << "package is not valid";
00117         return QString();
00118     }
00119 
00120     QString path = d->structure->path(fileType);
00121 
00122     if (path.isEmpty()) {
00123         kDebug() << "no matching path came of it";
00124         return QString();
00125     }
00126 
00127     path.prepend(d->basePath + d->structure->contentsPrefix());
00128 
00129     if (!filename.isEmpty()) {
00130         path.append("/").append(filename);
00131     }
00132 
00133     if (QFile::exists(path)) {
00134         return path;
00135     }
00136 
00137     kDebug() << path << "does not exist";
00138     return QString();
00139 }
00140 
00141 QString Package::filePath(const char* fileType) const
00142 {
00143     return filePath(fileType, QString());
00144 }
00145 
00146 QStringList Package::entryList(const char* fileType) const
00147 {
00148     if (!d->valid) {
00149         return QStringList();
00150     }
00151 
00152     QString path = d->structure->path(fileType);
00153     if (path.isEmpty()) {
00154         return QStringList();
00155     }
00156 
00157     QDir dir(d->basePath + d->structure->contentsPrefix() + path);
00158 
00159     if (!dir.exists()) {
00160         return QStringList();
00161     }
00162 
00163     return dir.entryList(QDir::Files | QDir::Readable);
00164 }
00165 
00166 const PackageMetadata* Package::metadata() const
00167 {
00168     //FIXME: this only works for native plasma packges; should fall back to... PackageStructure?
00169     if (!d->metadata) {
00170         d->metadata = new PackageMetadata(d->basePath + "metadata.desktop");
00171     }
00172     return d->metadata;
00173 }
00174 
00175 const QString Package::path() const
00176 {
00177     return d->basePath;
00178 }
00179 
00180 const PackageStructure::Ptr Package::structure() const
00181 {
00182     return d->structure;
00183 }
00184 
00185 //TODO: provide a version of this that allows one to ask for certain types of packages, etc?
00186 //      should we be using KService here instead/as well?
00187 QStringList Package::listInstalled(const QString& packageRoot) // static
00188 {
00189     QDir dir(packageRoot);
00190 
00191     if (!dir.exists()) {
00192         return QStringList();
00193     }
00194 
00195     QStringList packages;
00196 
00197     foreach (const QString& sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
00198         QString metadata = packageRoot + '/' + sdir + "/metadata.desktop";
00199         if (QFile::exists(metadata)) {
00200             PackageMetadata m(metadata);
00201             packages << m.pluginName();
00202         }
00203     }
00204 
00205     return packages;
00206 }
00207 
00208 bool Package::installPackage(const QString& package,
00209                              const QString& packageRoot) // static
00210 {
00211     //TODO: report *what* failed if something does fail
00212     QDir root(packageRoot);
00213 
00214     if (!root.exists()) {
00215         KStandardDirs::makeDir(packageRoot);
00216         if (!root.exists()) {
00217             kWarning() << "Could not create package root directory:" << packageRoot;
00218             return false;
00219         }
00220     }
00221 
00222     QFileInfo fileInfo(package);
00223     if (!fileInfo.exists()) {
00224         kWarning() << "No such file:" << package;
00225         return false;
00226     }
00227 
00228     QString path;
00229     KTempDir tempdir;
00230     bool archivedPackage = false;
00231 
00232     if (fileInfo.isDir()) {
00233         // we have a directory, so let's just install what is in there
00234         path = package;
00235 
00236         // make sure we end in a slash!
00237         if (path[path.size() - 1] != '/') {
00238             path.append('/');
00239         }
00240     } else {
00241         KZip archive(package);
00242         if (!archive.open(QIODevice::ReadOnly)) {
00243             kWarning() << "Could not open package file:" << package;
00244             return false;
00245         }
00246 
00247         archivedPackage = true;
00248         const KArchiveDirectory* source = archive.directory();
00249         const KArchiveEntry* metadata = source->entry("metadata.desktop");
00250 
00251         if (!metadata) {
00252             kWarning() << "No metadata file in package" << package;
00253             return false;
00254         }
00255 
00256         path = tempdir.name();
00257         source->copyTo(path);
00258     }
00259 
00260     QString metadataPath = path + "metadata.desktop";
00261     if (!QFile::exists(metadataPath)) {
00262         kWarning() << "No metadata file in package" << package;
00263         return false;
00264     }
00265 
00266     PackageMetadata meta(metadataPath);
00267     QString targetName = meta.pluginName();
00268 
00269     if (targetName.isEmpty()) {
00270         kWarning() << "Package plugin name not specified";
00271         return false;
00272     }
00273 
00274     targetName = packageRoot + '/' + targetName;
00275     if (QFile::exists(targetName)) {
00276         kWarning() << targetName << "already exists";
00277         return false;
00278     }
00279 
00280     if (archivedPackage) {
00281         // it's in a temp dir, so just move it over.
00282         KIO::CopyJob *job = KIO::move(KUrl(path), KUrl(targetName), KIO::HideProgressInfo);
00283         if (!job->exec()) {
00284             kWarning() << "Could not move package to destination:" << targetName << " : " << job->errorString();
00285             return false;
00286         }
00287     } else {
00288         // it's a directory containing the stuff, so copy the contents rather
00289         // than move them
00290         KIO::CopyJob *job = KIO::copy(KUrl(path), KUrl(targetName), KIO::HideProgressInfo);
00291         if (!job->exec()) {
00292             kWarning() << "Could not copy package to destination:" << targetName << " : " << job->errorString();
00293             return false;
00294         }
00295     }
00296 
00297     if (archivedPackage) {
00298         // no need to remove the temp dir (which has been successfully moved if it's an archive)
00299         tempdir.setAutoRemove(false);
00300     }
00301 
00302     // and now we register it as a service =)
00303     QString metaPath = targetName + "/metadata.desktop";
00304     KDesktopFile df(metaPath);
00305     KConfigGroup cg = df.desktopGroup();
00306 
00307     // Q: should not installing it as a service disqualify it?
00308     // Q: i don't think so since KServiceTypeTrader may not be
00309     // used by the installing app in any case, and the
00310     // package is properly installed - aseigo
00311 
00312     //TODO: reduce code duplication with registerPackage below
00313 
00314     QString serviceName;
00315     if (KGlobal::hasMainComponent()) {
00316         serviceName = KGlobal::mainComponent().componentName();
00317     }
00318     serviceName.append("_plasma_applet_" + meta.pluginName());
00319 
00320     QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
00321     KIO::FileCopyJob *job = KIO::file_copy(metaPath, service, -1, KIO::HideProgressInfo);
00322     if (job->exec()) {
00323         // the icon in the installed file needs to point to the icon in the
00324         // installation dir!
00325         QString iconPath = targetName + '/' + cg.readEntry("Icon");
00326         QFile icon(iconPath);
00327         if (icon.exists()) {
00328             cg.writeEntry("Icon", iconPath);
00329         }
00330     }
00331 
00332     return true;
00333 }
00334 
00335 bool Package::registerPackage(const PackageMetadata &data, const QString &iconPath)
00336 {
00337     QString serviceName("plasma-applet-" + data.pluginName());
00338     QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
00339 
00340     if (data.pluginName().isEmpty()) {
00341         return false;
00342     }
00343 
00344     data.write(service);
00345 
00346     KDesktopFile config(service);
00347     KConfigGroup cg = config.desktopGroup();
00348     const QString type = data.type().isEmpty() ? "Service" : data.type();
00349     cg.writeEntry("Type", type);
00350     const QString serviceTypes = data.serviceType().isNull() ? "Plasma/Applet,Plasma/Containment" : data.serviceType();
00351     cg.writeEntry("X-KDE-ServiceTypes", serviceTypes);
00352     cg.writeEntry("X-KDE-PluginInfo-EnabledByDefault", true);
00353 
00354     QFile icon(iconPath);
00355     if (icon.exists()) {
00356         //FIXME: the '/' search will break on non-UNIX. do we care?
00357         QString installedIcon("plasma_applet_" + data.pluginName() +
00358                               iconPath.right(iconPath.length() - iconPath.lastIndexOf("/")));
00359         cg.writeEntry("Icon", installedIcon);
00360         installedIcon = KStandardDirs::locateLocal("icon", installedIcon);
00361         KIO::FileCopyJob *job = KIO::file_copy(iconPath, installedIcon, -1, KIO::HideProgressInfo);
00362         job->exec();
00363     }
00364 
00365     return true;
00366 }
00367 
00368 bool Package::createPackage(const PackageMetadata &metadata,
00369                             const QString &source,
00370                             const QString &destination,
00371                             const QString &icon) // static
00372 {
00373     if (!metadata.isValid()) {
00374         kWarning(550) << "Metadata file is not complete";
00375         return false;
00376     }
00377 
00378     // write metadata in a temporary file
00379     KTemporaryFile metadataFile;
00380     if (!metadataFile.open()) {
00381         return false;
00382     }
00383     metadata.write(metadataFile.fileName());
00384 
00385     // put everything into a zip archive
00386     KZip creation(destination);
00387     creation.setCompression(KZip::NoCompression);
00388     if (!creation.open(QIODevice::WriteOnly)) {
00389         return false;
00390     }
00391 
00392     creation.addLocalFile(metadataFile.fileName(), "metadata.desktop");
00393     creation.addLocalDirectory(source, "contents");
00394     creation.close();
00395     return true;
00396 }
00397 
00398 
00399 } // Namespace

libplasma

Skip menu "libplasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

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