22 #include "config-plasma.h"
26 #include <QMutableListIterator>
29 #include <kconfiggroup.h>
34 #include <kmimetype.h>
35 #include <kstandarddirs.h>
36 #include <kservicetypetrader.h>
38 #include <ktemporaryfile.h>
44 #include "private/packages_p.h"
50 class ContentStructure
59 ContentStructure(
const ContentStructure &other)
63 mimetypes = other.mimetypes;
64 directory = other.directory;
65 required = other.required;
70 QStringList mimetypes;
75 class PackageStructurePrivate
78 PackageStructurePrivate(
const QString &t)
80 packageRoot(
"plasma/plasmoids"),
81 servicePrefix(
"plasma-applet-"),
85 contentsPrefixPaths <<
"contents/";
88 ~PackageStructurePrivate()
93 void createPackageMetadata(
const QString &path);
94 QStringList entryList(
const QString &prefix,
const QString &requestedPath);
98 QStringList contentsPrefixPaths;
100 QString servicePrefix;
101 QMap<QByteArray, ContentStructure> contents;
102 QStringList mimetypes;
103 PackageMetadata *metadata;
109 d(new PackageStructurePrivate(type))
120 if (packageFormat.isEmpty()) {
126 if (packageFormat ==
"Plasma/Applet") {
128 structure->d->type =
"Plasma/Applet";
129 }
else if (packageFormat ==
"Plasma/DataEngine") {
131 structure->d->type =
"Plasma/DataEngine";
132 }
else if (packageFormat ==
"Plasma/Runner") {
134 structure->d->type =
"Plasma/Runner";
135 }
else if (packageFormat ==
"Plasma/Wallpaper") {
137 structure->d->type =
"Plasma/Wallpaper";
138 }
else if (packageFormat ==
"Plasma/Theme") {
140 structure->d->type =
"Plasma/Theme";
141 }
else if (packageFormat ==
"Plasma/Generic") {
143 structure->d->type =
"Plasma/Generic";
144 structure->setDefaultPackageRoot(
"plasma/packages/");
152 QString constraint = QString(
"[X-KDE-PluginInfo-Name] == '%1'").arg(packageFormat);
153 KService::List offers =
154 KServiceTypeTrader::self()->query(
"Plasma/PackageStructure", constraint);
158 foreach (
const KService::Ptr &offer, offers) {
166 kDebug() <<
"Couldn't load PackageStructure for" << packageFormat
167 <<
"! reason given: " << error;
172 QString configPath(
"plasma/packageformats/%1rc");
173 configPath = KStandardDirs::locate(
"data", configPath.arg(packageFormat));
175 if (!configPath.isEmpty()) {
176 KConfig config(configPath);
177 structure->read(&config);
182 KUrl url(packageFormat);
183 if (url.isLocalFile()) {
184 KConfig config(url.toLocalFile(), KConfig::SimpleConfig);
185 structure->read(&config);
187 #ifndef PLASMA_NO_KIO
191 KIO::Job *job = KIO::file_copy(url, KUrl(tmp.fileName()),
192 -1, KIO::Overwrite | KIO::HideProgressInfo);
194 KConfig config(tmp.fileName(), KConfig::SimpleConfig);
195 structure->read(&config);
221 QList<const char*> dirs;
222 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
223 while (it != d->contents.constEnd()) {
224 if (it.value().directory) {
234 QList<const char*> dirs;
235 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
236 while (it != d->contents.constEnd()) {
237 if (it.value().directory &&
238 it.value().required) {
248 QList<const char*>
files;
249 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
250 while (it != d->contents.constEnd()) {
251 if (!it.value().directory) {
261 QList<const char*>
files;
262 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
263 while (it != d->contents.constEnd()) {
264 if (!it.value().directory && it.value().required) {
274 QString p =
path(key);
277 return QStringList();
281 if (d->contentsPrefixPaths.isEmpty()) {
283 list << d->entryList(QString(), p);
285 foreach (QString prefix, d->contentsPrefixPaths) {
286 list << d->entryList(prefix, p);
293 QStringList PackageStructurePrivate::entryList(
const QString &prefix,
const QString &requestedPath)
295 QDir dir(path + prefix + requestedPath);
298 return dir.entryList(QDir::Files | QDir::Readable);
303 QString canonicalized = dir.canonicalPath();
304 if (canonicalized.startsWith(path)) {
305 return dir.entryList(QDir::Files | QDir::Readable);
308 return QStringList();
312 const QString &path,
const QString &name)
316 if (d->contents.contains(key)) {
317 s = d->contents[key];
320 if (!name.isEmpty()) {
324 s.paths.append(path);
327 d->contents[key] = s;
334 if (d->contents.contains(key)) {
335 s = d->contents[key];
338 if (!name.isEmpty()) {
342 s.paths.append(path);
345 d->contents[key] = s;
350 d->contents.remove(key);
356 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
357 if (it == d->contents.constEnd()) {
362 return it.value().paths.first();
368 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
369 if (it == d->contents.constEnd()) {
370 return QStringList();
374 return it.value().paths;
379 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
380 if (it == d->contents.constEnd()) {
384 return it.value().name;
389 QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
390 if (it == d->contents.end()) {
394 it.value().required = required;
399 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
400 if (it == d->contents.constEnd()) {
404 return it.value().required;
414 QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
415 if (it == d->contents.end()) {
424 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
425 if (it == d->contents.constEnd()) {
426 return QStringList();
429 if (it.value().mimetypes.isEmpty()) {
433 return it.value().mimetypes;
439 QDir dir(url.toLocalFile());
440 QString basePath = dir.canonicalPath();
441 bool valid = QFile::exists(basePath);
444 QFileInfo info(basePath);
445 if (info.isDir() && !basePath.endsWith(
'/')) {
446 basePath.append(
'/');
450 kDebug() << path <<
"invalid, basePath is" << basePath;
454 if (d->path == basePath) {
477 d->mimetypes.clear();
478 KConfigGroup general(config, QString());
479 d->type = general.readEntry(
"Type", QString());
480 d->contentsPrefixPaths = general.readEntry(
"ContentsPrefixPaths", d->contentsPrefixPaths);
481 d->packageRoot = general.readEntry(
"DefaultPackageRoot", d->packageRoot);
482 d->externalPaths = general.readEntry(
"AllowExternalPaths", d->externalPaths);
484 QStringList groups = config->groupList();
485 foreach (
const QString &group, groups) {
486 KConfigGroup entry(config, group);
487 QByteArray key = group.toLatin1();
489 QString
path = entry.readEntry(
"Path", QString());
490 QString
name = entry.readEntry(
"Name", QString());
491 QStringList
mimetypes = entry.readEntry(
"Mimetypes", QStringList());
492 bool directory = entry.readEntry(
"Directory",
false);
493 bool required = entry.readEntry(
"Required",
false);
508 KConfigGroup general = KConfigGroup(config,
"");
509 general.writeEntry(
"Type",
type());
510 general.writeEntry(
"ContentsPrefixPaths", d->contentsPrefixPaths);
511 general.writeEntry(
"DefaultPackageRoot", d->packageRoot);
512 general.writeEntry(
"AllowExternalPaths", d->externalPaths);
514 QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
515 while (it != d->contents.constEnd()) {
516 KConfigGroup group = config->group(it.key());
517 group.writeEntry(
"Path", it.value().paths);
518 group.writeEntry(
"Name", it.value().name);
519 if (!it.value().mimetypes.isEmpty()) {
520 group.writeEntry(
"Mimetypes", it.value().mimetypes);
522 if (it.value().directory) {
523 group.writeEntry(
"Directory",
true);
525 if (it.value().required) {
526 group.writeEntry(
"Required",
true);
535 return d->contentsPrefixPaths.isEmpty() ? QString() : d->contentsPrefixPaths.first();
540 d->contentsPrefixPaths.clear();
541 d->contentsPrefixPaths << prefix;
546 return d->contentsPrefixPaths;
551 d->contentsPrefixPaths = prefixPaths;
555 QMutableStringListIterator it(d->contentsPrefixPaths);
556 while (it.hasNext()) {
559 if (!it.value().endsWith(
'/')) {
560 it.setValue(it.value() %
'/');
583 return d->packageRoot;
588 return d->servicePrefix;
593 d->packageRoot = packageRoot;
601 void PackageStructurePrivate::createPackageMetadata(
const QString &path)
606 QString metadataPath(path +
"/metadata.desktop");
607 if (!QFile::exists(metadataPath)) {
608 kWarning() <<
"No metadata file in the package, expected it at:" << metadataPath;
609 metadataPath.clear();
612 metadata =
new PackageMetadata(metadataPath);
618 if (!d->metadata && !d->path.isEmpty()) {
619 QFileInfo fileInfo(d->path);
621 if (fileInfo.isDir()) {
622 d->createPackageMetadata(d->path);
623 }
else if (fileInfo.exists()) {
624 KArchive *archive = 0;
625 KMimeType::Ptr mimetype = KMimeType::findByPath(d->path);
627 if (mimetype->is(
"application/zip")) {
628 archive =
new KZip(d->path);
629 }
else if (mimetype->is(
"application/x-compressed-tar") || mimetype->is(
"application/x-gzip") ||
630 mimetype->is(
"application/x-xz-compressed-tar") || mimetype->is(
"application/x-lzma-compressed-tar") ||
631 mimetype->is(
"application/x-tar")|| mimetype->is(
"application/x-bzip-compressed-tar")) {
632 archive =
new KTar(d->path);
634 kWarning() <<
"Could not open package file, unsupported archive format:" << d->path << mimetype->name();
637 if (archive && archive->open(QIODevice::ReadOnly)) {
638 const KArchiveDirectory *source = archive->directory();
640 source->copyTo(tempdir.name());
641 d->createPackageMetadata(tempdir.name());
643 kWarning() <<
"Could not open package file:" << d->path;
659 return d->externalPaths;
664 d->externalPaths = allow;
669 #include "packagestructure.moc"