22 #include "config-plasma.h" 24 #include <QDirIterator> 27 #include <QMutableListIterator> 30 #include <kconfiggroup.h> 35 #include <kmimetype.h> 36 #include <kstandarddirs.h> 37 #include <kservicetypetrader.h> 39 #include <ktemporaryfile.h> 45 #include "private/packages_p.h" 51 class ContentStructure
60 ContentStructure(
const ContentStructure &other)
64 mimetypes = other.mimetypes;
65 directory = other.directory;
66 required = other.required;
71 QStringList mimetypes;
76 class PackageStructurePrivate
79 PackageStructurePrivate(
const QString &t)
81 packageRoot(
"plasma/plasmoids"),
82 servicePrefix(
"plasma-applet-"),
86 contentsPrefixPaths <<
"contents/";
89 ~PackageStructurePrivate()
94 void createPackageMetadata(
const QString &path);
95 QStringList entryList(
const QString &prefix,
const QString &requestedPath);
99 QStringList contentsPrefixPaths;
101 QString servicePrefix;
102 QMap<QByteArray, ContentStructure> contents;
103 QStringList mimetypes;
104 PackageMetadata *metadata;
110 d(new PackageStructurePrivate(type))
121 if (packageFormat.isEmpty()) {
127 if (packageFormat ==
"Plasma/Applet") {
129 structure->d->type =
"Plasma/Applet";
130 }
else if (packageFormat ==
"Plasma/DataEngine") {
132 structure->d->type =
"Plasma/DataEngine";
133 }
else if (packageFormat ==
"Plasma/Runner") {
135 structure->d->type =
"Plasma/Runner";
136 }
else if (packageFormat ==
"Plasma/Wallpaper") {
138 structure->d->type =
"Plasma/Wallpaper";
139 }
else if (packageFormat ==
"Plasma/Theme") {
141 structure->d->type =
"Plasma/Theme";
142 }
else if (packageFormat ==
"Plasma/Generic") {
144 structure->d->type =
"Plasma/Generic";
145 structure->setDefaultPackageRoot(
"plasma/packages/");
153 QString constraint = QString(
"[X-KDE-PluginInfo-Name] == '%1'").arg(packageFormat);
154 KService::List offers =
155 KServiceTypeTrader::self()->query(
"Plasma/PackageStructure", constraint);
159 foreach (
const KService::Ptr &offer, offers) {
167 kDebug() <<
"Couldn't load PackageStructure for" << packageFormat
168 <<
"! reason given: " << error;
173 QString configPath(
"plasma/packageformats/%1rc");
174 configPath = KStandardDirs::locate(
"data", configPath.arg(packageFormat));
176 if (!configPath.isEmpty()) {
177 KConfig config(configPath);
178 structure->read(&config);
183 KUrl url(packageFormat);
184 if (url.isLocalFile()) {
185 KConfig config(url.toLocalFile(), KConfig::SimpleConfig);
186 structure->read(&config);
188 #ifndef PLASMA_NO_KIO 192 KIO::Job *job = KIO::file_copy(url, KUrl(tmp.fileName()),
193 -1, KIO::Overwrite | KIO::HideProgressInfo);
195 KConfig config(tmp.fileName(), KConfig::SimpleConfig);
196 structure->read(&config);
222 QList<const char*> dirs;
223 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
224 while (it != d->contents.constEnd()) {
225 if (it.value().directory) {
235 QList<const char*> dirs;
236 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
237 while (it != d->contents.constEnd()) {
238 if (it.value().directory &&
239 it.value().required) {
249 QList<const char*>
files;
250 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
251 while (it != d->contents.constEnd()) {
252 if (!it.value().directory) {
262 QList<const char*>
files;
263 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
264 while (it != d->contents.constEnd()) {
265 if (!it.value().directory && it.value().required) {
275 QString p =
path(key);
278 return QStringList();
282 if (d->contentsPrefixPaths.isEmpty()) {
284 list << d->entryList(QString(), p);
286 foreach (QString prefix, d->contentsPrefixPaths) {
287 list << d->entryList(prefix, p);
294 QStringList PackageStructurePrivate::entryList(
const QString &prefix,
const QString &requestedPath)
296 QDir dir(
path + prefix + requestedPath);
299 return dir.entryList(QDir::Files | QDir::Readable);
304 QString canonicalized = dir.canonicalPath();
305 if (canonicalized.startsWith(
path)) {
306 return dir.entryList(QDir::Files | QDir::Readable);
309 return QStringList();
313 const QString &
path,
const QString &
name)
317 if (d->contents.contains(key)) {
318 s = d->contents[key];
321 if (!name.isEmpty()) {
325 s.paths.append(path);
328 d->contents[key] = s;
335 if (d->contents.contains(key)) {
336 s = d->contents[key];
339 if (!name.isEmpty()) {
343 s.paths.append(path);
346 d->contents[key] = s;
351 d->contents.remove(key);
357 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
358 if (it == d->contents.constEnd()) {
363 return it.value().paths.first();
369 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
370 if (it == d->contents.constEnd()) {
371 return QStringList();
375 return it.value().paths;
380 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
381 if (it == d->contents.constEnd()) {
385 return it.value().name;
390 QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
391 if (it == d->contents.end()) {
395 it.value().required = required;
400 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
401 if (it == d->contents.constEnd()) {
405 return it.value().required;
415 QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
416 if (it == d->contents.end()) {
425 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
426 if (it == d->contents.constEnd()) {
427 return QStringList();
430 if (it.value().mimetypes.isEmpty()) {
434 return it.value().mimetypes;
440 QDir dir(url.toLocalFile());
441 QString basePath = dir.canonicalPath();
442 bool valid = QFile::exists(basePath);
445 QFileInfo info(basePath);
446 if (info.isDir() && !basePath.endsWith(
'/')) {
447 basePath.append(
'/');
451 kDebug() << path <<
"invalid, basePath is" << basePath;
455 if (d->path == basePath) {
478 d->mimetypes.clear();
479 KConfigGroup general(config, QString());
480 d->type = general.readEntry(
"Type", QString());
481 d->contentsPrefixPaths = general.readEntry(
"ContentsPrefixPaths", d->contentsPrefixPaths);
482 d->packageRoot = general.readEntry(
"DefaultPackageRoot", d->packageRoot);
483 d->externalPaths = general.readEntry(
"AllowExternalPaths", d->externalPaths);
485 QStringList groups = config->groupList();
486 foreach (
const QString &group, groups) {
487 KConfigGroup entry(config, group);
488 QByteArray key = group.toLatin1();
490 QString
path = entry.readEntry(
"Path", QString());
491 QString
name = entry.readEntry(
"Name", QString());
492 QStringList
mimetypes = entry.readEntry(
"Mimetypes", QStringList());
493 bool directory = entry.readEntry(
"Directory",
false);
494 bool required = entry.readEntry(
"Required",
false);
509 KConfigGroup general = KConfigGroup(config,
"");
510 general.writeEntry(
"Type",
type());
511 general.writeEntry(
"ContentsPrefixPaths", d->contentsPrefixPaths);
512 general.writeEntry(
"DefaultPackageRoot", d->packageRoot);
513 general.writeEntry(
"AllowExternalPaths", d->externalPaths);
515 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
516 while (it != d->contents.constEnd()) {
517 KConfigGroup group = config->group(it.key());
518 group.writeEntry(
"Path", it.value().paths);
519 group.writeEntry(
"Name", it.value().name);
520 if (!it.value().mimetypes.isEmpty()) {
521 group.writeEntry(
"Mimetypes", it.value().mimetypes);
523 if (it.value().directory) {
524 group.writeEntry(
"Directory",
true);
526 if (it.value().required) {
527 group.writeEntry(
"Required",
true);
536 return d->contentsPrefixPaths.isEmpty() ? QString() : d->contentsPrefixPaths.first();
541 d->contentsPrefixPaths.clear();
542 d->contentsPrefixPaths << prefix;
547 return d->contentsPrefixPaths;
552 d->contentsPrefixPaths = prefixPaths;
556 QMutableStringListIterator it(d->contentsPrefixPaths);
557 while (it.hasNext()) {
560 if (!it.value().endsWith(
'/')) {
561 it.setValue(it.value() %
'/');
584 return d->packageRoot;
589 return d->servicePrefix;
594 d->packageRoot = packageRoot;
602 void PackageStructurePrivate::createPackageMetadata(
const QString &
path)
607 QString metadataPath(path +
"/metadata.desktop");
608 if (!QFile::exists(metadataPath)) {
609 kWarning() <<
"No metadata file in the package, expected it at:" << metadataPath;
610 metadataPath.clear();
619 if (!d->metadata && !d->path.isEmpty()) {
620 QFileInfo fileInfo(d->path);
622 if (fileInfo.isDir()) {
623 d->createPackageMetadata(d->path);
624 }
else if (fileInfo.exists()) {
625 KArchive *archive = 0;
626 KMimeType::Ptr mimetype = KMimeType::findByPath(d->path);
628 if (mimetype->is(
"application/zip")) {
629 archive =
new KZip(d->path);
630 }
else if (mimetype->is(
"application/x-compressed-tar") || mimetype->is(
"application/x-gzip") ||
631 mimetype->is(
"application/x-xz-compressed-tar") || mimetype->is(
"application/x-lzma-compressed-tar") ||
632 mimetype->is(
"application/x-tar")|| mimetype->is(
"application/x-bzip-compressed-tar")) {
633 archive =
new KTar(d->path);
635 kWarning() <<
"Could not open package file, unsupported archive format:" << d->path << mimetype->name();
638 if (archive && archive->open(QIODevice::ReadOnly)) {
639 const KArchiveDirectory *source = archive->directory();
641 source->copyTo(tempdir.name());
649 QDir dir(tempdir.name());
650 QString filename =
"metadata.desktop";
651 QFileInfo metadataFileInfo(dir, filename);
653 if (metadataFileInfo.exists()) {
654 d->createPackageMetadata(metadataFileInfo.absolutePath());
656 dir.setFilter(QDir::NoDotAndDotDot|QDir::Dirs);
657 dir.setSorting(QDir::DirsFirst);
658 QFileInfo firstDir(dir.entryInfoList().first());
659 metadataFileInfo = QFileInfo(firstDir.filePath(), filename);
660 if (metadataFileInfo.exists()) {
661 kWarning() <<
"Found in: " << metadataFileInfo.absolutePath();
662 d->createPackageMetadata(metadataFileInfo.absolutePath());
666 kWarning() <<
"Could not open package file:" << d->path;
682 return d->externalPaths;
687 d->externalPaths = allow;
692 #include "packagestructure.moc" QList< const char * > files() const
The individual files, by key, that are defined for this package.
QString name(const char *key) const
void write(KConfigBase *config) const
Write this package structure to a config file.
Plasma::Wallpaper based plugins.
QString contentsPrefix() const
QStringList entryList(const char *key)
Get the list of files of a given type.
virtual ~PackageStructure()
Destructor.
void setPath(const QString &path)
Sets the path to the package.
QStringList contentsPrefixPaths() const
void setServicePrefix(const QString &servicePrefix)
Sets service prefix.
void setDefaultMimetypes(QStringList mimetypes)
Defines the default mimetypes for any definitions that do not have associated mimetypes.
void newWidgetBrowserFinished()
Emitted when the new widget browser process completes.
Namespace for everything in libplasma.
PackageStructure::Ptr defaultPackageStructure(ComponentType type)
static PackageStructure::Ptr packageStructure()
void addFileDefinition(const char *key, const QString &path, const QString &name)
Adds a file to the structure of the package.
static bool uninstallPackage(const QString &package, const QString &packageRoot, const QString &servicePrefix)
Uninstalls a package.
static bool installPackage(const QString &package, const QString &packageRoot, const QString &servicePrefix)
Installs a package.
PackageStructure & operator=(const PackageStructure &rhs)
Assignment operator.
void setRequired(const char *key, bool required)
Sets whether or not a given part of the structure is required or not.
void setContentsPrefix(const QString &prefix)
Sets the prefix that all the contents in this package should appear under.
virtual void createNewWidgetBrowser(QWidget *parent=0)
When called, the package plugin should display a window to the user that they can use to browser...
QString defaultPackageRoot() const
PackageStructure(QObject *parent=0, const QString &type=i18nc("A non-functional package","Invalid"))
Default constructor for a package structure definition.
void setDefaultPackageRoot(const QString &packageRoot)
Sets preferred package root.
QList< const char * > requiredFiles() const
The individual required files, by key, that are defined for this package.
virtual bool uninstallPackage(const QString &packageName, const QString &packageRoot)
Uninstalls a package matching this package structure.
KSharedPtr< PackageStructure > Ptr
void addDirectoryDefinition(const char *key, const QString &path, const QString &name)
Adds a directory to the structure of the package.
QStringList mimetypes(const char *key) const
Plasma::AbstractRunner based plugsin.
virtual void pathChanged()
Called whenever the path changes so that subclasses may take package specific actions.
void setContentsPrefixPaths(const QStringList &prefixPaths)
Sets the prefixes that all the contents in this package should appear under.
static PackageStructure::Ptr load(const QString &packageFormat)
Loads a package format by name.
Plasma::Applet based plugins.
static QScriptValue type(QScriptContext *ctx, QScriptEngine *eng)
Plasma::DataEngine based plugins.
QString servicePrefix() const
QStringList searchPath(const char *key) const
void setAllowExternalPaths(bool allow)
Sets whether or not external paths/symlinks can be followed by a package.
virtual bool installPackage(const QString &archivePath, const QString &packageRoot)
Installs a package matching this package structure.
void removeDefinition(const char *key)
Removes a definition from the structure of the package.
bool isRequired(const char *key) const
void setMimetypes(const char *key, QStringList mimetypes)
Define mimetypes for a given part of the structure The path must already have been added using addDir...
QString type() const
Type of package this structure describes.
bool allowExternalPaths() const
void read(const KConfigBase *config)
Read a package structure from a config file.
virtual PackageMetadata metadata()
QList< const char * > requiredDirectories() const
The required directories defined for this package.
A description of the expected file structure of a given package type.
QList< const char * > directories() const
The directories defined for this package.