• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

Plasma

packagestructure.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *   Copyright 2007 by Aaron Seigo <aseigo@kde.org>                            *
00003 *                                                                             *
00004 *   This library is free software; you can redistribute it and/or             *
00005 *   modify it under the terms of the GNU Library General Public               *
00006 *   License as published by the Free Software Foundation; either              *
00007 *   version 2 of the License, or (at your option) any later version.          *
00008 *                                                                             *
00009 *   This library is distributed in the hope that it will be useful,           *
00010 *   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00011 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU          *
00012 *   Library General Public License for more details.                          *
00013 *                                                                             *
00014 *   You should have received a copy of the GNU Library General Public License *
00015 *   along with this library; see the file COPYING.LIB.  If not, write to      *
00016 *   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,      *
00017 *   Boston, MA 02110-1301, USA.                                               *
00018 *******************************************************************************/
00019 
00020 #include "packagestructure.h"
00021 
00022 #include "config-plasma.h"
00023 
00024 #include <QDir>
00025 #include <QMap>
00026 #include <QFileInfo>
00027 
00028 #include <kconfiggroup.h>
00029 #include <kdebug.h>
00030 #ifndef PLASMA_NO_KIO
00031 #include <kio/job.h>
00032 #endif
00033 #include <kmimetype.h>
00034 #include <kstandarddirs.h>
00035 #include <kservicetypetrader.h>
00036 #include <ktar.h>
00037 #include <ktemporaryfile.h>
00038 #include <ktempdir.h>
00039 #include <kurl.h>
00040 #include <kzip.h>
00041 
00042 #include "package.h"
00043 #include "private/packages_p.h"
00044 #include "theme.h"
00045 
00046 namespace Plasma
00047 {
00048 
00049 class ContentStructure
00050 {
00051     public:
00052         ContentStructure()
00053             : directory(false),
00054               required(false)
00055         {
00056         }
00057 
00058         ContentStructure(const ContentStructure &other)
00059         {
00060             paths = other.paths;
00061             name = other.name;
00062             mimetypes = other.mimetypes;
00063             directory = other.directory;
00064             required = other.required;
00065         }
00066 
00067         QStringList paths;
00068         QString name;
00069         QStringList mimetypes;
00070         bool directory : 1;
00071         bool required : 1;
00072 };
00073 
00074 class PackageStructurePrivate
00075 {
00076 public:
00077     PackageStructurePrivate(const QString &t)
00078         : type(t),
00079           packageRoot("plasma/plasmoids"),
00080           servicePrefix("plasma-applet-"),
00081           metadata(0),
00082           externalPaths(false)
00083     {
00084         contentsPrefixPaths << "contents/";
00085     }
00086 
00087     ~PackageStructurePrivate()
00088     {
00089         delete metadata;
00090     }
00091 
00092     void createPackageMetadata(const QString &path);
00093     QStringList entryList(const QString &prefix, const QString &requestedPath);
00094 
00095     static QHash<QString, PackageStructure::Ptr> structures;
00096 
00097     QString type;
00098     QString path;
00099     QStringList contentsPrefixPaths;
00100     QString packageRoot;
00101     QString servicePrefix;
00102     QMap<QByteArray, ContentStructure> contents;
00103     QStringList mimetypes;
00104     PackageMetadata *metadata;
00105     bool externalPaths;
00106  };
00107 
00108 QHash<QString, PackageStructure::Ptr> PackageStructurePrivate::structures;
00109 
00110 PackageStructure::PackageStructure(QObject *parent, const QString &type)
00111     : QObject(parent),
00112       d(new PackageStructurePrivate(type))
00113 {
00114 }
00115 
00116 PackageStructure::~PackageStructure()
00117 {
00118     delete d;
00119 }
00120 
00121 PackageStructure::Ptr PackageStructure::load(const QString &packageFormat)
00122 {
00123     if (packageFormat.isEmpty()) {
00124         return Ptr(new PackageStructure());
00125     }
00126 
00127     PackageStructure::Ptr structure = PackageStructurePrivate::structures[packageFormat];
00128 
00129     if (structure) {
00130         return structure;
00131     }
00132 
00133     if (packageFormat == "Plasma/Applet") {
00134         structure = defaultPackageStructure(AppletComponent);
00135         structure->d->type = "Plasma/Applet";
00136     } else if (packageFormat == "Plasma/DataEngine") {
00137         structure = defaultPackageStructure(DataEngineComponent);
00138         structure->d->type = "Plasma/DataEngine";
00139     } else if (packageFormat == "Plasma/Runner") {
00140         structure = defaultPackageStructure(RunnerComponent);
00141         structure->d->type = "Plasma/Runner";
00142     } else if (packageFormat == "Plasma/Wallpaper") {
00143         structure = defaultPackageStructure(WallpaperComponent);
00144         structure->d->type = "Plasma/Wallpaper";
00145     } else if (packageFormat == "Plasma/Theme") {
00146         structure = Theme::packageStructure();
00147         structure->d->type = "Plasma/Theme";
00148     }
00149 
00150     if (structure) {
00151         PackageStructurePrivate::structures[packageFormat] = structure;
00152         return structure;
00153     }
00154 
00155     // first we check for plugins in sycoca
00156     QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(packageFormat);
00157     KService::List offers =
00158         KServiceTypeTrader::self()->query("Plasma/PackageStructure", constraint);
00159 
00160     QVariantList args;
00161     QString error;
00162     foreach (const KService::Ptr &offer, offers) {
00163         PackageStructure::Ptr structure(
00164             offer->createInstance<Plasma::PackageStructure>(0, args, &error));
00165 
00166         if (structure) {
00167             return structure;
00168         }
00169 
00170         kDebug() << "Couldn't load PackageStructure for" << packageFormat
00171                  << "! reason given: " << error;
00172     }
00173 
00174     // if that didn't give us any love, then we try to load from a config file
00175     structure = new PackageStructure();
00176     QString configPath("plasma/packageformats/%1rc");
00177     configPath = KStandardDirs::locate("data", configPath.arg(packageFormat));
00178 
00179     if (!configPath.isEmpty()) {
00180         KConfig config(configPath);
00181         structure->read(&config);
00182         PackageStructurePrivate::structures[packageFormat] = structure;
00183         return structure;
00184     }
00185 
00186     // try to load from absolute file path
00187     KUrl url(packageFormat);
00188     if (url.isLocalFile()) {
00189         KConfig config(url.toLocalFile(), KConfig::SimpleConfig);
00190         structure->read(&config);
00191         PackageStructurePrivate::structures[structure->type()] = structure;
00192     }
00193 #ifndef PLASMA_NO_KIO
00194     else {
00195         KTemporaryFile tmp;
00196         if (tmp.open()) {
00197             KIO::Job *job = KIO::file_copy(url, KUrl(tmp.fileName()),
00198                                            -1, KIO::Overwrite | KIO::HideProgressInfo);
00199             if (job->exec()) {
00200                 KConfig config(tmp.fileName(), KConfig::SimpleConfig);
00201                 structure->read(&config);
00202                 PackageStructurePrivate::structures[structure->type()] = structure;
00203             }
00204         }
00205     }
00206 #endif
00207 
00208     return structure;
00209 }
00210 
00211 PackageStructure &PackageStructure::operator=(const PackageStructure &rhs)
00212 {
00213     if (this == &rhs) {
00214         return *this;
00215     }
00216 
00217     *d = *rhs.d;
00218     return *this;
00219 }
00220 
00221 QString PackageStructure::type() const
00222 {
00223     return d->type;
00224 }
00225 
00226 QList<const char*> PackageStructure::directories() const
00227 {
00228     QList<const char*> dirs;
00229     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
00230     while (it != d->contents.constEnd()) {
00231         if (it.value().directory) {
00232             dirs << it.key();
00233         }
00234         ++it;
00235     }
00236     return dirs;
00237 }
00238 
00239 QList<const char*> PackageStructure::requiredDirectories() const
00240 {
00241     QList<const char*> dirs;
00242     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
00243     while (it != d->contents.constEnd()) {
00244         if (it.value().directory &&
00245             it.value().required) {
00246             dirs << it.key();
00247         }
00248         ++it;
00249     }
00250     return dirs;
00251 }
00252 
00253 QList<const char*> PackageStructure::files() const
00254 {
00255     QList<const char*> files;
00256     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
00257     while (it != d->contents.constEnd()) {
00258         if (!it.value().directory) {
00259             files << it.key();
00260         }
00261         ++it;
00262     }
00263     return files;
00264 }
00265 
00266 QList<const char*> PackageStructure::requiredFiles() const
00267 {
00268     QList<const char*> files;
00269     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
00270     while (it != d->contents.constEnd()) {
00271         if (!it.value().directory && it.value().required) {
00272             files << it.key();
00273         }
00274         ++it;
00275     }
00276     return files;
00277 }
00278 
00279 QStringList PackageStructure::entryList(const char *key)
00280 {
00281     QString p = path(key);
00282 
00283     if (p.isEmpty()) {
00284         return QStringList();
00285     }
00286 
00287     QStringList list;
00288     if (d->contentsPrefixPaths.isEmpty()) {
00289         // no prefixes is the same as d->contentsPrefixPths with QStringList() << QString()
00290         list << d->entryList(QString(), p);
00291     } else {
00292         foreach (QString prefix, d->contentsPrefixPaths) {
00293             list << d->entryList(prefix, p);
00294         }
00295     }
00296 
00297     return list;
00298 }
00299 
00300 QStringList PackageStructurePrivate::entryList(const QString &prefix, const QString &requestedPath)
00301 {
00302     QDir dir(path + prefix + requestedPath);
00303 
00304     if (externalPaths) {
00305         return dir.entryList(QDir::Files | QDir::Readable);
00306     }
00307 
00308     // ensure that we don't return files outside of our base path
00309     // due to symlink or ../ games
00310     QString canonicalized = dir.canonicalPath();
00311     if (canonicalized.startsWith(path)) {
00312         return dir.entryList(QDir::Files | QDir::Readable);
00313     }
00314 
00315     return QStringList();
00316 }
00317 
00318 void PackageStructure::addDirectoryDefinition(const char *key,
00319                                               const QString &path, const QString &name)
00320 {
00321     ContentStructure s;
00322 
00323     if (d->contents.contains(key)) {
00324         s = d->contents[key];
00325     }
00326 
00327     if (!name.isEmpty()) {
00328         s.name = name;
00329     }
00330 
00331     s.paths.append(path);
00332     s.directory = true;
00333 
00334     d->contents[key] = s;
00335 }
00336 
00337 void PackageStructure::addFileDefinition(const char *key, const QString &path, const QString &name)
00338 {
00339     ContentStructure s;
00340 
00341     if (d->contents.contains(key)) {
00342         s = d->contents[key];
00343     }
00344 
00345     if (!name.isEmpty()) {
00346         s.name = name;
00347     }
00348 
00349     s.paths.append(path);
00350     s.directory = false;
00351 
00352     d->contents[key] = s;
00353 }
00354 
00355 void PackageStructure::removeDefinition(const char *key)
00356 {
00357     d->contents.remove(key);
00358 }
00359 
00360 QString PackageStructure::path(const char *key) const
00361 {
00362     //kDebug() << "looking for" << key;
00363     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
00364     if (it == d->contents.constEnd()) {
00365         return QString();
00366     }
00367 
00368     //kDebug() << "found" << key << "and the value is" << it.value().paths.first();
00369     return it.value().paths.first();
00370 }
00371 
00372 QStringList PackageStructure::searchPath(const char *key) const
00373 {
00374     //kDebug() << "looking for" << key;
00375     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
00376     if (it == d->contents.constEnd()) {
00377         return QStringList();
00378     }
00379 
00380     //kDebug() << "found" << key << "and the value is" << it.value().paths;
00381     return it.value().paths;
00382 }
00383 
00384 QString PackageStructure::name(const char *key) const
00385 {
00386     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
00387     if (it == d->contents.constEnd()) {
00388         return QString();
00389     }
00390 
00391     return it.value().name;
00392 }
00393 
00394 void PackageStructure::setRequired(const char *key, bool required)
00395 {
00396     QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
00397     if (it == d->contents.end()) {
00398         return;
00399     }
00400 
00401     it.value().required = required;
00402 }
00403 
00404 bool PackageStructure::isRequired(const char *key) const
00405 {
00406     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
00407     if (it == d->contents.constEnd()) {
00408         return false;
00409     }
00410 
00411     return it.value().required;
00412 }
00413 
00414 void PackageStructure::setDefaultMimetypes(QStringList mimetypes)
00415 {
00416     d->mimetypes = mimetypes;
00417 }
00418 
00419 void PackageStructure::setMimetypes(const char *key, QStringList mimetypes)
00420 {
00421     QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
00422     if (it == d->contents.end()) {
00423         return;
00424     }
00425 
00426     it.value().mimetypes = mimetypes;
00427 }
00428 
00429 QStringList PackageStructure::mimetypes(const char *key) const
00430 {
00431     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
00432     if (it == d->contents.constEnd()) {
00433         return QStringList();
00434     }
00435 
00436     if (it.value().mimetypes.isEmpty()) {
00437         return d->mimetypes;
00438     }
00439 
00440     return it.value().mimetypes;
00441 }
00442 
00443 void PackageStructure::setPath(const QString &path)
00444 {
00445     KUrl url(path);
00446     QDir dir(url.toLocalFile());
00447     QString basePath = dir.canonicalPath();
00448     bool valid = QFile::exists(basePath);
00449 
00450     if (valid) {
00451         QFileInfo info(basePath);
00452         if (info.isDir() && !basePath.endsWith('/')) {
00453             basePath.append('/');
00454         }
00455         //kDebug() << "basePath is" << basePath;
00456     } else {
00457         kDebug() << path << "invalid, basePath is" << basePath;
00458         return;
00459     }
00460 
00461     if (d->path == basePath) {
00462         return;
00463     }
00464 
00465     d->path = basePath;
00466     delete d->metadata;
00467     d->metadata = 0;
00468     pathChanged();
00469 }
00470 
00471 QString PackageStructure::path() const
00472 {
00473     return d->path;
00474 }
00475 
00476 void PackageStructure::pathChanged()
00477 {
00478     // default impl does nothing, this is a hook for subclasses.
00479 }
00480 
00481 void PackageStructure::read(const KConfigBase *config)
00482 {
00483     d->contents.clear();
00484     d->mimetypes.clear();
00485     KConfigGroup general(config, QString());
00486     d->type = general.readEntry("Type", QString());
00487     d->contentsPrefixPaths = general.readEntry("ContentsPrefixPaths", d->contentsPrefixPaths);
00488     d->packageRoot = general.readEntry("DefaultPackageRoot", d->packageRoot);
00489     d->externalPaths = general.readEntry("AllowExternalPaths", d->externalPaths);
00490 
00491     QStringList groups = config->groupList();
00492     foreach (const QString &group, groups) {
00493         KConfigGroup entry(config, group);
00494         QByteArray key = group.toAscii();
00495 
00496         QString path = entry.readEntry("Path", QString());
00497         QString name = entry.readEntry("Name", QString());
00498         QStringList mimetypes = entry.readEntry("Mimetypes", QStringList());
00499         bool directory = entry.readEntry("Directory", false);
00500         bool required = entry.readEntry("Required", false);
00501 
00502         if (directory) {
00503             addDirectoryDefinition(key, path, name);
00504         } else {
00505             addFileDefinition(key, path, name);
00506         }
00507 
00508         setMimetypes(key, mimetypes);
00509         setRequired(key, required);
00510     }
00511 }
00512 
00513 void PackageStructure::write(KConfigBase *config) const
00514 {
00515     KConfigGroup general = KConfigGroup(config, "");
00516     general.writeEntry("Type", type());
00517     general.writeEntry("ContentsPrefixPaths", d->contentsPrefixPaths);
00518     general.writeEntry("DefaultPackageRoot", d->packageRoot);
00519     general.writeEntry("AllowExternalPaths", d->externalPaths);
00520 
00521     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
00522     while (it != d->contents.constEnd()) {
00523         KConfigGroup group = config->group(it.key());
00524         group.writeEntry("Path", it.value().paths);
00525         group.writeEntry("Name", it.value().name);
00526         if (!it.value().mimetypes.isEmpty()) {
00527             group.writeEntry("Mimetypes", it.value().mimetypes);
00528         }
00529         if (it.value().directory) {
00530             group.writeEntry("Directory", true);
00531         }
00532         if (it.value().required) {
00533             group.writeEntry("Required", true);
00534         }
00535 
00536         ++it;
00537     }
00538 }
00539 
00540 QString PackageStructure::contentsPrefix() const
00541 {
00542     return d->contentsPrefixPaths.isEmpty() ? QString() : d->contentsPrefixPaths.first();
00543 }
00544 
00545 void PackageStructure::setContentsPrefix(const QString &prefix)
00546 {
00547     d->contentsPrefixPaths.clear();
00548     d->contentsPrefixPaths << prefix;
00549 }
00550 
00551 QStringList PackageStructure::contentsPrefixPaths() const
00552 {
00553     return d->contentsPrefixPaths;
00554 }
00555 
00556 void PackageStructure::setContentsPrefixPaths(const QStringList &prefixPaths)
00557 {
00558     d->contentsPrefixPaths = prefixPaths;
00559 }
00560 
00561 bool PackageStructure::installPackage(const QString &package, const QString &packageRoot)
00562 {
00563     return Package::installPackage(package, packageRoot, d->servicePrefix);
00564 }
00565 
00566 bool PackageStructure::uninstallPackage(const QString &packageName, const QString &packageRoot)
00567 {
00568     return Package::uninstallPackage(packageName, packageRoot, d->servicePrefix);
00569 }
00570 
00571 void PackageStructure::createNewWidgetBrowser(QWidget *parent)
00572 {
00573     Q_UNUSED(parent)
00574     emit newWidgetBrowserFinished();
00575 }
00576 
00577 QString PackageStructure::defaultPackageRoot() const
00578 {
00579     return d->packageRoot;
00580 }
00581 
00582 QString PackageStructure::servicePrefix() const
00583 {
00584     return d->servicePrefix;
00585 }
00586 
00587 void PackageStructure::setDefaultPackageRoot(const QString &packageRoot)
00588 {
00589     d->packageRoot = packageRoot;
00590 }
00591 
00592 void PackageStructure::setServicePrefix(const QString &servicePrefix)
00593 {
00594     d->servicePrefix = servicePrefix;
00595 }
00596 
00597 void PackageStructurePrivate::createPackageMetadata(const QString &path)
00598 {
00599     delete metadata;
00600     metadata = 0;
00601 
00602     QString metadataPath(path + "/metadata.desktop");
00603     if (!QFile::exists(metadataPath)) {
00604         metadataPath.clear();
00605         kWarning() << "No metadata file in the package, expected it at:" << metadataPath;
00606     }
00607 
00608     metadata = new PackageMetadata(metadataPath);
00609 }
00610 
00611 //FIXME KDE5: should be const
00612 PackageMetadata PackageStructure::metadata()
00613 {
00614     if (!d->metadata && !d->path.isEmpty()) {
00615         QFileInfo fileInfo(d->path);
00616 
00617         if (fileInfo.isDir()) {
00618             d->createPackageMetadata(d->path);
00619         } else if (fileInfo.exists()) {
00620             KArchive *archive = 0;
00621             KMimeType::Ptr mimetype = KMimeType::findByPath(d->path);
00622 
00623             if (mimetype->is("application/zip")) {
00624                 archive = new KZip(d->path);
00625             } else if (mimetype->is("application/x-compressed-tar") ||
00626                        mimetype->is("application/x-tar")|| mimetype->is("application/x-bzip-compressed-tar")) {
00627                 archive = new KTar(d->path);
00628             } else {
00629                 kWarning() << "Could not open package file, unsupported archive format:" << d->path << mimetype->name();
00630             }
00631 
00632             if (archive->open(QIODevice::ReadOnly)) {
00633                 const KArchiveDirectory *source = archive->directory();
00634                 KTempDir tempdir;
00635                 source->copyTo(tempdir.name());
00636                 d->createPackageMetadata(tempdir.name());
00637             } else {
00638                 kWarning() << "Could not open package file:" << d->path;
00639             }
00640 
00641             delete archive;
00642         }
00643     }
00644 
00645     if (!d->metadata) {
00646         d->metadata = new PackageMetadata();
00647     }
00648 
00649     return *d->metadata;
00650 }
00651 
00652 bool PackageStructure::allowExternalPaths() const
00653 {
00654     return d->externalPaths;
00655 }
00656 
00657 void PackageStructure::setAllowExternalPaths(bool allow)
00658 {
00659     d->externalPaths = allow;
00660 }
00661 
00662 } // Plasma namespace
00663 
00664 #include "packagestructure.moc"
00665 

Plasma

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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