22 #include "config-plasma.h"
28 #include <kconfiggroup.h>
33 #include <kmimetype.h>
34 #include <kstandarddirs.h>
35 #include <kservicetypetrader.h>
37 #include <ktemporaryfile.h>
43 #include "private/packages_p.h"
49 class ContentStructure
58 ContentStructure(
const ContentStructure &other)
62 mimetypes = other.mimetypes;
63 directory = other.directory;
64 required = other.required;
69 QStringList mimetypes;
74 class PackageStructurePrivate
77 PackageStructurePrivate(
const QString &t)
79 packageRoot(
"plasma/plasmoids"),
80 servicePrefix(
"plasma-applet-"),
84 contentsPrefixPaths <<
"contents/";
87 ~PackageStructurePrivate()
92 void createPackageMetadata(
const QString &path);
93 QStringList entryList(
const QString &prefix,
const QString &requestedPath);
97 QStringList contentsPrefixPaths;
99 QString servicePrefix;
100 QMap<QByteArray, ContentStructure> contents;
101 QStringList mimetypes;
102 PackageMetadata *metadata;
108 d(new PackageStructurePrivate(type))
119 if (packageFormat.isEmpty()) {
125 if (packageFormat ==
"Plasma/Applet") {
127 structure->d->type =
"Plasma/Applet";
128 }
else if (packageFormat ==
"Plasma/DataEngine") {
130 structure->d->type =
"Plasma/DataEngine";
131 }
else if (packageFormat ==
"Plasma/Runner") {
133 structure->d->type =
"Plasma/Runner";
134 }
else if (packageFormat ==
"Plasma/Wallpaper") {
136 structure->d->type =
"Plasma/Wallpaper";
137 }
else if (packageFormat ==
"Plasma/Theme") {
139 structure->d->type =
"Plasma/Theme";
140 }
else if (packageFormat ==
"Plasma/Generic") {
142 structure->d->type =
"Plasma/Generic";
143 structure->setDefaultPackageRoot(KStandardDirs::locate(
"data",
"plasma/packages/"));
151 QString constraint = QString(
"[X-KDE-PluginInfo-Name] == '%1'").arg(packageFormat);
152 KService::List offers =
153 KServiceTypeTrader::self()->query(
"Plasma/PackageStructure", constraint);
157 foreach (
const KService::Ptr &offer, offers) {
165 kDebug() <<
"Couldn't load PackageStructure for" << packageFormat
166 <<
"! reason given: " << error;
171 QString configPath(
"plasma/packageformats/%1rc");
172 configPath = KStandardDirs::locate(
"data", configPath.arg(packageFormat));
174 if (!configPath.isEmpty()) {
175 KConfig config(configPath);
176 structure->read(&config);
181 KUrl url(packageFormat);
182 if (url.isLocalFile()) {
183 KConfig config(url.toLocalFile(), KConfig::SimpleConfig);
184 structure->read(&config);
186 #ifndef PLASMA_NO_KIO
190 KIO::Job *job = KIO::file_copy(url, KUrl(tmp.fileName()),
191 -1, KIO::Overwrite | KIO::HideProgressInfo);
193 KConfig config(tmp.fileName(), KConfig::SimpleConfig);
194 structure->read(&config);
220 QList<const char*> dirs;
221 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
222 while (it != d->contents.constEnd()) {
223 if (it.value().directory) {
233 QList<const char*> dirs;
234 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
235 while (it != d->contents.constEnd()) {
236 if (it.value().directory &&
237 it.value().required) {
247 QList<const char*>
files;
248 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
249 while (it != d->contents.constEnd()) {
250 if (!it.value().directory) {
260 QList<const char*>
files;
261 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
262 while (it != d->contents.constEnd()) {
263 if (!it.value().directory && it.value().required) {
273 QString p =
path(key);
276 return QStringList();
280 if (d->contentsPrefixPaths.isEmpty()) {
282 list << d->entryList(QString(), p);
284 foreach (QString prefix, d->contentsPrefixPaths) {
285 list << d->entryList(prefix, p);
292 QStringList PackageStructurePrivate::entryList(
const QString &prefix,
const QString &requestedPath)
294 QDir dir(path + prefix + requestedPath);
297 return dir.entryList(QDir::Files | QDir::Readable);
302 QString canonicalized = dir.canonicalPath();
303 if (canonicalized.startsWith(path)) {
304 return dir.entryList(QDir::Files | QDir::Readable);
307 return QStringList();
311 const QString &path,
const QString &name)
315 if (d->contents.contains(key)) {
316 s = d->contents[key];
319 if (!name.isEmpty()) {
323 s.paths.append(path);
326 d->contents[key] = s;
333 if (d->contents.contains(key)) {
334 s = d->contents[key];
337 if (!name.isEmpty()) {
341 s.paths.append(path);
344 d->contents[key] = s;
349 d->contents.remove(key);
355 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
356 if (it == d->contents.constEnd()) {
361 return it.value().paths.first();
367 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
368 if (it == d->contents.constEnd()) {
369 return QStringList();
373 return it.value().paths;
378 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
379 if (it == d->contents.constEnd()) {
383 return it.value().name;
388 QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
389 if (it == d->contents.end()) {
393 it.value().required = required;
398 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
399 if (it == d->contents.constEnd()) {
403 return it.value().required;
413 QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
414 if (it == d->contents.end()) {
423 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
424 if (it == d->contents.constEnd()) {
425 return QStringList();
428 if (it.value().mimetypes.isEmpty()) {
432 return it.value().mimetypes;
438 QDir dir(url.toLocalFile());
439 QString basePath = dir.canonicalPath();
440 bool valid = QFile::exists(basePath);
443 QFileInfo info(basePath);
444 if (info.isDir() && !basePath.endsWith(
'/')) {
445 basePath.append(
'/');
449 kDebug() << path <<
"invalid, basePath is" << basePath;
453 if (d->path == basePath) {
476 d->mimetypes.clear();
477 KConfigGroup general(config, QString());
478 d->type = general.readEntry(
"Type", QString());
479 d->contentsPrefixPaths = general.readEntry(
"ContentsPrefixPaths", d->contentsPrefixPaths);
480 d->packageRoot = general.readEntry(
"DefaultPackageRoot", d->packageRoot);
481 d->externalPaths = general.readEntry(
"AllowExternalPaths", d->externalPaths);
483 QStringList groups = config->groupList();
484 foreach (
const QString &group, groups) {
485 KConfigGroup entry(config, group);
486 QByteArray key = group.toAscii();
488 QString
path = entry.readEntry(
"Path", QString());
489 QString
name = entry.readEntry(
"Name", QString());
490 QStringList
mimetypes = entry.readEntry(
"Mimetypes", QStringList());
491 bool directory = entry.readEntry(
"Directory",
false);
492 bool required = entry.readEntry(
"Required",
false);
507 KConfigGroup general = KConfigGroup(config,
"");
508 general.writeEntry(
"Type",
type());
509 general.writeEntry(
"ContentsPrefixPaths", d->contentsPrefixPaths);
510 general.writeEntry(
"DefaultPackageRoot", d->packageRoot);
511 general.writeEntry(
"AllowExternalPaths", d->externalPaths);
513 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
514 while (it != d->contents.constEnd()) {
515 KConfigGroup group = config->group(it.key());
516 group.writeEntry(
"Path", it.value().paths);
517 group.writeEntry(
"Name", it.value().name);
518 if (!it.value().mimetypes.isEmpty()) {
519 group.writeEntry(
"Mimetypes", it.value().mimetypes);
521 if (it.value().directory) {
522 group.writeEntry(
"Directory",
true);
524 if (it.value().required) {
525 group.writeEntry(
"Required",
true);
534 return d->contentsPrefixPaths.isEmpty() ? QString() : d->contentsPrefixPaths.first();
539 d->contentsPrefixPaths.clear();
540 d->contentsPrefixPaths << prefix;
545 return d->contentsPrefixPaths;
550 d->contentsPrefixPaths = prefixPaths;
571 return d->packageRoot;
576 return d->servicePrefix;
581 d->packageRoot = packageRoot;
589 void PackageStructurePrivate::createPackageMetadata(
const QString &path)
594 QString metadataPath(path +
"/metadata.desktop");
595 if (!QFile::exists(metadataPath)) {
596 kWarning() <<
"No metadata file in the package, expected it at:" << metadataPath;
597 metadataPath.clear();
600 metadata =
new PackageMetadata(metadataPath);
606 if (!d->metadata && !d->path.isEmpty()) {
607 QFileInfo fileInfo(d->path);
609 if (fileInfo.isDir()) {
610 d->createPackageMetadata(d->path);
611 }
else if (fileInfo.exists()) {
612 KArchive *archive = 0;
613 KMimeType::Ptr mimetype = KMimeType::findByPath(d->path);
615 if (mimetype->is(
"application/zip")) {
616 archive =
new KZip(d->path);
617 }
else if (mimetype->is(
"application/x-compressed-tar") || mimetype->is(
"application/x-gzip") ||
618 mimetype->is(
"application/x-tar")|| mimetype->is(
"application/x-bzip-compressed-tar")) {
619 archive =
new KTar(d->path);
621 kWarning() <<
"Could not open package file, unsupported archive format:" << d->path << mimetype->name();
624 if (archive && archive->open(QIODevice::ReadOnly)) {
625 const KArchiveDirectory *source = archive->directory();
627 source->copyTo(tempdir.name());
628 d->createPackageMetadata(tempdir.name());
630 kWarning() <<
"Could not open package file:" << d->path;
646 return d->externalPaths;
651 d->externalPaths = allow;
656 #include "packagestructure.moc"