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

Plasma

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • 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.5
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