diff --git a/package.cpp b/package.cpp index 7a755c813..a9d767e73 100644 --- a/package.cpp +++ b/package.cpp @@ -22,8 +22,8 @@ #include "package.h" -#include #include +#include #include #include @@ -46,6 +46,7 @@ #endif #include "config-plasma.h" +#include "packagestructure.h" #include "pluginloader.h" #include "private/package_p.h" #include "private/packages_p.h" @@ -117,12 +118,13 @@ bool removeFolder(QString folderPath) Package Package::load(const QString &packageFormat, const QString &specialization) { - return PluginLoader::pluginLoader()->loadPackage(packageFormat, specialization); + return PluginLoader::self()->loadPackage(packageFormat, specialization); } -Package::Package() +Package::Package(PackageStructure *structure) : d(new PackagePrivate()) { + d->structure = structure; } Package::Package(const Package &other) @@ -253,33 +255,38 @@ void Package::setAllowExternalPaths(bool allow) KPluginInfo Package::metadata() const { if (!d->metadata && !d->path.isEmpty()) { - QFileInfo fileInfo(d->path); + const QString metadataPath = filePath("metadata"); + if (!metadataPath.isEmpty()) { + d->createPackageMetadata(metadataPath); + } else { + QFileInfo fileInfo(d->path); - if (fileInfo.isDir()) { - d->createPackageMetadata(d->path); - } else if (fileInfo.exists()) { - KArchive *archive = 0; - KMimeType::Ptr mimeType = KMimeType::findByPath(d->path); + if (fileInfo.isDir()) { + d->createPackageMetadata(d->path); + } else if (fileInfo.exists()) { + KArchive *archive = 0; + KMimeType::Ptr mimeType = KMimeType::findByPath(d->path); - if (mimeType->is("application/zip")) { - archive = new KZip(d->path); - } else if (mimeType->is("application/x-compressed-tar") || - mimeType->is("application/x-tar")|| mimeType->is("application/x-bzip-compressed-tar")) { - archive = new KTar(d->path); - } else { - kWarning() << "Could not open package file, unsupported archive format:" << d->path << mimeType->name(); + if (mimeType->is("application/zip")) { + archive = new KZip(d->path); + } else if (mimeType->is("application/x-compressed-tar") || + mimeType->is("application/x-tar")|| mimeType->is("application/x-bzip-compressed-tar")) { + archive = new KTar(d->path); + } else { + kWarning() << "Could not open package file, unsupported archive format:" << d->path << mimeType->name(); + } + + if (archive && archive->open(QIODevice::ReadOnly)) { + const KArchiveDirectory *source = archive->directory(); + KTempDir tempdir; + source->copyTo(tempdir.name()); + d->createPackageMetadata(tempdir.name()); + } else { + kWarning() << "Could not open package file:" << d->path; + } + + delete archive; } - - if (archive && archive->open(QIODevice::ReadOnly)) { - const KArchiveDirectory *source = archive->directory(); - KTempDir tempdir; - source->copyTo(tempdir.name()); - d->createPackageMetadata(tempdir.name()); - } else { - kWarning() << "Could not open package file:" << d->path; - } - - delete archive; } } @@ -475,7 +482,9 @@ const QString Package::path() const void Package::pathChanged() { - // default impl does nothing, this is a hook for subclasses. + if (d->structure) { + d->structure.data()->pathChanged(this); + } } QStringList Package::contentsPrefixPaths() const @@ -647,65 +656,16 @@ QList Package::requiredFiles() const return files; } -void Package::read(const KConfigBase *config) -{ - d->contents.clear(); - d->mimeTypes.clear(); - KConfigGroup general(config, QString()); - d->type = general.readEntry("Type", QString()); - d->contentsPrefixPaths = general.readEntry("ContentsPrefixPaths", d->contentsPrefixPaths); - d->defaultPackageRoot = general.readEntry("DefaultPackageRoot", d->defaultPackageRoot); - d->externalPaths = general.readEntry("AllowExternalPaths", d->externalPaths); - - QStringList groups = config->groupList(); - foreach (const QString &group, groups) { - KConfigGroup entry(config, group); - QByteArray key = group.toAscii(); - - QString path = entry.readEntry("Path", QString()); - QString name = entry.readEntry("Name", QString()); - QStringList mimeTypes = entry.readEntry("Mimetypes", QStringList()); - bool directory = entry.readEntry("Directory", false); - bool required = entry.readEntry("Required", false); - - if (directory) { - addDirectoryDefinition(key, path, name); - } else { - addFileDefinition(key, path, name); - } - - setMimeTypes(key, mimeTypes); - setRequired(key, required); - } -} - -void Package::write(KConfigBase *config) const -{ - KConfigGroup general = KConfigGroup(config, ""); - general.writeEntry("ContentsPrefixPaths", d->contentsPrefixPaths); - general.writeEntry("DefaultPackageRoot", d->defaultPackageRoot); - general.writeEntry("AllowExternalPaths", d->externalPaths); - - QMap::const_iterator it = d->contents.constBegin(); - while (it != d->contents.constEnd()) { - KConfigGroup group = config->group(it.key()); - group.writeEntry("Path", it.value().paths); - group.writeEntry("Name", it.value().name); - if (!it.value().mimeTypes.isEmpty()) { - group.writeEntry("Mimetypes", it.value().mimeTypes); - } - if (it.value().directory) { - group.writeEntry("Directory", true); - } - if (it.value().required) { - group.writeEntry("Required", true); - } - - ++it; - } -} - bool Package::installPackage(const QString &package, const QString &packageRoot) +{ + if (d->structure) { + return d->structure.data()->installPackage(this, package, packageRoot); + } + + return PackagePrivate::installPackage(package, packageRoot, d->servicePrefix); +} + +bool PackagePrivate::installPackage(const QString &package, const QString &packageRoot, const QString &servicePrefix) { //TODO: report *what* failed if something does fail QDir root(packageRoot); @@ -838,7 +798,7 @@ bool Package::installPackage(const QString &package, const QString &packageRoot) tempdir.setAutoRemove(false); } - if (!d->servicePrefix.isEmpty()) { + if (!servicePrefix.isEmpty()) { // and now we register it as a service =) QString metaPath = targetName + "/metadata.desktop"; KDesktopFile df(metaPath); @@ -851,9 +811,9 @@ bool Package::installPackage(const QString &package, const QString &packageRoot) //TODO: reduce code duplication with registerPackage below - QString serviceName = d->servicePrefix + meta.pluginName(); + const QString serviceName = servicePrefix + meta.pluginName() + ".desktop"; - QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop"); + QString service = KStandardDirs::locateLocal("services", serviceName); #ifndef PLASMA_NO_KIO KIO::FileCopyJob *job = KIO::file_copy(metaPath, service, -1, KIO::HideProgressInfo); const bool ok = job->exec(); @@ -881,6 +841,15 @@ bool Package::installPackage(const QString &package, const QString &packageRoot) } bool Package::uninstallPackage(const QString &packageName, const QString &packageRoot) +{ + if (d->structure) { + return d->structure.data()->uninstallPackage(this, packageName, packageRoot); + } + + return PackagePrivate::uninstallPackage(packageName, packageRoot, d->servicePrefix); +} + +bool PackagePrivate::uninstallPackage(const QString &packageName, const QString &packageRoot, const QString &servicePrefix) { // We need to remove the package directory and its metadata file. const QString targetName = packageRoot + '/' + packageName; @@ -890,9 +859,9 @@ bool Package::uninstallPackage(const QString &packageName, const QString &packag return false; } - QString serviceName = d->servicePrefix + packageName; + const QString serviceName = servicePrefix + packageName + ".desktop"; - QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop"); + QString service = KStandardDirs::locateLocal("services", serviceName); kDebug() << "Removing service file " << service; bool ok = QFile::remove(service); @@ -1015,15 +984,4 @@ void PackagePrivate::createPackageMetadata(const QString &path) metadata = new KPluginInfo(metadataPath); } -PackageFactory::PackageFactory(QObject *parent, const QVariantList &args) - : QObject(parent) -{ - Q_UNUSED(args) -} - -Package PackageFactory::package() const -{ - return Package(); -} - } // Namespace diff --git a/package.h b/package.h index 2dda8ba96..344bc13da 100644 --- a/package.h +++ b/package.h @@ -55,14 +55,14 @@ namespace Plasma package.addFileDefinition("mainscript", "code/main.js", i18n("Main Script File")); package.setRequired("mainscript", true); @endcode - * One may also choose to create a subclass of Package and include the setup + * One may also choose to create a subclass of PackageStructure and include the setup * in the constructor. * * Either way, Package creates a self-documenting contract between the packager and * the application without exposing package internals such as actual on-disk structure * of the package or requiring that all contents be explicitly known ahead of time. * - * Subclassing Package does have provide a number of potential const benefits: + * Subclassing PackageStructure does have provide a number of potential const benefits: * * the package can be notified of path changes via the virtual pathChanged() method * * the subclass may implement mechanisms to install and remove packages using the * virtual installPackage and uninstallPackage methods @@ -71,6 +71,7 @@ namespace Plasma //TODO: write documentation on USING a package class PackagePrivate; +class PackageStructure; class PLASMA_EXPORT Package { @@ -86,10 +87,13 @@ public: static Package load(const QString &format, const QString &specialization = QString()); /** - * Default constructor that creates an invalid Package + * Default constructor + * + * @arg structure if a NULL pointer is passed in, this will creates an empty (invalid) Package; + * otherwise the structure is allowed to set up the Package's initial layout * @since 4.6 */ - explicit Package(); + explicit Package(PackageStructure *structure = 0); /** * Copy constructore @@ -97,7 +101,7 @@ public: */ Package(const Package &other); - virtual ~Package(); + ~Package(); /** * Assignment operator @@ -186,7 +190,7 @@ public: /** * @return the package metadata object. */ - virtual KPluginInfo metadata() const; + KPluginInfo metadata() const; /** * @return a SHA1 hash digest of the contents of the package in hexadecimal form @@ -290,7 +294,7 @@ public: * Called whenever the path changes so that subclasses may take * package specific actions. */ - virtual void pathChanged(); + void pathChanged(); // Content structure description methods /** @@ -313,16 +317,6 @@ public: */ QList requiredFiles() const; - /** - * Read a package structure from a config file. - */ - void read(const KConfigBase *config); - - /** - * Write this package structure to a config file. - */ - void write(KConfigBase *config) const; - /** * Installs a package matching this package structure. By default installs a * native Plasma::Package. @@ -332,7 +326,7 @@ public: * installed to * @return true on successful installation, false otherwise **/ - virtual bool installPackage(const QString &archivePath, const QString &packageRoot); + bool installPackage(const QString &archivePath, const QString &packageRoot); /** * Uninstalls a package matching this package structure. @@ -341,37 +335,13 @@ public: * @param packageRoot path to the directory where the package should be installed to * @return true on successful removal of the package, false otherwise */ - virtual bool uninstallPackage(const QString &packageName, const QString &packageRoot); + bool uninstallPackage(const QString &packageName, const QString &packageRoot); private: PackagePrivate * const d; }; -class PackageFactory : public QObject -{ - Q_OBJECT - -public: - PackageFactory(QObject *parent, const QVariantList &args); - virtual Package package() const; -}; - -} // Namespace - -/** - * Register a Package class when it is contained in a loadable module - */ -#define K_EXPORT_PLASMA_PACKAGE(libname, classname) \ -class classname "_Factory" : public Plasma::PackageFactory { \ - Q_OBJECT \ -public: \ - classname "_PackageFactory"(QObject *parent, const QVariantList &args) \ - : Plasma::PackageFactory(parent, args) {} \ - Package package() const { return classname(); } \ -}; \ -K_PLUGIN_FACTORY(factory, registerPlugin();) \ -K_EXPORT_PLUGIN(factory("plasma_package_" #libname)) \ -K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION) +} Q_DECLARE_METATYPE(Plasma::Package) #endif