• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • 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 <QDir>
00023 #include <QMap>
00024 #include <QFileInfo>
00025 
00026 #include <kconfiggroup.h>
00027 #include <kstandarddirs.h>
00028 #include <kservicetypetrader.h>
00029 #include <kurl.h>
00030 #include <ktemporaryfile.h>
00031 #include <ktempdir.h>
00032 #include <kzip.h>
00033 #include <kio/netaccess.h>
00034 #include <kio/job.h>
00035 
00036 #include "package.h"
00037 #include "private/packages_p.h"
00038 #include "theme.h"
00039 
00040 namespace Plasma
00041 {
00042 
00043 class ContentStructure
00044 {
00045     public:
00046         ContentStructure()
00047             : directory(false),
00048               required(false)
00049         {
00050         }
00051 
00052         ContentStructure(const ContentStructure &other)
00053         {
00054             path = other.path;
00055             name = other.name;
00056             mimetypes = other.mimetypes;
00057             directory = other.directory;
00058             required = other.required;
00059         }
00060 
00061         QString path;
00062         QString name;
00063         QStringList mimetypes;
00064         bool directory : 1;
00065         bool required : 1;
00066 };
00067 
00068 class PackageStructurePrivate
00069 {
00070 public:
00071     PackageStructurePrivate()
00072         : metadata(0),
00073           externalPaths(false)
00074     {
00075     }
00076 
00077     ~PackageStructurePrivate()
00078     {
00079         delete metadata;
00080     }
00081 
00082     void createPackageMetadata(const QString &path);
00083 
00084     static QHash<QString, PackageStructure::Ptr> structures;
00085 
00086     QString type;
00087     QString path;
00088     QString contentsPrefix;
00089     QString packageRoot;
00090     QString servicePrefix;
00091     QMap<QByteArray, ContentStructure> contents;
00092     QStringList mimetypes;
00093     PackageMetadata *metadata;
00094     bool externalPaths;
00095  };
00096 
00097 QHash<QString, PackageStructure::Ptr> PackageStructurePrivate::structures;
00098 
00099 PackageStructure::PackageStructure(QObject *parent, const QString &type)
00100     : QObject(parent),
00101       d(new PackageStructurePrivate)
00102 {
00103     d->type = type;
00104     d->contentsPrefix = "contents/";
00105     d->packageRoot = "plasma/plasmoids/";
00106     d->servicePrefix = "plasma-applet-";
00107 }
00108 
00109 PackageStructure::~PackageStructure()
00110 {
00111     delete d;
00112 }
00113 
00114 PackageStructure::Ptr PackageStructure::load(const QString &packageFormat)
00115 {
00116     if (packageFormat.isEmpty()) {
00117         return Ptr(new PackageStructure());
00118     }
00119 
00120     PackageStructure::Ptr structure = PackageStructurePrivate::structures[packageFormat];
00121 
00122     if (structure) {
00123         return structure;
00124     }
00125 
00126     if (packageFormat == "Plasma/Applet") {
00127         structure = defaultPackageStructure(AppletComponent);
00128         structure->d->type = "Plasma/Applet";
00129     } else if (packageFormat == "Plasma/DataEngine") {
00130         structure = defaultPackageStructure(DataEngineComponent);
00131         structure->d->type = "Plasma/DataEngine";
00132     } else if (packageFormat == "Plasma/Runner") {
00133         structure = defaultPackageStructure(RunnerComponent);
00134         structure->d->type = "Plasma/Runner";
00135     } else if (packageFormat == "Plasma/Theme") {
00136         structure = Theme::packageStructure();
00137         structure->d->type = "Plasma/Theme";
00138     }
00139 
00140     if (structure) {
00141         PackageStructurePrivate::structures[packageFormat] = structure;
00142         return structure;
00143     }
00144 
00145     // first we check for plugins in sycoca
00146     QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(packageFormat);
00147     KService::List offers =
00148         KServiceTypeTrader::self()->query("Plasma/PackageStructure", constraint);
00149 
00150     QVariantList args;
00151     QString error;
00152     foreach (const KService::Ptr &offer, offers) {
00153         PackageStructure::Ptr structure(
00154             offer->createInstance<Plasma::PackageStructure>(0, args, &error));
00155 
00156         if (structure) {
00157             return structure;
00158         }
00159 
00160         kDebug() << "Couldn't load PackageStructure for" << packageFormat
00161                  << "! reason given: " << error;
00162     }
00163 
00164     // if that didn't give us any love, then we try to load from a config file
00165     structure = new PackageStructure();
00166     QString configPath("plasma/packageformats/%1rc");
00167     configPath = KStandardDirs::locate("data", configPath.arg(packageFormat));
00168 
00169     if (!configPath.isEmpty()) {
00170         KConfig config(configPath);
00171         structure->read(&config);
00172         PackageStructurePrivate::structures[packageFormat] = structure;
00173         return structure;
00174     }
00175 
00176     // try to load from absolute file path
00177     KUrl url(packageFormat);
00178     if (url.isLocalFile()) {
00179         KConfig config(KIO::NetAccess::mostLocalUrl(url, NULL).toLocalFile(), KConfig::SimpleConfig);
00180         structure->read(&config);
00181         PackageStructurePrivate::structures[structure->type()] = structure;
00182     } else {
00183         KTemporaryFile tmp;
00184         if (tmp.open()) {
00185             KIO::Job *job = KIO::file_copy(url, KUrl(tmp.fileName()),
00186                                            -1, KIO::Overwrite | KIO::HideProgressInfo);
00187             if (job->exec()) {
00188                 KConfig config(tmp.fileName(), KConfig::SimpleConfig);
00189                 structure->read(&config);
00190                 PackageStructurePrivate::structures[structure->type()] = structure;
00191             }
00192         }
00193     }
00194 
00195     return structure;
00196 }
00197 
00198 PackageStructure &PackageStructure::operator=(const PackageStructure &rhs)
00199 {
00200     if (this == &rhs) {
00201         return *this;
00202     }
00203 
00204     *d = *rhs.d;
00205     return *this;
00206 }
00207 
00208 QString PackageStructure::type() const
00209 {
00210     return d->type;
00211 }
00212 
00213 QList<const char*> PackageStructure::directories() const
00214 {
00215     QList<const char*> dirs;
00216     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
00217     while (it != d->contents.constEnd()) {
00218         if (it.value().directory) {
00219             dirs << it.key();
00220         }
00221         ++it;
00222     }
00223     return dirs;
00224 }
00225 
00226 QList<const char*> PackageStructure::requiredDirectories() 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             it.value().required) {
00233             dirs << it.key();
00234         }
00235         ++it;
00236     }
00237     return dirs;
00238 }
00239 
00240 QList<const char*> PackageStructure::files() const
00241 {
00242     QList<const char*> files;
00243     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
00244     while (it != d->contents.constEnd()) {
00245         if (!it.value().directory) {
00246             files << it.key();
00247         }
00248         ++it;
00249     }
00250     return files;
00251 }
00252 
00253 QList<const char*> PackageStructure::requiredFiles() 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 && it.value().required) {
00259             files << it.key();
00260         }
00261         ++it;
00262     }
00263     return files;
00264 }
00265 
00266 QStringList PackageStructure::entryList(const char *key)
00267 {
00268     QString p = path(key);
00269 
00270     if (p.isEmpty()) {
00271         return QStringList();
00272     }
00273 
00274     QDir dir(d->path + d->contentsPrefix + p);
00275 
00276     if (dir.exists()) {
00277         if (d->externalPaths) {
00278             return dir.entryList(QDir::Files | QDir::Readable);
00279         }
00280 
00281         // ensure that we don't return files outside of our base path
00282         // due to symlink or ../ games
00283         QString canonicalized = dir.canonicalPath();
00284         if (canonicalized.startsWith(d->path)) {
00285             return dir.entryList(QDir::Files | QDir::Readable);
00286         }
00287     }
00288 
00289     return QStringList();
00290 }
00291 
00292 void PackageStructure::addDirectoryDefinition(const char *key,
00293                                               const QString &path, const QString &name)
00294 {
00295     ContentStructure s;
00296     s.name = name;
00297     s.path = path;
00298     s.directory = true;
00299 
00300     d->contents[key] = s;
00301 }
00302 
00303 void PackageStructure::addFileDefinition(const char *key, const QString &path, const QString &name)
00304 {
00305     ContentStructure s;
00306     s.name = name;
00307     s.path = path;
00308     s.directory = false;
00309 
00310     d->contents[key] = s;
00311 }
00312 
00313 QString PackageStructure::path(const char *key) const
00314 {
00315     //kDebug() << "looking for" << key;
00316     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
00317     if (it == d->contents.constEnd()) {
00318         return QString();
00319     }
00320 
00321     //kDebug() << "found" << key << "and the value is" << it.value().path;
00322     return it.value().path;
00323 }
00324 
00325 QString PackageStructure::name(const char *key) const
00326 {
00327     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
00328     if (it == d->contents.constEnd()) {
00329         return QString();
00330     }
00331 
00332     return it.value().name;
00333 }
00334 
00335 void PackageStructure::setRequired(const char *key, bool required)
00336 {
00337     QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
00338     if (it == d->contents.end()) {
00339         return;
00340     }
00341 
00342     it.value().required = required;
00343 }
00344 
00345 bool PackageStructure::isRequired(const char *key) const
00346 {
00347     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
00348     if (it == d->contents.constEnd()) {
00349         return false;
00350     }
00351 
00352     return it.value().required;
00353 }
00354 
00355 void PackageStructure::setDefaultMimetypes(QStringList mimetypes)
00356 {
00357     d->mimetypes = mimetypes;
00358 }
00359 
00360 void PackageStructure::setMimetypes(const char *key, QStringList mimetypes)
00361 {
00362     QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
00363     if (it == d->contents.end()) {
00364         return;
00365     }
00366 
00367     it.value().mimetypes = mimetypes;
00368 }
00369 
00370 QStringList PackageStructure::mimetypes(const char *key) const
00371 {
00372     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
00373     if (it == d->contents.constEnd()) {
00374         return QStringList();
00375     }
00376 
00377     if (it.value().mimetypes.isEmpty()) {
00378         return d->mimetypes;
00379     }
00380 
00381     return it.value().mimetypes;
00382 }
00383 
00384 void PackageStructure::setPath(const QString &path)
00385 {
00386     QDir dir(path);
00387     QString basePath = dir.canonicalPath();
00388     bool valid = QFile::exists(basePath);
00389 
00390     if (valid) {
00391         QFileInfo info(basePath);
00392         if (info.isDir()) {
00393             basePath.append(QDir::separator());
00394         }
00395         //kDebug() << "basePath is" << basePath;
00396     } else {
00397         kDebug() << path << "invalid, basePath is" << basePath;
00398         return;
00399     }
00400 
00401     if (d->path == basePath) {
00402         return;
00403     }
00404 
00405     d->path = basePath;
00406     delete d->metadata;
00407     d->metadata = 0;
00408     pathChanged();
00409 }
00410 
00411 QString PackageStructure::path() const
00412 {
00413     return d->path;
00414 }
00415 
00416 void PackageStructure::pathChanged()
00417 {
00418     // default impl does nothing, this is a hook for subclasses.
00419 }
00420 
00421 void PackageStructure::read(const KConfigBase *config)
00422 {
00423     d->contents.clear();
00424     d->mimetypes.clear();
00425     d->type = config->group("").readEntry("Type", QString());
00426 
00427     QStringList groups = config->groupList();
00428     foreach (const QString &group, groups) {
00429         QByteArray key = group.toAscii();
00430         KConfigGroup entry = config->group(group);
00431 
00432         QString path = entry.readEntry("Path", QString());
00433         QString name = entry.readEntry("Name", QString());
00434         QStringList mimetypes = entry.readEntry("Mimetypes", QStringList());
00435         bool directory = entry.readEntry("Directory", false);
00436         bool required = entry.readEntry("Required", false);
00437 
00438         if (directory) {
00439             addDirectoryDefinition(key, path, name);
00440         } else {
00441             addFileDefinition(key, path, name);
00442         }
00443 
00444         setMimetypes(key, mimetypes);
00445         setRequired(key, required);
00446     }
00447 }
00448 
00449 void PackageStructure::write(KConfigBase *config) const
00450 {
00451     config->group("").writeEntry("Type", type());
00452 
00453     QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
00454     while (it != d->contents.constEnd()) {
00455         KConfigGroup group = config->group(it.key());
00456         group.writeEntry("Path", it.value().path);
00457         group.writeEntry("Name", it.value().name);
00458         if (!it.value().mimetypes.isEmpty()) {
00459             group.writeEntry("Mimetypes", it.value().mimetypes);
00460         }
00461         if (it.value().directory) {
00462             group.writeEntry("Directory", true);
00463         }
00464         if (it.value().required) {
00465             group.writeEntry("Required", true);
00466         }
00467 
00468         ++it;
00469     }
00470 }
00471 
00472 QString PackageStructure::contentsPrefix() const
00473 {
00474     return d->contentsPrefix;
00475 }
00476 
00477 void PackageStructure::setContentsPrefix(const QString &prefix)
00478 {
00479     d->contentsPrefix = prefix;
00480 }
00481 
00482 bool PackageStructure::installPackage(const QString &package, const QString &packageRoot)
00483 {
00484     return Package::installPackage(package, packageRoot, d->servicePrefix);
00485 }
00486 
00487 bool PackageStructure::uninstallPackage(const QString &packageName, const QString &packageRoot)
00488 {
00489     return Package::uninstallPackage(packageName, packageRoot, d->servicePrefix);
00490 }
00491 
00492 void PackageStructure::createNewWidgetBrowser(QWidget *parent)
00493 {
00494     Q_UNUSED(parent)
00495     emit newWidgetBrowserFinished();
00496 }
00497 
00498 QString PackageStructure::defaultPackageRoot() const
00499 {
00500     return d->packageRoot;
00501 }
00502 
00503 QString PackageStructure::servicePrefix() const
00504 {
00505     return d->servicePrefix;
00506 }
00507 
00508 void PackageStructure::setDefaultPackageRoot(const QString &packageRoot)
00509 {
00510     d->packageRoot = packageRoot;
00511 }
00512 
00513 void PackageStructure::setServicePrefix(const QString &servicePrefix)
00514 {
00515     d->servicePrefix = servicePrefix;
00516 }
00517 
00518 void PackageStructurePrivate::createPackageMetadata(const QString &path)
00519 {
00520     if (metadata) {
00521         delete metadata;
00522         metadata = 0;
00523     }
00524 
00525     QString metadataPath(path + "/metadata.desktop");
00526     if (!QFile::exists(metadataPath)) {
00527         metadataPath.clear();
00528         kWarning() << "No metadata file in the package, expected it at:" << metadataPath;
00529     }
00530 
00531     metadata = new PackageMetadata(metadataPath);
00532 }
00533 
00534 PackageMetadata PackageStructure::metadata()
00535 {
00536     if (!d->metadata && !d->path.isEmpty()) {
00537         QFileInfo fileInfo(d->path);
00538 
00539         if (fileInfo.isDir()) {
00540             d->createPackageMetadata(d->path);
00541         } else if (fileInfo.exists()) {
00542             KZip archive(d->path);
00543             if (archive.open(QIODevice::ReadOnly)) {
00544                 const KArchiveDirectory *source = archive.directory();
00545                 KTempDir tempdir;
00546                 source->copyTo(tempdir.name());
00547                 d->createPackageMetadata(tempdir.name());
00548             } else {
00549                 kWarning() << "Could not open package file:" << d->path;
00550             }
00551         }
00552     }
00553 
00554     if (!d->metadata) {
00555         d->metadata = new PackageMetadata();
00556     }
00557 
00558     return *d->metadata;
00559 }
00560 
00561 bool PackageStructure::allowExternalPaths() const
00562 {
00563     return d->externalPaths;
00564 }
00565 
00566 void PackageStructure::setAllowExternalPaths(bool allow)
00567 {
00568     d->externalPaths = allow;
00569 }
00570 
00571 } // Plasma namespace
00572 
00573 #include "packagestructure.moc"
00574 

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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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