• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.5 API Reference
  • KDE Home
  • Contact Us
 

Plasma

  • plasma
packagestructure.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 * Copyright 2007 by Aaron Seigo <aseigo@kde.org> *
3 * *
4 * This library is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Library General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2 of the License, or (at your option) any later version. *
8 * *
9 * This library is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Library General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Library General Public License *
15 * along with this library; see the file COPYING.LIB. If not, write to *
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301, USA. *
18 *******************************************************************************/
19 
20 #include "packagestructure.h"
21 
22 #include "config-plasma.h"
23 
24 #include <QDir>
25 #include <QMap>
26 #include <QFileInfo>
27 
28 #include <kconfiggroup.h>
29 #include <kdebug.h>
30 #ifndef PLASMA_NO_KIO
31 #include <kio/job.h>
32 #endif
33 #include <kmimetype.h>
34 #include <kstandarddirs.h>
35 #include <kservicetypetrader.h>
36 #include <ktar.h>
37 #include <ktemporaryfile.h>
38 #include <ktempdir.h>
39 #include <kurl.h>
40 #include <kzip.h>
41 
42 #include "package.h"
43 #include "private/packages_p.h"
44 #include "theme.h"
45 
46 namespace Plasma
47 {
48 
49 class ContentStructure
50 {
51  public:
52  ContentStructure()
53  : directory(false),
54  required(false)
55  {
56  }
57 
58  ContentStructure(const ContentStructure &other)
59  {
60  paths = other.paths;
61  name = other.name;
62  mimetypes = other.mimetypes;
63  directory = other.directory;
64  required = other.required;
65  }
66 
67  QStringList paths;
68  QString name;
69  QStringList mimetypes;
70  bool directory : 1;
71  bool required : 1;
72 };
73 
74 class PackageStructurePrivate
75 {
76 public:
77  PackageStructurePrivate(const QString &t)
78  : type(t),
79  packageRoot("plasma/plasmoids"),
80  servicePrefix("plasma-applet-"),
81  metadata(0),
82  externalPaths(false)
83  {
84  contentsPrefixPaths << "contents/";
85  }
86 
87  ~PackageStructurePrivate()
88  {
89  delete metadata;
90  }
91 
92  void createPackageMetadata(const QString &path);
93  QStringList entryList(const QString &prefix, const QString &requestedPath);
94 
95  QString type;
96  QString path;
97  QStringList contentsPrefixPaths;
98  QString packageRoot;
99  QString servicePrefix;
100  QMap<QByteArray, ContentStructure> contents;
101  QStringList mimetypes;
102  PackageMetadata *metadata;
103  bool externalPaths;
104  };
105 
106 PackageStructure::PackageStructure(QObject *parent, const QString &type)
107  : QObject(parent),
108  d(new PackageStructurePrivate(type))
109 {
110 }
111 
112 PackageStructure::~PackageStructure()
113 {
114  delete d;
115 }
116 
117 PackageStructure::Ptr PackageStructure::load(const QString &packageFormat)
118 {
119  if (packageFormat.isEmpty()) {
120  return Ptr(new PackageStructure());
121  }
122 
123  PackageStructure::Ptr structure;
124 
125  if (packageFormat == "Plasma/Applet") {
126  structure = defaultPackageStructure(AppletComponent);
127  structure->d->type = "Plasma/Applet";
128  } else if (packageFormat == "Plasma/DataEngine") {
129  structure = defaultPackageStructure(DataEngineComponent);
130  structure->d->type = "Plasma/DataEngine";
131  } else if (packageFormat == "Plasma/Runner") {
132  structure = defaultPackageStructure(RunnerComponent);
133  structure->d->type = "Plasma/Runner";
134  } else if (packageFormat == "Plasma/Wallpaper") {
135  structure = defaultPackageStructure(WallpaperComponent);
136  structure->d->type = "Plasma/Wallpaper";
137  } else if (packageFormat == "Plasma/Theme") {
138  structure = Theme::packageStructure();
139  structure->d->type = "Plasma/Theme";
140  } else if (packageFormat == "Plasma/Generic") {
141  structure = defaultPackageStructure(GenericComponent);
142  structure->d->type = "Plasma/Generic";
143  structure->setDefaultPackageRoot(KStandardDirs::locate("data", "plasma/packages/"));
144  }
145 
146  if (structure) {
147  return structure;
148  }
149 
150  // first we check for plugins in sycoca
151  QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(packageFormat);
152  KService::List offers =
153  KServiceTypeTrader::self()->query("Plasma/PackageStructure", constraint);
154 
155  QVariantList args;
156  QString error;
157  foreach (const KService::Ptr &offer, offers) {
158  PackageStructure::Ptr structure(
159  offer->createInstance<Plasma::PackageStructure>(0, args, &error));
160 
161  if (structure) {
162  return structure;
163  }
164 
165  kDebug() << "Couldn't load PackageStructure for" << packageFormat
166  << "! reason given: " << error;
167  }
168 
169  // if that didn't give us any love, then we try to load from a config file
170  structure = new PackageStructure();
171  QString configPath("plasma/packageformats/%1rc");
172  configPath = KStandardDirs::locate("data", configPath.arg(packageFormat));
173 
174  if (!configPath.isEmpty()) {
175  KConfig config(configPath);
176  structure->read(&config);
177  return structure;
178  }
179 
180  // try to load from absolute file path
181  KUrl url(packageFormat);
182  if (url.isLocalFile()) {
183  KConfig config(url.toLocalFile(), KConfig::SimpleConfig);
184  structure->read(&config);
185  }
186 #ifndef PLASMA_NO_KIO
187  else {
188  KTemporaryFile tmp;
189  if (tmp.open()) {
190  KIO::Job *job = KIO::file_copy(url, KUrl(tmp.fileName()),
191  -1, KIO::Overwrite | KIO::HideProgressInfo);
192  if (job->exec()) {
193  KConfig config(tmp.fileName(), KConfig::SimpleConfig);
194  structure->read(&config);
195  }
196  }
197  }
198 #endif
199 
200  return structure;
201 }
202 
203 PackageStructure &PackageStructure::operator=(const PackageStructure &rhs)
204 {
205  if (this == &rhs) {
206  return *this;
207  }
208 
209  *d = *rhs.d;
210  return *this;
211 }
212 
213 QString PackageStructure::type() const
214 {
215  return d->type;
216 }
217 
218 QList<const char*> PackageStructure::directories() const
219 {
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) {
224  dirs << it.key();
225  }
226  ++it;
227  }
228  return dirs;
229 }
230 
231 QList<const char*> PackageStructure::requiredDirectories() const
232 {
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) {
238  dirs << it.key();
239  }
240  ++it;
241  }
242  return dirs;
243 }
244 
245 QList<const char*> PackageStructure::files() const
246 {
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) {
251  files << it.key();
252  }
253  ++it;
254  }
255  return files;
256 }
257 
258 QList<const char*> PackageStructure::requiredFiles() const
259 {
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) {
264  files << it.key();
265  }
266  ++it;
267  }
268  return files;
269 }
270 
271 QStringList PackageStructure::entryList(const char *key)
272 {
273  QString p = path(key);
274 
275  if (p.isEmpty()) {
276  return QStringList();
277  }
278 
279  QStringList list;
280  if (d->contentsPrefixPaths.isEmpty()) {
281  // no prefixes is the same as d->contentsPrefixPths with QStringList() << QString()
282  list << d->entryList(QString(), p);
283  } else {
284  foreach (QString prefix, d->contentsPrefixPaths) {
285  list << d->entryList(prefix, p);
286  }
287  }
288 
289  return list;
290 }
291 
292 QStringList PackageStructurePrivate::entryList(const QString &prefix, const QString &requestedPath)
293 {
294  QDir dir(path + prefix + requestedPath);
295 
296  if (externalPaths) {
297  return dir.entryList(QDir::Files | QDir::Readable);
298  }
299 
300  // ensure that we don't return files outside of our base path
301  // due to symlink or ../ games
302  QString canonicalized = dir.canonicalPath();
303  if (canonicalized.startsWith(path)) {
304  return dir.entryList(QDir::Files | QDir::Readable);
305  }
306 
307  return QStringList();
308 }
309 
310 void PackageStructure::addDirectoryDefinition(const char *key,
311  const QString &path, const QString &name)
312 {
313  ContentStructure s;
314 
315  if (d->contents.contains(key)) {
316  s = d->contents[key];
317  }
318 
319  if (!name.isEmpty()) {
320  s.name = name;
321  }
322 
323  s.paths.append(path);
324  s.directory = true;
325 
326  d->contents[key] = s;
327 }
328 
329 void PackageStructure::addFileDefinition(const char *key, const QString &path, const QString &name)
330 {
331  ContentStructure s;
332 
333  if (d->contents.contains(key)) {
334  s = d->contents[key];
335  }
336 
337  if (!name.isEmpty()) {
338  s.name = name;
339  }
340 
341  s.paths.append(path);
342  s.directory = false;
343 
344  d->contents[key] = s;
345 }
346 
347 void PackageStructure::removeDefinition(const char *key)
348 {
349  d->contents.remove(key);
350 }
351 
352 QString PackageStructure::path(const char *key) const
353 {
354  //kDebug() << "looking for" << key;
355  QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
356  if (it == d->contents.constEnd()) {
357  return QString();
358  }
359 
360  //kDebug() << "found" << key << "and the value is" << it.value().paths.first();
361  return it.value().paths.first();
362 }
363 
364 QStringList PackageStructure::searchPath(const char *key) const
365 {
366  //kDebug() << "looking for" << key;
367  QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
368  if (it == d->contents.constEnd()) {
369  return QStringList();
370  }
371 
372  //kDebug() << "found" << key << "and the value is" << it.value().paths;
373  return it.value().paths;
374 }
375 
376 QString PackageStructure::name(const char *key) const
377 {
378  QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
379  if (it == d->contents.constEnd()) {
380  return QString();
381  }
382 
383  return it.value().name;
384 }
385 
386 void PackageStructure::setRequired(const char *key, bool required)
387 {
388  QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
389  if (it == d->contents.end()) {
390  return;
391  }
392 
393  it.value().required = required;
394 }
395 
396 bool PackageStructure::isRequired(const char *key) const
397 {
398  QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
399  if (it == d->contents.constEnd()) {
400  return false;
401  }
402 
403  return it.value().required;
404 }
405 
406 void PackageStructure::setDefaultMimetypes(QStringList mimetypes)
407 {
408  d->mimetypes = mimetypes;
409 }
410 
411 void PackageStructure::setMimetypes(const char *key, QStringList mimetypes)
412 {
413  QMap<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
414  if (it == d->contents.end()) {
415  return;
416  }
417 
418  it.value().mimetypes = mimetypes;
419 }
420 
421 QStringList PackageStructure::mimetypes(const char *key) const
422 {
423  QMap<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
424  if (it == d->contents.constEnd()) {
425  return QStringList();
426  }
427 
428  if (it.value().mimetypes.isEmpty()) {
429  return d->mimetypes;
430  }
431 
432  return it.value().mimetypes;
433 }
434 
435 void PackageStructure::setPath(const QString &path)
436 {
437  KUrl url(path);
438  QDir dir(url.toLocalFile());
439  QString basePath = dir.canonicalPath();
440  bool valid = QFile::exists(basePath);
441 
442  if (valid) {
443  QFileInfo info(basePath);
444  if (info.isDir() && !basePath.endsWith('/')) {
445  basePath.append('/');
446  }
447  //kDebug() << "basePath is" << basePath;
448  } else {
449  kDebug() << path << "invalid, basePath is" << basePath;
450  return;
451  }
452 
453  if (d->path == basePath) {
454  return;
455  }
456 
457  d->path = basePath;
458  delete d->metadata;
459  d->metadata = 0;
460  pathChanged();
461 }
462 
463 QString PackageStructure::path() const
464 {
465  return d->path;
466 }
467 
468 void PackageStructure::pathChanged()
469 {
470  // default impl does nothing, this is a hook for subclasses.
471 }
472 
473 void PackageStructure::read(const KConfigBase *config)
474 {
475  d->contents.clear();
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);
482 
483  QStringList groups = config->groupList();
484  foreach (const QString &group, groups) {
485  KConfigGroup entry(config, group);
486  QByteArray key = group.toAscii();
487 
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);
493 
494  if (directory) {
495  addDirectoryDefinition(key, path, name);
496  } else {
497  addFileDefinition(key, path, name);
498  }
499 
500  setMimetypes(key, mimetypes);
501  setRequired(key, required);
502  }
503 }
504 
505 void PackageStructure::write(KConfigBase *config) const
506 {
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);
512 
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);
520  }
521  if (it.value().directory) {
522  group.writeEntry("Directory", true);
523  }
524  if (it.value().required) {
525  group.writeEntry("Required", true);
526  }
527 
528  ++it;
529  }
530 }
531 
532 QString PackageStructure::contentsPrefix() const
533 {
534  return d->contentsPrefixPaths.isEmpty() ? QString() : d->contentsPrefixPaths.first();
535 }
536 
537 void PackageStructure::setContentsPrefix(const QString &prefix)
538 {
539  d->contentsPrefixPaths.clear();
540  d->contentsPrefixPaths << prefix;
541 }
542 
543 QStringList PackageStructure::contentsPrefixPaths() const
544 {
545  return d->contentsPrefixPaths;
546 }
547 
548 void PackageStructure::setContentsPrefixPaths(const QStringList &prefixPaths)
549 {
550  d->contentsPrefixPaths = prefixPaths;
551 }
552 
553 bool PackageStructure::installPackage(const QString &package, const QString &packageRoot)
554 {
555  return Package::installPackage(package, packageRoot, d->servicePrefix);
556 }
557 
558 bool PackageStructure::uninstallPackage(const QString &packageName, const QString &packageRoot)
559 {
560  return Package::uninstallPackage(packageName, packageRoot, d->servicePrefix);
561 }
562 
563 void PackageStructure::createNewWidgetBrowser(QWidget *parent)
564 {
565  Q_UNUSED(parent)
566  emit newWidgetBrowserFinished();
567 }
568 
569 QString PackageStructure::defaultPackageRoot() const
570 {
571  return d->packageRoot;
572 }
573 
574 QString PackageStructure::servicePrefix() const
575 {
576  return d->servicePrefix;
577 }
578 
579 void PackageStructure::setDefaultPackageRoot(const QString &packageRoot)
580 {
581  d->packageRoot = packageRoot;
582 }
583 
584 void PackageStructure::setServicePrefix(const QString &servicePrefix)
585 {
586  d->servicePrefix = servicePrefix;
587 }
588 
589 void PackageStructurePrivate::createPackageMetadata(const QString &path)
590 {
591  delete metadata;
592  metadata = 0;
593 
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();
598  }
599 
600  metadata = new PackageMetadata(metadataPath);
601 }
602 
603 //FIXME KDE5: should be const
604 PackageMetadata PackageStructure::metadata()
605 {
606  if (!d->metadata && !d->path.isEmpty()) {
607  QFileInfo fileInfo(d->path);
608 
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);
614 
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);
620  } else {
621  kWarning() << "Could not open package file, unsupported archive format:" << d->path << mimetype->name();
622  }
623 
624  if (archive && archive->open(QIODevice::ReadOnly)) {
625  const KArchiveDirectory *source = archive->directory();
626  KTempDir tempdir;
627  source->copyTo(tempdir.name());
628  d->createPackageMetadata(tempdir.name());
629  } else {
630  kWarning() << "Could not open package file:" << d->path;
631  }
632 
633  delete archive;
634  }
635  }
636 
637  if (!d->metadata) {
638  d->metadata = new PackageMetadata();
639  }
640 
641  return *d->metadata;
642 }
643 
644 bool PackageStructure::allowExternalPaths() const
645 {
646  return d->externalPaths;
647 }
648 
649 void PackageStructure::setAllowExternalPaths(bool allow)
650 {
651  d->externalPaths = allow;
652 }
653 
654 } // Plasma namespace
655 
656 #include "packagestructure.moc"
657 
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Thu Feb 21 2013 11:04:19 by doxygen 1.8.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.8.5 API Reference

Skip menu "kdelibs-4.8.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal