Merge "migrate to KPackage"
This commit is contained in:
commit
dd866b427e
@ -59,6 +59,7 @@ find_package(KF5Service ${KF5_DEP_VERSION} REQUIRED)
|
|||||||
find_package(KF5WindowSystem ${KF5_DEP_VERSION} REQUIRED)
|
find_package(KF5WindowSystem ${KF5_DEP_VERSION} REQUIRED)
|
||||||
find_package(KF5XmlGui ${KF5_DEP_VERSION} REQUIRED)
|
find_package(KF5XmlGui ${KF5_DEP_VERSION} REQUIRED)
|
||||||
find_package(KF5Notifications ${KF5_DEP_VERSION} REQUIRED)
|
find_package(KF5Notifications ${KF5_DEP_VERSION} REQUIRED)
|
||||||
|
find_package(KF5Package ${KF5_DEP_VERSION} REQUIRED)
|
||||||
|
|
||||||
find_package(KF5DocTools ${KF5_DEP_VERSION})
|
find_package(KF5DocTools ${KF5_DEP_VERSION})
|
||||||
set_package_properties(KF5DocTools PROPERTIES DESCRIPTION "Tools to generate documentation"
|
set_package_properties(KF5DocTools PROPERTIES DESCRIPTION "Tools to generate documentation"
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/KF5PlasmaTargets.cmake")
|
include("${CMAKE_CURRENT_LIST_DIR}/KF5PlasmaTargets.cmake")
|
||||||
|
|
||||||
|
find_dependency(KF5Package "@KF5_DEP_VERSION@")
|
||||||
|
|
||||||
set(Plasma_INSTALL_PREFIX "@PACKAGE_CMAKE_INSTALL_PREFIX@")
|
set(Plasma_INSTALL_PREFIX "@PACKAGE_CMAKE_INSTALL_PREFIX@")
|
||||||
set_and_check(Plasma_INCLUDE_DIR "@PACKAGE_KF5_INCLUDE_INSTALL_DIR@")
|
set_and_check(Plasma_INCLUDE_DIR "@PACKAGE_KF5_INCLUDE_INSTALL_DIR@")
|
||||||
|
|
||||||
|
@ -66,8 +66,6 @@ set(Plasma_LIB_SRCS
|
|||||||
#packages
|
#packages
|
||||||
package.cpp
|
package.cpp
|
||||||
packagestructure.cpp
|
packagestructure.cpp
|
||||||
private/packagejob.cpp
|
|
||||||
private/packagejobthread.cpp
|
|
||||||
private/packages.cpp
|
private/packages.cpp
|
||||||
|
|
||||||
#graphics
|
#graphics
|
||||||
@ -112,6 +110,7 @@ target_link_libraries(KF5Plasma
|
|||||||
PUBLIC
|
PUBLIC
|
||||||
KF5::Service # For kplugininfo.h and kservice.h
|
KF5::Service # For kplugininfo.h and kservice.h
|
||||||
Qt5::Gui
|
Qt5::Gui
|
||||||
|
KF5::Package
|
||||||
PRIVATE
|
PRIVATE
|
||||||
Qt5::Sql
|
Qt5::Sql
|
||||||
Qt5::Svg
|
Qt5::Svg
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
|
|
||||||
#include "private/associatedapplicationmanager_p.h"
|
#include "private/associatedapplicationmanager_p.h"
|
||||||
#include "private/containment_p.h"
|
#include "private/containment_p.h"
|
||||||
|
#include "private/package_p.h"
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
@ -287,7 +288,16 @@ KConfigLoader *Applet::configScheme() const
|
|||||||
|
|
||||||
Package Applet::package() const
|
Package Applet::package() const
|
||||||
{
|
{
|
||||||
return d->package ? *d->package : Package();
|
Package p;
|
||||||
|
if (d->package) {
|
||||||
|
p.d->internalPackage = new KPackage::Package(*d->package);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
KPackage::Package Applet::kPackage() const
|
||||||
|
{
|
||||||
|
return d->package ? *d->package : KPackage::Package();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Applet::updateConstraints(Plasma::Types::Constraints constraints)
|
void Applet::updateConstraints(Plasma::Types::Constraints constraints)
|
||||||
|
@ -33,6 +33,8 @@
|
|||||||
#include <plasma/version.h>
|
#include <plasma/version.h>
|
||||||
#include <plasma/framesvg.h>
|
#include <plasma/framesvg.h>
|
||||||
|
|
||||||
|
#include <KPackage/Package>
|
||||||
|
|
||||||
class KActionCollection;
|
class KActionCollection;
|
||||||
class KConfigLoader;
|
class KConfigLoader;
|
||||||
|
|
||||||
@ -224,13 +226,26 @@ public:
|
|||||||
void setUserConfiguring(bool configuring);
|
void setUserConfiguring(bool configuring);
|
||||||
|
|
||||||
//UTILS
|
//UTILS
|
||||||
|
#ifndef PLASMA_NO_DEPRECATED
|
||||||
|
/**
|
||||||
|
* Accessor for the associated Package object if any.
|
||||||
|
* Generally, only Plasmoids come in a Package.
|
||||||
|
* Deprecated: please use kPackage()
|
||||||
|
*
|
||||||
|
* @deprecated use kPackage() instead
|
||||||
|
* @return the Package object, or an invalid one if none
|
||||||
|
**/
|
||||||
|
PLASMA_DEPRECATED Package package() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accessor for the associated Package object if any.
|
* Accessor for the associated Package object if any.
|
||||||
* Generally, only Plasmoids come in a Package.
|
* Generally, only Plasmoids come in a Package.
|
||||||
*
|
*
|
||||||
* @return the Package object, or an invalid one if none
|
* @return the Package object, or an invalid one if none
|
||||||
|
* @since 5.6
|
||||||
**/
|
**/
|
||||||
Package package() const;
|
KPackage::Package kPackage() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when any of the geometry constraints have been updated.
|
* Called when any of the geometry constraints have been updated.
|
||||||
|
@ -38,8 +38,10 @@
|
|||||||
|
|
||||||
#include "containment.h"
|
#include "containment.h"
|
||||||
#include "pluginloader.h"
|
#include "pluginloader.h"
|
||||||
|
#include "packagestructure.h"
|
||||||
#include "private/applet_p.h"
|
#include "private/applet_p.h"
|
||||||
#include "private/containment_p.h"
|
#include "private/containment_p.h"
|
||||||
|
#include "private/package_p.h"
|
||||||
#include "private/timetracker.h"
|
#include "private/timetracker.h"
|
||||||
|
|
||||||
using namespace Plasma;
|
using namespace Plasma;
|
||||||
@ -71,15 +73,28 @@ Corona::~Corona()
|
|||||||
|
|
||||||
Plasma::Package Corona::package() const
|
Plasma::Package Corona::package() const
|
||||||
{
|
{
|
||||||
return d->package;
|
Package p;
|
||||||
|
p.d->internalPackage = new KPackage::Package(d->package);
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Corona::setPackage(const Plasma::Package &package)
|
void Corona::setPackage(const Plasma::Package &package)
|
||||||
{
|
{
|
||||||
d->package = package;
|
setKPackage(*package.d->internalPackage);
|
||||||
emit packageChanged(package);
|
emit packageChanged(package);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KPackage::Package Corona::kPackage() const
|
||||||
|
{
|
||||||
|
return d->package;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Corona::setKPackage(const KPackage::Package &package)
|
||||||
|
{
|
||||||
|
d->package = package;
|
||||||
|
emit kPackageChanged(package);
|
||||||
|
}
|
||||||
|
|
||||||
void Corona::saveLayout(const QString &configName) const
|
void Corona::saveLayout(const QString &configName) const
|
||||||
{
|
{
|
||||||
KSharedConfigPtr c;
|
KSharedConfigPtr c;
|
||||||
|
@ -43,11 +43,33 @@ class PLASMA_EXPORT Corona : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool isStartupCompleted READ isStartupCompleted NOTIFY startupCompleted)
|
Q_PROPERTY(bool isStartupCompleted READ isStartupCompleted NOTIFY startupCompleted)
|
||||||
Q_PROPERTY(Package package READ package NOTIFY packageChanged)
|
Q_PROPERTY(Package package READ package NOTIFY packageChanged)
|
||||||
|
Q_PROPERTY(KPackage::Package kPackage READ kPackage NOTIFY kPackageChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Corona(QObject *parent = 0);
|
explicit Corona(QObject *parent = 0);
|
||||||
~Corona();
|
~Corona();
|
||||||
|
|
||||||
|
#ifndef PLASMA_NO_DEPRECATED
|
||||||
|
/**
|
||||||
|
* Accessor for the associated Package object if any.
|
||||||
|
* A Corona package defines how Containments are laid out in a View,
|
||||||
|
* ToolBoxes, default layout, error messages
|
||||||
|
* and in genelal all the furniture specific of a particular
|
||||||
|
* device form factor.
|
||||||
|
*
|
||||||
|
* @deprecated use kPackage instead
|
||||||
|
* @return the Package object, or an invalid one if none
|
||||||
|
* @since 5.0
|
||||||
|
**/
|
||||||
|
PLASMA_DEPRECATED Plasma::Package package() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setting the package name
|
||||||
|
* @deprecated use setKPackage instead
|
||||||
|
*/
|
||||||
|
PLASMA_DEPRECATED void setPackage(const Plasma::Package &package);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accessor for the associated Package object if any.
|
* Accessor for the associated Package object if any.
|
||||||
* A Corona package defines how Containments are laid out in a View,
|
* A Corona package defines how Containments are laid out in a View,
|
||||||
@ -56,14 +78,15 @@ public:
|
|||||||
* device form factor.
|
* device form factor.
|
||||||
*
|
*
|
||||||
* @return the Package object, or an invalid one if none
|
* @return the Package object, or an invalid one if none
|
||||||
* @since 5.0
|
* @since 5.5
|
||||||
**/
|
**/
|
||||||
Plasma::Package package() const;
|
KPackage::Package kPackage() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setting the package name
|
* Setting the package for the corona
|
||||||
|
* @since 5.5
|
||||||
*/
|
*/
|
||||||
void setPackage(const Plasma::Package &package);
|
void setKPackage(const KPackage::Package &package);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return all containments on this Corona
|
* @return all containments on this Corona
|
||||||
@ -278,13 +301,24 @@ Q_SIGNALS:
|
|||||||
*/
|
*/
|
||||||
void immutabilityChanged(Plasma::Types::ImmutabilityType immutability);
|
void immutabilityChanged(Plasma::Types::ImmutabilityType immutability);
|
||||||
|
|
||||||
|
#ifndef PLASMA_NO_DEPRECATED
|
||||||
|
/**
|
||||||
|
* Emitted when the package for this corona has been changed.
|
||||||
|
* Shells must support changing the shell package on the fly (for instance due to device form factor changing)
|
||||||
|
*
|
||||||
|
* @deprecated use kPackageChanged instead
|
||||||
|
* @param package the new package that defines the Corona furniture and behavior
|
||||||
|
*/
|
||||||
|
PLASMA_DEPRECATED void packageChanged(const Plasma::Package &package);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emitted when the package for this corona has been changed.
|
* Emitted when the package for this corona has been changed.
|
||||||
* Shells must support changing the shell package on the fly (for instance due to device form factor changing)
|
* Shells must support changing the shell package on the fly (for instance due to device form factor changing)
|
||||||
*
|
*
|
||||||
* @param package the new package that defines the Corona furniture and behavior
|
* @param package the new package that defines the Corona furniture and behavior
|
||||||
*/
|
*/
|
||||||
void packageChanged(const Plasma::Package &package);
|
void kPackageChanged(const KPackage::Package &package);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emitted when the startup phase has been completed
|
* Emitted when the startup phase has been completed
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <kservicetypetrader.h>
|
#include <kservicetypetrader.h>
|
||||||
#include <ktar.h>
|
#include <ktar.h>
|
||||||
#include <kzip.h>
|
#include <kzip.h>
|
||||||
|
#include <KJob>
|
||||||
|
|
||||||
#include "config-plasma.h"
|
#include "config-plasma.h"
|
||||||
|
|
||||||
@ -39,35 +40,64 @@
|
|||||||
#include "packagestructure.h"
|
#include "packagestructure.h"
|
||||||
#include "pluginloader.h"
|
#include "pluginloader.h"
|
||||||
#include "private/package_p.h"
|
#include "private/package_p.h"
|
||||||
|
#include "private/packagestructure_p.h"
|
||||||
#include "private/packages_p.h"
|
#include "private/packages_p.h"
|
||||||
#include "private/packagejob_p.h"
|
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
PackagePrivate::PackagePrivate()
|
||||||
|
: internalPackage(0),
|
||||||
|
fallbackPackage(0),
|
||||||
|
structure(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PackagePrivate::~PackagePrivate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Package::Package(PackageStructure *structure)
|
Package::Package(PackageStructure *structure)
|
||||||
: d(new PackagePrivate())
|
: d(new Plasma::PackagePrivate())
|
||||||
{
|
{
|
||||||
d->structure = structure;
|
d->structure = structure;
|
||||||
|
|
||||||
if (d->structure) {
|
if (!structure) {
|
||||||
d->structure.data()->initPackage(this);
|
d->internalPackage = new KPackage::Package();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!structure->d->internalStructure) {
|
||||||
|
d->structure->d->internalStructure = new KPackage::PackageStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->internalPackage = new KPackage::Package(structure->d->internalStructure);
|
||||||
|
PackageStructureWrapper::s_packagesMap[d->internalPackage] = this;
|
||||||
|
structure->initPackage(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Package::Package(const Package &other)
|
Package::Package(const Package &other)
|
||||||
: d(other.d)
|
: d(new Plasma::PackagePrivate())
|
||||||
{
|
{
|
||||||
|
d->internalPackage = new KPackage::Package(*other.d->internalPackage);
|
||||||
|
d->structure = other.d->structure;
|
||||||
|
PackageStructureWrapper::s_packagesMap[d->internalPackage] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Package::~Package()
|
Package::~Package()
|
||||||
{
|
{
|
||||||
|
PackageStructureWrapper::s_packagesMap.remove(d->internalPackage);
|
||||||
|
delete d->internalPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
Package &Package::operator=(const Package &rhs)
|
Package &Package::operator=(const Package &rhs)
|
||||||
{
|
{
|
||||||
if (&rhs != this) {
|
if (&rhs != this) {
|
||||||
d = rhs.d;
|
d->internalPackage = new KPackage::Package(*rhs.d->internalPackage);
|
||||||
|
d->structure = rhs.d->structure;
|
||||||
|
PackageStructureWrapper::s_packagesMap[d->internalPackage] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@ -75,130 +105,43 @@ Package &Package::operator=(const Package &rhs)
|
|||||||
|
|
||||||
bool Package::hasValidStructure() const
|
bool Package::hasValidStructure() const
|
||||||
{
|
{
|
||||||
return d->structure;
|
return d->internalPackage->hasValidStructure();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Package::isValid() const
|
bool Package::isValid() const
|
||||||
{
|
{
|
||||||
if (!d->structure) {
|
return d->internalPackage->isValid();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Minimal packages with no metadata *are* supposed to be possible
|
|
||||||
//so if !metadata().isValid() go ahead
|
|
||||||
if (metadata().isValid() && metadata().isHidden()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->checkedValid) {
|
|
||||||
return d->valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->valid = true;
|
|
||||||
|
|
||||||
//search for the file in all prefixes and in all possible paths for each prefix
|
|
||||||
//even if it's a big nested loop, usually there is one prefix and one location
|
|
||||||
//so shouldn't cause too much disk access
|
|
||||||
QHashIterator<QByteArray, ContentStructure> it(d->contents);
|
|
||||||
const QString rootPath = d->tempRoot.isEmpty() ? d->path : d->tempRoot;
|
|
||||||
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
if (!it.value().required) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool failed = true;
|
|
||||||
foreach (const QString &path, it.value().paths) {
|
|
||||||
foreach (const QString &prefix, d->contentsPrefixPaths) {
|
|
||||||
if (QFile::exists(rootPath + prefix + path)) {
|
|
||||||
failed = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!failed) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failed) {
|
|
||||||
//qWarning() << "Could not find required" << (it.value().directory ? "directory" : "file") << it.key() << "for package" << path();
|
|
||||||
d->valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d->valid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Package::name(const char *key) const
|
QString Package::name(const char *key) const
|
||||||
{
|
{
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
return d->internalPackage->name(key);
|
||||||
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
|
|
||||||
if (it == d->contents.constEnd()) {
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return it.value().name;
|
|
||||||
#else
|
|
||||||
Q_UNUSED(key);
|
|
||||||
return QString();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Package::isRequired(const char *key) const
|
bool Package::isRequired(const char *key) const
|
||||||
{
|
{
|
||||||
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
|
return d->internalPackage->isRequired(key);
|
||||||
if (it == d->contents.constEnd()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return it.value().required;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Package::mimeTypes(const char *key) const
|
QStringList Package::mimeTypes(const char *key) const
|
||||||
{
|
{
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
return d->internalPackage->mimeTypes(key);
|
||||||
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
|
|
||||||
if (it == d->contents.constEnd()) {
|
|
||||||
return QStringList();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it.value().mimeTypes.isEmpty()) {
|
|
||||||
return d->mimeTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return it.value().mimeTypes;
|
|
||||||
#else
|
|
||||||
return QStringList();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Package::defaultPackageRoot() const
|
QString Package::defaultPackageRoot() const
|
||||||
{
|
{
|
||||||
return d->defaultPackageRoot;
|
return d->internalPackage->defaultPackageRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::setDefaultPackageRoot(const QString &packageRoot)
|
void Package::setDefaultPackageRoot(const QString &packageRoot)
|
||||||
{
|
{
|
||||||
d.detach();
|
d->internalPackage->setDefaultPackageRoot(packageRoot);
|
||||||
d->defaultPackageRoot = packageRoot;
|
|
||||||
if (!d->defaultPackageRoot.isEmpty() && !d->defaultPackageRoot.endsWith('/')) {
|
|
||||||
d->defaultPackageRoot.append('/');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::setFallbackPackage(const Plasma::Package &package)
|
void Package::setFallbackPackage(const Plasma::Package &package)
|
||||||
{
|
{
|
||||||
if ((d->fallbackPackage && d->fallbackPackage->path() == package.path() && d->fallbackPackage->metadata() == package.metadata()) ||
|
|
||||||
//can't be fallback of itself
|
|
||||||
(package.path() == path() && package.metadata() == metadata()) ||
|
|
||||||
d->hasCycle(package)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->fallbackPackage = new Package(package);
|
d->fallbackPackage = new Package(package);
|
||||||
|
d->internalPackage->setFallbackPackage(*package.d->internalPackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Plasma::Package Package::fallbackPackage() const
|
Plasma::Package Package::fallbackPackage() const
|
||||||
@ -217,553 +160,128 @@ QString Package::servicePrefix() const
|
|||||||
|
|
||||||
void Package::setServicePrefix(const QString &servicePrefix)
|
void Package::setServicePrefix(const QString &servicePrefix)
|
||||||
{
|
{
|
||||||
d.detach();
|
|
||||||
d->servicePrefix = servicePrefix;
|
d->servicePrefix = servicePrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Package::allowExternalPaths() const
|
bool Package::allowExternalPaths() const
|
||||||
{
|
{
|
||||||
return d->externalPaths;
|
return d->internalPackage->allowExternalPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::setAllowExternalPaths(bool allow)
|
void Package::setAllowExternalPaths(bool allow)
|
||||||
{
|
{
|
||||||
d.detach();
|
d->internalPackage->setAllowExternalPaths(allow);
|
||||||
d->externalPaths = allow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KPluginInfo Package::metadata() const
|
KPluginInfo Package::metadata() const
|
||||||
{
|
{
|
||||||
//qDebug() << "metadata: " << d->path << filePath("metadata");
|
return KPluginInfo::fromMetaData(d->internalPackage->metadata());
|
||||||
if (!d->metadata && !d->path.isEmpty()) {
|
|
||||||
const QString metadataPath = filePath("metadata");
|
|
||||||
if (!metadataPath.isEmpty()) {
|
|
||||||
d->createPackageMetadata(metadataPath);
|
|
||||||
} else {
|
|
||||||
// d->path might still be a file, if its path has a trailing /,
|
|
||||||
// the fileInfo lookup will fail, so remove it.
|
|
||||||
QString p = d->path;
|
|
||||||
if (p.endsWith("/")) {
|
|
||||||
p.chop(1);
|
|
||||||
}
|
|
||||||
QFileInfo fileInfo(p);
|
|
||||||
|
|
||||||
if (fileInfo.isDir()) {
|
|
||||||
d->createPackageMetadata(d->path);
|
|
||||||
} else if (fileInfo.exists()) {
|
|
||||||
d->path = p;
|
|
||||||
d->tempRoot = d->unpack(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!d->metadata) {
|
|
||||||
d->metadata = new KPluginInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *d->metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString PackagePrivate::unpack(const QString &filePath)
|
|
||||||
{
|
|
||||||
KArchive *archive = 0;
|
|
||||||
QMimeDatabase db;
|
|
||||||
QMimeType mimeType = db.mimeTypeForFile(filePath);
|
|
||||||
|
|
||||||
if (mimeType.inherits("application/zip")) {
|
|
||||||
archive = new KZip(filePath);
|
|
||||||
} else if (mimeType.inherits("application/x-compressed-tar") || mimeType.inherits("application/x-gzip") ||
|
|
||||||
mimeType.inherits("application/x-tar") || mimeType.inherits("application/x-bzip-compressed-tar") ||
|
|
||||||
mimeType.inherits("application/x-xz") || mimeType.inherits("application/x-lzma")) {
|
|
||||||
archive = new KTar(filePath);
|
|
||||||
} else {
|
|
||||||
//qWarning() << "Could not open package file, unsupported archive format:" << filePath << mimeType.name();
|
|
||||||
}
|
|
||||||
QString tempRoot;
|
|
||||||
if (archive && archive->open(QIODevice::ReadOnly)) {
|
|
||||||
const KArchiveDirectory *source = archive->directory();
|
|
||||||
QTemporaryDir tempdir;
|
|
||||||
tempdir.setAutoRemove(false);
|
|
||||||
tempRoot = tempdir.path() + '/';
|
|
||||||
source->copyTo(tempRoot);
|
|
||||||
|
|
||||||
if (!QFile::exists(tempdir.path() + "/metadata.desktop")) {
|
|
||||||
// search metadata.desktop, the zip file might have the package contents in a subdirectory
|
|
||||||
QDir unpackedPath(tempdir.path());
|
|
||||||
const QStringList &entries = unpackedPath.entryList(QDir::Dirs);
|
|
||||||
foreach (const QString &pack, entries) {
|
|
||||||
if ((pack != "." && pack != "..") &&
|
|
||||||
(QFile::exists(unpackedPath.absolutePath() + '/' + pack + "/metadata.desktop"))) {
|
|
||||||
tempRoot = unpackedPath.absolutePath() + '/' + pack + '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createPackageMetadata(tempRoot);
|
|
||||||
} else {
|
|
||||||
//qWarning() << "Could not open package file:" << path;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete archive;
|
|
||||||
return tempRoot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Package::filePath(const char *fileType, const QString &filename) const
|
QString Package::filePath(const char *fileType, const QString &filename) const
|
||||||
{
|
{
|
||||||
if (!d->valid) {
|
return d->internalPackage->filePath(fileType, filename);
|
||||||
//qDebug() << "package is not valid";
|
|
||||||
return d->fallbackFilePath(fileType, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString discoveryKey(fileType + filename);
|
|
||||||
if (d->discoveries.contains(discoveryKey)) {
|
|
||||||
//qDebug() << "looking for" << discoveryKey << d->discoveries.value(discoveryKey);
|
|
||||||
return d->discoveries[discoveryKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList paths;
|
|
||||||
|
|
||||||
if (qstrlen(fileType) != 0) {
|
|
||||||
//qDebug()<<d->contents.keys();
|
|
||||||
if (!d->contents.contains(fileType)) {
|
|
||||||
//qDebug() << "package does not contain" << fileType << filename;
|
|
||||||
return d->fallbackFilePath(fileType, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
paths = d->contents[fileType].paths;
|
|
||||||
|
|
||||||
if (paths.isEmpty()) {
|
|
||||||
//qDebug() << "no matching path came of it, while looking for" << fileType << filename;
|
|
||||||
d->discoveries.insert(discoveryKey, QString());
|
|
||||||
return d->fallbackFilePath(fileType, filename);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//when filetype is empty paths is always empty, so try with an empty string
|
|
||||||
paths << QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Nested loop, but in the medium case resolves to just one iteration
|
|
||||||
//qDebug() << "prefixes:" << prefixes.count() << prefixes;
|
|
||||||
foreach (const QString &contentsPrefix, d->contentsPrefixPaths) {
|
|
||||||
const QString prefix(d->path + contentsPrefix);
|
|
||||||
|
|
||||||
foreach (const QString &path, paths) {
|
|
||||||
QString file = prefix + path;
|
|
||||||
|
|
||||||
if (!filename.isEmpty()) {
|
|
||||||
file.append("/").append(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
//qDebug() << "testing" << file << QFile::exists("/bin/ls") << QFile::exists(file);
|
|
||||||
if (QFile::exists(file)) {
|
|
||||||
if (d->externalPaths) {
|
|
||||||
//qDebug() << "found" << file;
|
|
||||||
d->discoveries.insert(discoveryKey, file);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure that we don't return files outside of our base path
|
|
||||||
// due to symlink or ../ games
|
|
||||||
QDir dir(file);
|
|
||||||
QString canonicalized = dir.canonicalPath() + QDir::separator();
|
|
||||||
|
|
||||||
//qDebug() << "testing that" << canonicalized << "is in" << d->path;
|
|
||||||
if (canonicalized.startsWith(d->path)) {
|
|
||||||
//qDebug() << "found" << file;
|
|
||||||
d->discoveries.insert(discoveryKey, file);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//qDebug() << fileType << filename << "does not exist in" << prefixes << "at root" << d->path;
|
|
||||||
return d->fallbackFilePath(fileType, filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Package::entryList(const char *key) const
|
QStringList Package::entryList(const char *key) const
|
||||||
{
|
{
|
||||||
if (!d->valid) {
|
return d->internalPackage->entryList(key);
|
||||||
return QStringList();
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constFind(key);
|
|
||||||
if (it == d->contents.constEnd()) {
|
|
||||||
//qDebug() << "couldn't find" << key;
|
|
||||||
return QStringList();
|
|
||||||
}
|
|
||||||
|
|
||||||
//qDebug() << "going to list" << key;
|
|
||||||
QStringList list;
|
|
||||||
foreach (const QString &prefix, d->contentsPrefixPaths) {
|
|
||||||
//qDebug() << " looking in" << prefix;
|
|
||||||
foreach (const QString &path, it.value().paths) {
|
|
||||||
//qDebug() << " looking in" << path;
|
|
||||||
if (it.value().directory) {
|
|
||||||
//qDebug() << "it's a directory, so trying out" << d->path + prefix + path;
|
|
||||||
QDir dir(d->path + prefix + path);
|
|
||||||
|
|
||||||
if (d->externalPaths) {
|
|
||||||
list += dir.entryList(QDir::Files | QDir::Readable);
|
|
||||||
} else {
|
|
||||||
// ensure that we don't return files outside of our base path
|
|
||||||
// due to symlink or ../ games
|
|
||||||
QString canonicalized = dir.canonicalPath();
|
|
||||||
if (canonicalized.startsWith(d->path)) {
|
|
||||||
list += dir.entryList(QDir::Files | QDir::Readable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const QString fullPath = d->path + prefix + path;
|
|
||||||
//qDebug() << "it's a file at" << fullPath << QFile::exists(fullPath);
|
|
||||||
if (!QFile::exists(fullPath)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->externalPaths) {
|
|
||||||
list += fullPath;
|
|
||||||
} else {
|
|
||||||
QDir dir(fullPath);
|
|
||||||
QString canonicalized = dir.canonicalPath() + QDir::separator();
|
|
||||||
|
|
||||||
//qDebug() << "testing that" << canonicalized << "is in" << d->path;
|
|
||||||
if (canonicalized.startsWith(d->path)) {
|
|
||||||
list += fullPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::setPath(const QString &path)
|
void Package::setPath(const QString &path)
|
||||||
{
|
{
|
||||||
// if the path is already what we have, don't bother
|
if (path == d->internalPackage->path()) {
|
||||||
if (path == d->path) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// our dptr is shared, and it is almost certainly going to change.
|
d->internalPackage->setPath(path);
|
||||||
// hold onto the old pointer just in case it does not, however!
|
|
||||||
QExplicitlySharedDataPointer<PackagePrivate> oldD(d);
|
|
||||||
d.detach();
|
|
||||||
|
|
||||||
// without structure we're doomed
|
|
||||||
if (!d->structure) {
|
|
||||||
d->path.clear();
|
|
||||||
d->discoveries.clear();
|
|
||||||
d->valid = false;
|
|
||||||
d->checkedValid = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// empty path => nothing to do
|
|
||||||
if (path.isEmpty()) {
|
|
||||||
d->path.clear();
|
|
||||||
d->discoveries.clear();
|
|
||||||
d->valid = false;
|
|
||||||
d->structure.data()->pathChanged(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now we look for all possible paths, including resolving
|
|
||||||
// relative paths against the system search paths
|
|
||||||
QStringList paths;
|
|
||||||
if (QDir::isRelativePath(path)) {
|
|
||||||
QString p;
|
|
||||||
|
|
||||||
if (d->defaultPackageRoot.isEmpty()) {
|
|
||||||
p = path % "/";
|
|
||||||
} else {
|
|
||||||
p = d->defaultPackageRoot % path % "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (QDir::isRelativePath(p)) {
|
|
||||||
paths << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, p, QStandardPaths::LocateDirectory);
|
|
||||||
} else {
|
|
||||||
const QDir dir(p);
|
|
||||||
if (QFile::exists(dir.canonicalPath())) {
|
|
||||||
paths << p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//qDebug() << "paths:" << p << paths << d->defaultPackageRoot;
|
|
||||||
} else {
|
|
||||||
const QDir dir(path);
|
|
||||||
if (QFile::exists(dir.canonicalPath())) {
|
|
||||||
paths << path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileInfo fileInfo(path);
|
|
||||||
if (fileInfo.isFile() && d->tempRoot.isEmpty()) {
|
|
||||||
d->path = path;
|
|
||||||
d->tempRoot = d->unpack(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now we search each path found, caching our previous path to know if
|
|
||||||
// anything actually really changed
|
|
||||||
const QString previousPath = d->path;
|
|
||||||
foreach (const QString &p, paths) {
|
|
||||||
d->checkedValid = false;
|
|
||||||
d->path = p;
|
|
||||||
|
|
||||||
if (!d->path.endsWith('/')) {
|
|
||||||
d->path.append('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need to tell the structure we're changing paths ...
|
|
||||||
d->structure.data()->pathChanged(this);
|
|
||||||
// ... and then testing the results for validity
|
|
||||||
if (isValid()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// if nothing did change, then we go back to the old dptr
|
|
||||||
if (d->path == previousPath) {
|
|
||||||
d = oldD;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// .. but something did change, so we get rid of our discovery cache
|
|
||||||
d->discoveries.clear();
|
|
||||||
delete d->metadata;
|
|
||||||
d->metadata = 0;
|
|
||||||
|
|
||||||
QString fallback;
|
|
||||||
|
|
||||||
// uh-oh, but we didn't end up with anything valid, so we sadly reset ourselves
|
|
||||||
// to futility.
|
|
||||||
if (!d->valid) {
|
|
||||||
d->path.clear();
|
|
||||||
d->structure.data()->pathChanged(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString Package::path() const
|
const QString Package::path() const
|
||||||
{
|
{
|
||||||
return d->path;
|
return d->internalPackage->path();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Package::contentsPrefixPaths() const
|
QStringList Package::contentsPrefixPaths() const
|
||||||
{
|
{
|
||||||
return d->contentsPrefixPaths;
|
return d->internalPackage->contentsPrefixPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::setContentsPrefixPaths(const QStringList &prefixPaths)
|
void Package::setContentsPrefixPaths(const QStringList &prefixPaths)
|
||||||
{
|
{
|
||||||
d.detach();
|
d->internalPackage->setContentsPrefixPaths(prefixPaths);
|
||||||
d->contentsPrefixPaths = prefixPaths;
|
|
||||||
if (d->contentsPrefixPaths.isEmpty()) {
|
|
||||||
d->contentsPrefixPaths << QString();
|
|
||||||
} else {
|
|
||||||
// the code assumes that the prefixes have a trailing slash
|
|
||||||
// so let's make that true here
|
|
||||||
QMutableStringListIterator it(d->contentsPrefixPaths);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
|
|
||||||
if (!it.value().endsWith('/')) {
|
|
||||||
it.setValue(it.value() % '/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Package::contentsHash() const
|
QString Package::contentsHash() const
|
||||||
{
|
{
|
||||||
if (!d->valid) {
|
return d->internalPackage->contentsHash();
|
||||||
qWarning() << "can not create hash due to Package being invalid";
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
|
||||||
QString metadataPath = d->path + "metadata.desktop";
|
|
||||||
if (QFile::exists(metadataPath)) {
|
|
||||||
QFile f(metadataPath);
|
|
||||||
if (f.open(QIODevice::ReadOnly)) {
|
|
||||||
while (!f.atEnd()) {
|
|
||||||
hash.addData(f.read(1024));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading.";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qWarning() << "no metadata at" << metadataPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (QString prefix, d->contentsPrefixPaths) {
|
|
||||||
const QString basePath = d->path + prefix;
|
|
||||||
QDir dir(basePath);
|
|
||||||
|
|
||||||
if (!dir.exists()) {
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
d->updateHash(basePath, QString(), dir, hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash.result().toHex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::addDirectoryDefinition(const char *key, const QString &path, const QString &name)
|
void Package::addDirectoryDefinition(const char *key, const QString &path, const QString &name)
|
||||||
{
|
{
|
||||||
ContentStructure s;
|
d->internalPackage->addDirectoryDefinition(key, path, name);
|
||||||
|
|
||||||
if (d->contents.contains(key)) {
|
|
||||||
s = d->contents[key];
|
|
||||||
if (s.paths.contains(path) && s.directory == true
|
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
|
||||||
&& s.name == name
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
d.detach();
|
|
||||||
|
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
|
||||||
if (!name.isEmpty()) {
|
|
||||||
s.name = name;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
Q_UNUSED(name)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
s.paths.append(path);
|
|
||||||
s.directory = true;
|
|
||||||
|
|
||||||
d->contents[key] = s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::addFileDefinition(const char *key, const QString &path, const QString &name)
|
void Package::addFileDefinition(const char *key, const QString &path, const QString &name)
|
||||||
{
|
{
|
||||||
ContentStructure s;
|
d->internalPackage->addFileDefinition(key, path, name);
|
||||||
|
|
||||||
if (d->contents.contains(key)) {
|
|
||||||
s = d->contents[key];
|
|
||||||
if (s.paths.contains(path) && s.directory == false
|
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
|
||||||
&& s.name == name
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
d.detach();
|
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
|
||||||
if (!name.isEmpty()) {
|
|
||||||
s.name = name;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
Q_UNUSED(name)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
s.paths.append(path);
|
|
||||||
s.directory = false;
|
|
||||||
|
|
||||||
d->contents[key] = s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::removeDefinition(const char *key)
|
void Package::removeDefinition(const char *key)
|
||||||
{
|
{
|
||||||
if (d->contents.contains(key)) {
|
d->internalPackage->removeDefinition(key);
|
||||||
d.detach();
|
|
||||||
d->contents.remove(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::setRequired(const char *key, bool required)
|
void Package::setRequired(const char *key, bool required)
|
||||||
{
|
{
|
||||||
QHash<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
|
d->internalPackage->setRequired(key, required);
|
||||||
if (it == d->contents.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d.detach();
|
|
||||||
// have to find the item again after detaching: d->contents is a different object now
|
|
||||||
it = d->contents.find(key);
|
|
||||||
it.value().required = required;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::setDefaultMimeTypes(QStringList mimeTypes)
|
void Package::setDefaultMimeTypes(QStringList mimeTypes)
|
||||||
{
|
{
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
d->internalPackage->setDefaultMimeTypes(mimeTypes);
|
||||||
d.detach();
|
|
||||||
d->mimeTypes = mimeTypes;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::setMimeTypes(const char *key, QStringList mimeTypes)
|
void Package::setMimeTypes(const char *key, QStringList mimeTypes)
|
||||||
{
|
{
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
d->internalPackage->setMimeTypes(key, mimeTypes);
|
||||||
QHash<QByteArray, ContentStructure>::iterator it = d->contents.find(key);
|
|
||||||
if (it == d->contents.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d.detach();
|
|
||||||
// have to find the item again after detaching: d->contents is a different object now
|
|
||||||
it = d->contents.find(key);
|
|
||||||
it.value().mimeTypes = mimeTypes;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<const char *> Package::directories() const
|
QList<const char *> Package::directories() const
|
||||||
{
|
{
|
||||||
QList<const char *> dirs;
|
QList<const char *> dirs;
|
||||||
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
|
for (auto data : d->internalPackage->directories()) {
|
||||||
while (it != d->contents.constEnd()) {
|
dirs << data.constData();
|
||||||
if (it.value().directory) {
|
|
||||||
dirs << it.key();
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dirs;
|
return dirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<const char *> Package::requiredDirectories() const
|
QList<const char *> Package::requiredDirectories() const
|
||||||
{
|
{
|
||||||
QList<const char *> dirs;
|
QList<const char *> dirs;
|
||||||
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
|
for (auto data : d->internalPackage->requiredDirectories()) {
|
||||||
while (it != d->contents.constEnd()) {
|
dirs << data.constData();
|
||||||
if (it.value().directory &&
|
|
||||||
it.value().required) {
|
|
||||||
dirs << it.key();
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dirs;
|
return dirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<const char *> Package::files() const
|
QList<const char *> Package::files() const
|
||||||
{
|
{
|
||||||
QList<const char *> files;
|
QList<const char *> files;
|
||||||
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
|
for (auto data : d->internalPackage->files()) {
|
||||||
while (it != d->contents.constEnd()) {
|
files << data.constData();
|
||||||
if (!it.value().directory) {
|
|
||||||
files << it.key();
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<const char *> Package::requiredFiles() const
|
QList<const char *> Package::requiredFiles() const
|
||||||
{
|
{
|
||||||
QList<const char *> files;
|
QList<const char *> files;
|
||||||
QHash<QByteArray, ContentStructure>::const_iterator it = d->contents.constBegin();
|
for (auto data : d->internalPackage->requiredFiles()) {
|
||||||
while (it != d->contents.constEnd()) {
|
files << data.constData();
|
||||||
if (!it.value().directory && it.value().required) {
|
|
||||||
files << it.key();
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
@ -775,169 +293,15 @@ KJob *Package::install(const QString &sourcePackage, const QString &packageRoot)
|
|||||||
const QString dest = packageRoot.isEmpty() ? defaultPackageRoot() : packageRoot;
|
const QString dest = packageRoot.isEmpty() ? defaultPackageRoot() : packageRoot;
|
||||||
//qDebug() << "Source: " << src;
|
//qDebug() << "Source: " << src;
|
||||||
//qDebug() << "PackageRoot: " << dest;
|
//qDebug() << "PackageRoot: " << dest;
|
||||||
KJob *j = d->structure.data()->install(this, src, dest);
|
KJob *j = d->structure->install(this, src, dest);
|
||||||
//connect(j, SIGNAL(finished(bool)), SLOT(installFinished(bool)));
|
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
KJob *Package::uninstall(const QString &packageName, const QString &packageRoot)
|
KJob *Package::uninstall(const QString &packageName, const QString &packageRoot)
|
||||||
{
|
{
|
||||||
d->createPackageMetadata(packageRoot + packageName);
|
setPath(packageRoot + packageName);
|
||||||
return d->structure.data()->uninstall(this, packageRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
PackagePrivate::PackagePrivate()
|
return d->structure->uninstall(this, packageRoot);
|
||||||
: QSharedData(),
|
|
||||||
servicePrefix("plasma-applet-"),
|
|
||||||
fallbackPackage(0),
|
|
||||||
metadata(0),
|
|
||||||
externalPaths(false),
|
|
||||||
valid(false),
|
|
||||||
checkedValid(false)
|
|
||||||
{
|
|
||||||
contentsPrefixPaths << "contents/";
|
|
||||||
}
|
|
||||||
|
|
||||||
PackagePrivate::PackagePrivate(const PackagePrivate &other)
|
|
||||||
: QSharedData()
|
|
||||||
{
|
|
||||||
*this = other;
|
|
||||||
metadata = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PackagePrivate::~PackagePrivate()
|
|
||||||
{
|
|
||||||
if (!tempRoot.isEmpty()) {
|
|
||||||
QDir dir(tempRoot);
|
|
||||||
dir.removeRecursively();
|
|
||||||
}
|
|
||||||
delete metadata;
|
|
||||||
delete fallbackPackage;
|
|
||||||
}
|
|
||||||
|
|
||||||
PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs)
|
|
||||||
{
|
|
||||||
if (&rhs == this) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
structure = rhs.structure;
|
|
||||||
if (rhs.fallbackPackage) {
|
|
||||||
fallbackPackage = new Package(*rhs.fallbackPackage);
|
|
||||||
} else {
|
|
||||||
fallbackPackage = 0;
|
|
||||||
}
|
|
||||||
path = rhs.path;
|
|
||||||
contentsPrefixPaths = rhs.contentsPrefixPaths;
|
|
||||||
servicePrefix = rhs.servicePrefix;
|
|
||||||
contents = rhs.contents;
|
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
|
||||||
mimeTypes = rhs.mimeTypes;
|
|
||||||
#endif
|
|
||||||
defaultPackageRoot = rhs.defaultPackageRoot;
|
|
||||||
servicePrefix = rhs.servicePrefix;
|
|
||||||
metadata = 0;
|
|
||||||
externalPaths = rhs.externalPaths;
|
|
||||||
valid = rhs.valid;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackagePrivate::updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCryptographicHash &hash)
|
|
||||||
{
|
|
||||||
// hash is calculated as a function of:
|
|
||||||
// * files ordered alphabetically by name, with each file's:
|
|
||||||
// * path relative to the content root
|
|
||||||
// * file data
|
|
||||||
// * directories ordered alphabetically by name, with each dir's:
|
|
||||||
// * path relative to the content root
|
|
||||||
// * file listing (recursing)
|
|
||||||
// symlinks (in both the file and dir case) are handled by adding
|
|
||||||
// the name of the symlink itself and the abs path of what it points to
|
|
||||||
|
|
||||||
const QDir::SortFlags sorting = QDir::Name | QDir::IgnoreCase;
|
|
||||||
const QDir::Filters filters = QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
|
|
||||||
foreach (const QString &file, dir.entryList(QDir::Files | filters, sorting)) {
|
|
||||||
if (!subPath.isEmpty()) {
|
|
||||||
hash.addData(subPath.toUtf8());
|
|
||||||
}
|
|
||||||
|
|
||||||
hash.addData(file.toUtf8());
|
|
||||||
|
|
||||||
QFileInfo info(dir.path() + '/' + file);
|
|
||||||
if (info.isSymLink()) {
|
|
||||||
hash.addData(info.symLinkTarget().toUtf8());
|
|
||||||
} else {
|
|
||||||
QFile f(info.filePath());
|
|
||||||
if (f.open(QIODevice::ReadOnly)) {
|
|
||||||
while (!f.atEnd()) {
|
|
||||||
hash.addData(f.read(1024));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading. "
|
|
||||||
<< "permissions fail?" << info.permissions() << info.isFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const QString &subDirPath, dir.entryList(QDir::Dirs | filters, sorting)) {
|
|
||||||
const QString relativePath = subPath + subDirPath + '/';
|
|
||||||
hash.addData(relativePath.toUtf8());
|
|
||||||
|
|
||||||
QDir subDir(dir.path());
|
|
||||||
subDir.cd(subDirPath);
|
|
||||||
|
|
||||||
if (subDir.path() != subDir.canonicalPath()) {
|
|
||||||
hash.addData(subDir.canonicalPath().toUtf8());
|
|
||||||
} else {
|
|
||||||
updateHash(basePath, relativePath, subDir, hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackagePrivate::createPackageMetadata(const QString &path)
|
|
||||||
{
|
|
||||||
delete metadata;
|
|
||||||
QString metadataPath(path + "/metadata.desktop");
|
|
||||||
if (!QFile::exists(metadataPath)) {
|
|
||||||
qWarning() << "No metadata file in the package, expected it at:" << metadataPath;
|
|
||||||
metadataPath.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata = new KPluginInfo(metadataPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString PackagePrivate::fallbackFilePath(const char *key, const QString &filename) const
|
|
||||||
{
|
|
||||||
//don't fallback if the package isn't valid and never fallback the metadata file
|
|
||||||
if (qstrcmp(key, "metadata") != 0 && fallbackPackage && fallbackPackage->isValid()) {
|
|
||||||
return fallbackPackage->filePath(key, filename);
|
|
||||||
} else {
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PackagePrivate::hasCycle(const Plasma::Package &package)
|
|
||||||
{
|
|
||||||
if (!package.d->fallbackPackage) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//This is the Floyd cycle detection algorithm
|
|
||||||
//http://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare
|
|
||||||
Plasma::Package *slowPackage = const_cast<Plasma::Package *>(&package);
|
|
||||||
Plasma::Package *fastPackage = const_cast<Plasma::Package *>(&package);
|
|
||||||
|
|
||||||
while (fastPackage && fastPackage->d->fallbackPackage) {
|
|
||||||
//consider two packages the same if they have the same metadata
|
|
||||||
if ((fastPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->metadata() == slowPackage->metadata()) ||
|
|
||||||
(fastPackage->d->fallbackPackage->d->fallbackPackage && fastPackage->d->fallbackPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->d->fallbackPackage->metadata() == slowPackage->metadata())) {
|
|
||||||
qWarning() << "Warning: the fallback chain of " << package.metadata().pluginName() << "contains a cyclical dependency.";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
fastPackage = fastPackage->d->fallbackPackage->d->fallbackPackage;
|
|
||||||
slowPackage = slowPackage->d->fallbackPackage;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Namespace
|
} // Namespace
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
class KJob;
|
class KJob;
|
||||||
|
|
||||||
|
#ifndef PLASMA_NO_DEPRECATED
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -37,6 +39,7 @@ namespace Plasma
|
|||||||
*
|
*
|
||||||
* @short object representing an installed Plasma package
|
* @short object representing an installed Plasma package
|
||||||
*
|
*
|
||||||
|
* @deprecated USe KPackage::Package instead
|
||||||
* Package defines what is in a package and provides easy access to the contents.
|
* Package defines what is in a package and provides easy access to the contents.
|
||||||
*
|
*
|
||||||
* To define a package, one might write the following code:
|
* To define a package, one might write the following code:
|
||||||
@ -85,13 +88,13 @@ public:
|
|||||||
* otherwise the structure is allowed to set up the Package's initial layout
|
* otherwise the structure is allowed to set up the Package's initial layout
|
||||||
* @since 4.6
|
* @since 4.6
|
||||||
*/
|
*/
|
||||||
explicit Package(PackageStructure *structure = 0);
|
PLASMA_DEPRECATED explicit Package(PackageStructure *structure = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy constructore
|
* Copy constructore
|
||||||
* @since 4.6
|
* @since 4.6
|
||||||
*/
|
*/
|
||||||
Package(const Package &other);
|
PLASMA_DEPRECATED Package(const Package &other);
|
||||||
|
|
||||||
~Package();
|
~Package();
|
||||||
|
|
||||||
@ -99,7 +102,7 @@ public:
|
|||||||
* Assignment operator
|
* Assignment operator
|
||||||
* @since 4.6
|
* @since 4.6
|
||||||
*/
|
*/
|
||||||
Package &operator=(const Package &rhs);
|
PLASMA_DEPRECATED Package &operator=(const Package &rhs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if this package has a valid PackageStructure associatedw it with it.
|
* @return true if this package has a valid PackageStructure associatedw it with it.
|
||||||
@ -107,24 +110,24 @@ public:
|
|||||||
* Package objects in a semi-initialized state (e.g. before calling setPath())
|
* Package objects in a semi-initialized state (e.g. before calling setPath())
|
||||||
* @since 5.1
|
* @since 5.1
|
||||||
*/
|
*/
|
||||||
bool hasValidStructure() const;
|
PLASMA_DEPRECATED bool hasValidStructure() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if all the required components exist
|
* @return true if all the required components exist
|
||||||
**/
|
**/
|
||||||
bool isValid() const;
|
PLASMA_DEPRECATED bool isValid() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the path to the root of this package
|
* Sets the path to the root of this package
|
||||||
* @param path an absolute path, or a relative path to the default package root
|
* @param path an absolute path, or a relative path to the default package root
|
||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
void setPath(const QString &path);
|
PLASMA_DEPRECATED void setPath(const QString &path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the path to the root of this particular package
|
* @return the path to the root of this particular package
|
||||||
*/
|
*/
|
||||||
const QString path() const;
|
PLASMA_DEPRECATED const QString path() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the path to a given file based on the key and an optional filename.
|
* Get the path to a given file based on the key and an optional filename.
|
||||||
@ -138,7 +141,7 @@ public:
|
|||||||
* @param filename optional name of the file to locate within the package
|
* @param filename optional name of the file to locate within the package
|
||||||
* @return path to the file on disk. QString() if not found.
|
* @return path to the file on disk. QString() if not found.
|
||||||
**/
|
**/
|
||||||
QString filePath(const char *key, const QString &filename = QString()) const;
|
PLASMA_DEPRECATED QString filePath(const char *key, const QString &filename = QString()) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of files of a given type.
|
* Get the list of files of a given type.
|
||||||
@ -147,56 +150,56 @@ public:
|
|||||||
* package structure.
|
* package structure.
|
||||||
* @return list of files by name, suitable for passing to filePath
|
* @return list of files by name, suitable for passing to filePath
|
||||||
**/
|
**/
|
||||||
QStringList entryList(const char *key) const;
|
PLASMA_DEPRECATED QStringList entryList(const char *key) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return user visible name for the given entry
|
* @return user visible name for the given entry
|
||||||
**/
|
**/
|
||||||
QString name(const char *key) const;
|
PLASMA_DEPRECATED QString name(const char *key) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the item at path exists and is required
|
* @return true if the item at path exists and is required
|
||||||
**/
|
**/
|
||||||
bool isRequired(const char *key) const;
|
PLASMA_DEPRECATED bool isRequired(const char *key) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the mimeTypes associated with the path, if any
|
* @return the mimeTypes associated with the path, if any
|
||||||
**/
|
**/
|
||||||
QStringList mimeTypes(const char *key) const;
|
PLASMA_DEPRECATED QStringList mimeTypes(const char *key) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the prefix paths inserted between the base path and content entries, in order of priority.
|
* @return the prefix paths inserted between the base path and content entries, in order of priority.
|
||||||
* When searching for a file, all paths will be tried in order.
|
* When searching for a file, all paths will be tried in order.
|
||||||
* @since 4.6
|
* @since 4.6
|
||||||
*/
|
*/
|
||||||
QStringList contentsPrefixPaths() const;
|
PLASMA_DEPRECATED QStringList contentsPrefixPaths() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return preferred package root. This defaults to plasma/plasmoids/
|
* @return preferred package root. This defaults to plasma/plasmoids/
|
||||||
*/
|
*/
|
||||||
QString defaultPackageRoot() const;
|
PLASMA_DEPRECATED QString defaultPackageRoot() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return service prefix used in desktop files. This defaults to plasma-applet-
|
* @return service prefix used in desktop files. This defaults to plasma-applet-
|
||||||
*/
|
*/
|
||||||
QString servicePrefix() const;
|
PLASMA_DEPRECATED QString servicePrefix() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if paths/symlinks outside the package itself should be followed.
|
* @return true if paths/symlinks outside the package itself should be followed.
|
||||||
* By default this is set to false for security reasons.
|
* By default this is set to false for security reasons.
|
||||||
*/
|
*/
|
||||||
bool allowExternalPaths() const;
|
PLASMA_DEPRECATED bool allowExternalPaths() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the package metadata object.
|
* @return the package metadata object.
|
||||||
*/
|
*/
|
||||||
KPluginInfo metadata() const;
|
PLASMA_DEPRECATED KPluginInfo metadata() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a SHA1 hash digest of the contents of the package in hexadecimal form
|
* @return a SHA1 hash digest of the contents of the package in hexadecimal form
|
||||||
* @since 4.4
|
* @since 4.4
|
||||||
*/
|
*/
|
||||||
QString contentsHash() const;
|
PLASMA_DEPRECATED QString contentsHash() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a directory to the structure of the package. It is added as
|
* Adds a directory to the structure of the package. It is added as
|
||||||
@ -209,7 +212,7 @@ public:
|
|||||||
* @param path the path within the package for this directory
|
* @param path the path within the package for this directory
|
||||||
* @param name the user visible (translated) name for the directory
|
* @param name the user visible (translated) name for the directory
|
||||||
**/
|
**/
|
||||||
void addDirectoryDefinition(const char *key, const QString &path, const QString &name);
|
PLASMA_DEPRECATED void addDirectoryDefinition(const char *key, const QString &path, const QString &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a file to the structure of the package. It is added as
|
* Adds a file to the structure of the package. It is added as
|
||||||
@ -222,14 +225,14 @@ public:
|
|||||||
* @param path the path within the package for this file
|
* @param path the path within the package for this file
|
||||||
* @param name the user visible (translated) name for the file
|
* @param name the user visible (translated) name for the file
|
||||||
**/
|
**/
|
||||||
void addFileDefinition(const char *key, const QString &path, const QString &name);
|
PLASMA_DEPRECATED void addFileDefinition(const char *key, const QString &path, const QString &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a definition from the structure of the package.
|
* Removes a definition from the structure of the package.
|
||||||
* @since 4.6
|
* @since 4.6
|
||||||
* @param key the internal label of the file or directory to remove
|
* @param key the internal label of the file or directory to remove
|
||||||
*/
|
*/
|
||||||
void removeDefinition(const char *key);
|
PLASMA_DEPRECATED void removeDefinition(const char *key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether or not a given part of the structure is required or not.
|
* Sets whether or not a given part of the structure is required or not.
|
||||||
@ -239,7 +242,7 @@ public:
|
|||||||
* @param key the entry within the package
|
* @param key the entry within the package
|
||||||
* @param required true if this entry is required, false if not
|
* @param required true if this entry is required, false if not
|
||||||
*/
|
*/
|
||||||
void setRequired(const char *key, bool required);
|
PLASMA_DEPRECATED void setRequired(const char *key, bool required);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the default mimeTypes for any definitions that do not have
|
* Defines the default mimeTypes for any definitions that do not have
|
||||||
@ -248,7 +251,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param mimeTypes a list of mimeTypes
|
* @param mimeTypes a list of mimeTypes
|
||||||
**/
|
**/
|
||||||
void setDefaultMimeTypes(QStringList mimeTypes);
|
PLASMA_DEPRECATED void setDefaultMimeTypes(QStringList mimeTypes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define mimeTypes for a given part of the structure
|
* Define mimeTypes for a given part of the structure
|
||||||
@ -258,7 +261,7 @@ public:
|
|||||||
* @param key the entry within the package
|
* @param key the entry within the package
|
||||||
* @param mimeTypes a list of mimeTypes
|
* @param mimeTypes a list of mimeTypes
|
||||||
**/
|
**/
|
||||||
void setMimeTypes(const char *key, QStringList mimeTypes);
|
PLASMA_DEPRECATED void setMimeTypes(const char *key, QStringList mimeTypes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the prefixes that all the contents in this package should
|
* Sets the prefixes that all the contents in this package should
|
||||||
@ -271,24 +274,24 @@ public:
|
|||||||
* @param prefix paths the directory prefix to use
|
* @param prefix paths the directory prefix to use
|
||||||
* @since 4.6
|
* @since 4.6
|
||||||
*/
|
*/
|
||||||
void setContentsPrefixPaths(const QStringList &prefixPaths);
|
PLASMA_DEPRECATED void setContentsPrefixPaths(const QStringList &prefixPaths);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets service prefix.
|
* Sets service prefix.
|
||||||
*/
|
*/
|
||||||
void setServicePrefix(const QString &servicePrefix);
|
PLASMA_DEPRECATED void setServicePrefix(const QString &servicePrefix);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether or not external paths/symlinks can be followed by a package
|
* Sets whether or not external paths/symlinks can be followed by a package
|
||||||
* @param allow true if paths/symlinks outside of the package should be followed,
|
* @param allow true if paths/symlinks outside of the package should be followed,
|
||||||
* false if they should be rejected.
|
* false if they should be rejected.
|
||||||
*/
|
*/
|
||||||
void setAllowExternalPaths(bool allow);
|
PLASMA_DEPRECATED void setAllowExternalPaths(bool allow);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets preferred package root.
|
* Sets preferred package root.
|
||||||
*/
|
*/
|
||||||
void setDefaultPackageRoot(const QString &packageRoot);
|
PLASMA_DEPRECATED void setDefaultPackageRoot(const QString &packageRoot);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the fallback package root path
|
* Sets the fallback package root path
|
||||||
@ -297,33 +300,33 @@ public:
|
|||||||
* It is intended to be used by the packageStructure
|
* It is intended to be used by the packageStructure
|
||||||
* @param path package root path @see setPath
|
* @param path package root path @see setPath
|
||||||
*/
|
*/
|
||||||
void setFallbackPackage(const Plasma::Package &package);
|
PLASMA_DEPRECATED void setFallbackPackage(const Plasma::Package &package);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The fallback package root path
|
* @return The fallback package root path
|
||||||
*/
|
*/
|
||||||
Plasma::Package fallbackPackage() const;
|
PLASMA_DEPRECATED Plasma::Package fallbackPackage() const;
|
||||||
|
|
||||||
// Content structure description methods
|
// Content structure description methods
|
||||||
/**
|
/**
|
||||||
* @return all directories registered as part of this Package's structure
|
* @return all directories registered as part of this Package's structure
|
||||||
*/
|
*/
|
||||||
QList<const char *> directories() const;
|
PLASMA_DEPRECATED QList<const char *> directories() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return all directories registered as part of this Package's required structure
|
* @return all directories registered as part of this Package's required structure
|
||||||
*/
|
*/
|
||||||
QList<const char *> requiredDirectories() const;
|
PLASMA_DEPRECATED QList<const char *> requiredDirectories() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return all files registered as part of this Package's structure
|
* @return all files registered as part of this Package's structure
|
||||||
*/
|
*/
|
||||||
QList<const char *> files() const;
|
PLASMA_DEPRECATED QList<const char *> files() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return all files registered as part of this Package's required structure
|
* @return all files registered as part of this Package's required structure
|
||||||
*/
|
*/
|
||||||
QList<const char *> requiredFiles() const;
|
PLASMA_DEPRECATED QList<const char *> requiredFiles() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs a package matching this package structure. By default installs a
|
* Installs a package matching this package structure. By default installs a
|
||||||
@ -331,22 +334,26 @@ public:
|
|||||||
*
|
*
|
||||||
* @return KJob to track installation progress and result
|
* @return KJob to track installation progress and result
|
||||||
**/
|
**/
|
||||||
KJob *install(const QString &sourcePackage, const QString &packageRoot = QString());
|
PLASMA_DEPRECATED KJob *install(const QString &sourcePackage, const QString &packageRoot = QString());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uninstalls a package matching this package structure.
|
* Uninstalls a package matching this package structure.
|
||||||
*
|
*
|
||||||
* @return KJob to track removal progress and result
|
* @return KJob to track removal progress and result
|
||||||
*/
|
*/
|
||||||
KJob *uninstall(const QString &packageName, const QString &packageRoot);
|
PLASMA_DEPRECATED KJob *uninstall(const QString &packageName, const QString &packageRoot);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QExplicitlySharedDataPointer<PackagePrivate> d;
|
QExplicitlySharedDataPointer<PackagePrivate> d;
|
||||||
friend class PackagePrivate;
|
friend class PackagePrivate;
|
||||||
|
friend class PackageStructure;
|
||||||
|
friend class AppletPrivate;
|
||||||
|
friend class Applet;
|
||||||
|
friend class Corona;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
Q_DECLARE_METATYPE(Plasma::Package)
|
Q_DECLARE_METATYPE(Plasma::Package)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -19,47 +19,226 @@
|
|||||||
|
|
||||||
#include "packagestructure.h"
|
#include "packagestructure.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <private/packagejob_p.h>
|
|
||||||
#include "private/package_p.h"
|
#include "private/package_p.h"
|
||||||
|
#include "private/packagestructure_p.h"
|
||||||
|
|
||||||
|
#include <kpackage/packageloader.h>
|
||||||
|
#include <kpackage/packagestructure.h>
|
||||||
|
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
#include <KJob>
|
||||||
|
#include <KDesktopFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
#include <QDBusPendingCall>
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
|
|
||||||
|
QHash<KPackage::Package *, Plasma::Package *> PackageStructureWrapper::s_packagesMap;
|
||||||
|
|
||||||
|
PackageStructureWrapper::PackageStructureWrapper(Plasma::PackageStructure *structure, QObject *parent, const QVariantList &args)
|
||||||
|
: KPackage::PackageStructure(parent, args),
|
||||||
|
m_struct(structure)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageStructureWrapper::~PackageStructureWrapper()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PackageStructureWrapper::initPackage(KPackage::Package *package)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!m_struct || !s_packagesMap.contains(package)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_struct->initPackage(s_packagesMap.value(package));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PackageStructureWrapper::pathChanged(KPackage::Package *package)
|
||||||
|
{
|
||||||
|
if (!m_struct || !s_packagesMap.contains(package)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_struct->pathChanged(s_packagesMap.value(package));
|
||||||
|
}
|
||||||
|
|
||||||
|
KJob *PackageStructureWrapper::install(KPackage::Package *package, const QString &archivePath, const QString &packageRoot)
|
||||||
|
{
|
||||||
|
if (!m_struct || !s_packagesMap.contains(package)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_struct->install(s_packagesMap.value(package), archivePath, packageRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
KJob *PackageStructureWrapper::uninstall(KPackage::Package *package, const QString &packageRoot)
|
||||||
|
{
|
||||||
|
if (!m_struct || !s_packagesMap.contains(package)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_struct->uninstall(s_packagesMap.value(package), packageRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void PackageStructurePrivate::installPathChanged(const QString &path)
|
||||||
|
{
|
||||||
|
KJob *job = qobject_cast<KJob *>(q->sender());
|
||||||
|
if (!job && job->error()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString servicePrefix = job->property("servicePrefix").toString();
|
||||||
|
const QString serviceName = job->property("serviceName").toString();
|
||||||
|
|
||||||
|
//uninstall
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
if (serviceName.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString service = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/") + serviceName;
|
||||||
|
|
||||||
|
bool ok = QFile::remove(service);
|
||||||
|
if (!ok) {
|
||||||
|
qWarning() << "Unable to remove " << service;
|
||||||
|
}
|
||||||
|
|
||||||
|
//install
|
||||||
|
} else {
|
||||||
|
if (!servicePrefix.isEmpty()) {
|
||||||
|
// and now we register it as a service =)
|
||||||
|
QString metaPath = path + "/metadata.desktop";
|
||||||
|
KDesktopFile df(metaPath);
|
||||||
|
KConfigGroup cg = df.desktopGroup();
|
||||||
|
const QString pluginName = cg.readEntry("X-KDE-PluginInfo-Name", QString());
|
||||||
|
|
||||||
|
if (pluginName.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Q: should not installing it as a service disqualify it?
|
||||||
|
// Q: i don't think so since KServiceTypeTrader may not be
|
||||||
|
// used by the installing app in any case, and the
|
||||||
|
// package is properly installed - aseigo
|
||||||
|
|
||||||
|
//TODO: reduce code duplication with registerPackage below
|
||||||
|
|
||||||
|
const QString serviceName = servicePrefix + pluginName + ".desktop";
|
||||||
|
|
||||||
|
QString localServiceDirectory = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/");
|
||||||
|
if (!QDir().mkpath(localServiceDirectory)) {
|
||||||
|
qDebug() << "Failed to create ... " << localServiceDirectory;
|
||||||
|
qWarning() << "Could not create local service directory:" << localServiceDirectory;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString service = localServiceDirectory + serviceName;
|
||||||
|
|
||||||
|
qDebug() << "-- Copying " << metaPath << service;
|
||||||
|
const bool ok = QFile::copy(metaPath, service);
|
||||||
|
if (ok) {
|
||||||
|
qDebug() << "Copying metadata went ok.";
|
||||||
|
// the icon in the installed file needs to point to the icon in the
|
||||||
|
// installation dir!
|
||||||
|
QString iconPath = path + '/' + cg.readEntry("Icon");
|
||||||
|
QFile icon(iconPath);
|
||||||
|
if (icon.exists()) {
|
||||||
|
KDesktopFile df(service);
|
||||||
|
KConfigGroup cg = df.desktopGroup();
|
||||||
|
cg.writeEntry("Icon", iconPath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning() << "Could not register package as service (this is not necessarily fatal):" << serviceName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QDBusInterface sycoca("org.kde.kded5", "/kbuildsycoca");
|
||||||
|
sycoca.asyncCall("recreate");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PackageStructure::PackageStructure(QObject *parent, const QVariantList &args)
|
PackageStructure::PackageStructure(QObject *parent, const QVariantList &args)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
d(0)
|
d(new PackageStructurePrivate(this))
|
||||||
{
|
{
|
||||||
|
if (!args.isEmpty() && args.first().canConvert<QString>()) {
|
||||||
|
d->internalStructure = KPackage::PackageLoader::self()->loadPackageStructure(args.first().toString());
|
||||||
|
}
|
||||||
|
|
||||||
Q_UNUSED(args)
|
Q_UNUSED(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
PackageStructure::~PackageStructure()
|
PackageStructure::~PackageStructure()
|
||||||
{
|
{
|
||||||
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackageStructure::initPackage(Package *package)
|
void PackageStructure::initPackage(Package *package)
|
||||||
{
|
{
|
||||||
Q_UNUSED(package)
|
if (d->internalStructure && !qobject_cast<PackageStructureWrapper *>(d->internalStructure)) {
|
||||||
|
d->internalStructure->initPackage(package->d->internalPackage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackageStructure::pathChanged(Package *package)
|
void PackageStructure::pathChanged(Package *package)
|
||||||
{
|
{
|
||||||
Q_UNUSED(package)
|
if (d->internalStructure && !qobject_cast<PackageStructureWrapper *>(d->internalStructure)) {
|
||||||
|
d->internalStructure->pathChanged(package->d->internalPackage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KJob *PackageStructure::install(Package *package, const QString &archivePath, const QString &packageRoot)
|
KJob *PackageStructure::install(Package *package, const QString &archivePath, const QString &packageRoot)
|
||||||
{
|
{
|
||||||
PackageJob *j = new PackageJob(package->servicePrefix(), this);
|
if (d->internalStructure && !qobject_cast<PackageStructureWrapper *>(d->internalStructure)) {
|
||||||
j->install(archivePath, packageRoot);
|
KJob *job = d->internalStructure->install(package->d->internalPackage, archivePath, packageRoot);
|
||||||
return j;
|
if (job) {
|
||||||
|
job->setProperty("servicePrefix", package->servicePrefix());
|
||||||
|
connect(job, SIGNAL(installPathChanged(QString)), this, SLOT(installPathChanged(QString)));
|
||||||
|
}
|
||||||
|
return job;
|
||||||
|
} else if (d->internalStructure) {
|
||||||
|
KJob *job = d->internalStructure->KPackage::PackageStructure::install(package->d->internalPackage, archivePath, packageRoot);
|
||||||
|
connect(job, SIGNAL(installPathChanged(QString)), this, SLOT(installPathChanged(QString)));
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
KJob *PackageStructure::uninstall(Package *package, const QString &packageRoot)
|
KJob *PackageStructure::uninstall(Package *package, const QString &packageRoot)
|
||||||
{
|
{
|
||||||
PackageJob *j = new PackageJob(package->servicePrefix(), this);
|
if (d->internalStructure && !qobject_cast<PackageStructureWrapper *>(d->internalStructure)) {
|
||||||
j->uninstall(packageRoot + package->metadata().pluginName());
|
QString metaPath = package->path() + "/metadata.desktop";
|
||||||
return j;
|
KDesktopFile df(metaPath);
|
||||||
|
KConfigGroup cg = df.desktopGroup();
|
||||||
|
const QString pluginName = cg.readEntry("X-KDE-PluginInfo-Name", QString());
|
||||||
|
const QString serviceName = package->servicePrefix() + pluginName + ".desktop";
|
||||||
|
|
||||||
|
KJob *job = d->internalStructure->uninstall(package->d->internalPackage, packageRoot);
|
||||||
|
if (job) {
|
||||||
|
job->setProperty("serviceName", serviceName);
|
||||||
|
|
||||||
|
connect(job, SIGNAL(installPathChanged(QString)), this, SLOT(installPathChanged(QString)));
|
||||||
|
}
|
||||||
|
return job;
|
||||||
|
} else if (d->internalStructure) {
|
||||||
|
KJob *job = d->internalStructure->KPackage::PackageStructure::uninstall(package->d->internalPackage, packageRoot);
|
||||||
|
connect(job, SIGNAL(installPathChanged(QString)), this, SLOT(installPathChanged(QString)));
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_packagestructure.cpp"
|
#include "moc_packagestructure.cpp"
|
||||||
|
#include "private/moc_packagestructure_p.cpp"
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
#include <plasma/package.h>
|
#include <plasma/package.h>
|
||||||
#include <plasma/version.h>
|
#include <plasma/version.h>
|
||||||
|
|
||||||
|
#ifndef PLASMA_NO_DEPRECATED
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -40,7 +42,7 @@ class PLASMA_EXPORT PackageStructure : public QObject
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit PackageStructure(QObject *parent = 0, const QVariantList &args = QVariantList());
|
PLASMA_DEPRECATED explicit PackageStructure(QObject *parent = 0, const QVariantList &args = QVariantList());
|
||||||
|
|
||||||
~PackageStructure();
|
~PackageStructure();
|
||||||
|
|
||||||
@ -55,13 +57,13 @@ public:
|
|||||||
* @arg package the Package to set up. The object is empty of all definition when
|
* @arg package the Package to set up. The object is empty of all definition when
|
||||||
* first passed in.
|
* first passed in.
|
||||||
*/
|
*/
|
||||||
virtual void initPackage(Package *package);
|
PLASMA_DEPRECATED virtual void initPackage(Package *package);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called whenever the path changes so that subclasses may take
|
* Called whenever the path changes so that subclasses may take
|
||||||
* package specific actions.
|
* package specific actions.
|
||||||
*/
|
*/
|
||||||
virtual void pathChanged(Package *package);
|
PLASMA_DEPRECATED virtual void pathChanged(Package *package);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs a package matching this package structure. By default installs a
|
* Installs a package matching this package structure. By default installs a
|
||||||
@ -74,7 +76,7 @@ public:
|
|||||||
* installed to
|
* installed to
|
||||||
* @return KJob* to track the installation status
|
* @return KJob* to track the installation status
|
||||||
**/
|
**/
|
||||||
virtual KJob *install(Package *package, const QString &archivePath, const QString &packageRoot);
|
PLASMA_DEPRECATED virtual KJob *install(Package *package, const QString &archivePath, const QString &packageRoot);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uninstalls a package matching this package structure.
|
* Uninstalls a package matching this package structure.
|
||||||
@ -85,10 +87,15 @@ public:
|
|||||||
* @param packageRoot path to the directory where the package should be installed to
|
* @param packageRoot path to the directory where the package should be installed to
|
||||||
* @return KJob* to track the installation status
|
* @return KJob* to track the installation status
|
||||||
*/
|
*/
|
||||||
virtual KJob *uninstall(Package *package, const QString &packageRoot);
|
PLASMA_DEPRECATED virtual KJob *uninstall(Package *package, const QString &packageRoot);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PackageStructurePrivate *d;
|
PackageStructurePrivate *d;
|
||||||
|
friend class Package;
|
||||||
|
friend class PluginLoader;
|
||||||
|
friend class PackageStructurePrivate;
|
||||||
|
|
||||||
|
Q_PRIVATE_SLOT(d, void installPathChanged(const QString &path))
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Plasma namespace
|
} // Plasma namespace
|
||||||
@ -105,3 +112,5 @@ private:
|
|||||||
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
|
K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <kservice.h>
|
#include <kservice.h>
|
||||||
#include <kservicetypetrader.h>
|
#include <kservicetypetrader.h>
|
||||||
#include <kplugintrader.h>
|
#include <kplugintrader.h>
|
||||||
|
#include <kpackage/packageloader.h>
|
||||||
|
|
||||||
#include "config-plasma.h"
|
#include "config-plasma.h"
|
||||||
|
|
||||||
@ -41,6 +42,8 @@
|
|||||||
#include "private/packages_p.h"
|
#include "private/packages_p.h"
|
||||||
#include "private/service_p.h" // for NullService
|
#include "private/service_p.h" // for NullService
|
||||||
#include "private/storage_p.h"
|
#include "private/storage_p.h"
|
||||||
|
#include "private/package_p.h"
|
||||||
|
#include "private/packagestructure_p.h"
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
@ -401,50 +404,48 @@ Package PluginLoader::loadPackage(const QString &packageFormat, const QString &s
|
|||||||
|
|
||||||
const QString hashkey = packageFormat + '%' + specialization;
|
const QString hashkey = packageFormat + '%' + specialization;
|
||||||
PackageStructure *structure = d->structures.value(hashkey).data();
|
PackageStructure *structure = d->structures.value(hashkey).data();
|
||||||
|
|
||||||
|
KPackage::PackageStructure *internalStructure = 0;
|
||||||
if (structure) {
|
if (structure) {
|
||||||
return Package(structure);
|
return Package(structure);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!specialization.isEmpty()) {
|
|
||||||
// check that the provided strings are safe to use in a ServiceType query
|
|
||||||
if (d->packageRE.indexIn(specialization) == -1 && d->packageRE.indexIn(packageFormat) == -1) {
|
|
||||||
// FIXME: The query below is rather spepcific to script engines. generify if possible
|
|
||||||
const QString component = packageFormat.right(packageFormat.size() - packageFormat.lastIndexOf('/') - 1);
|
|
||||||
const QString constraint = QString("[X-Plasma-API] == '%1' and " "'%2' in [X-Plasma-ComponentTypes]").arg(specialization, component);
|
|
||||||
KService::List offers = KServiceTypeTrader::self()->query("Plasma/ScriptEngine", constraint);
|
|
||||||
|
|
||||||
if (!offers.isEmpty()) {
|
|
||||||
KService::Ptr offer = offers.first();
|
|
||||||
QString packageFormat = offer->property("X-Plasma-PackageFormat").toString();
|
|
||||||
if (!packageFormat.isEmpty()) {
|
|
||||||
return loadPackage(packageFormat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packageFormat.startsWith("Plasma")) {
|
if (packageFormat.startsWith("Plasma")) {
|
||||||
if (packageFormat.endsWith("/Applet")) {
|
if (packageFormat.endsWith("/Applet")) {
|
||||||
structure = new PlasmoidPackage();
|
internalStructure = new PlasmoidPackage();
|
||||||
} else if (packageFormat.endsWith("/DataEngine")) {
|
} else if (packageFormat.endsWith("/DataEngine")) {
|
||||||
structure = new DataEnginePackage();
|
internalStructure = new DataEnginePackage();
|
||||||
} else if (packageFormat.endsWith("/Theme")) {
|
} else if (packageFormat.endsWith("/Theme")) {
|
||||||
structure = new ThemePackage();
|
internalStructure = new ThemePackage();
|
||||||
} else if (packageFormat.endsWith("/ContainmentActions")) {
|
} else if (packageFormat.endsWith("/ContainmentActions")) {
|
||||||
structure = new ContainmentActionsPackage();
|
internalStructure = new ContainmentActionsPackage();
|
||||||
} else if (packageFormat.endsWith("/Generic")) {
|
} else if (packageFormat.endsWith("/Generic")) {
|
||||||
structure = new GenericPackage();
|
internalStructure = new GenericPackage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (structure) {
|
if (internalStructure) {
|
||||||
|
structure = new PackageStructure();
|
||||||
|
structure->d->internalStructure = internalStructure;
|
||||||
d->structures.insert(hashkey, structure);
|
d->structures.insert(hashkey, structure);
|
||||||
return Package(structure);
|
return Package(structure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// first we check for plugins in sycoca
|
internalStructure = KPackage::PackageLoader::self()->loadPackageStructure(packageFormat);
|
||||||
const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(packageFormat);
|
|
||||||
structure = KPluginTrader::createInstanceFromQuery<Plasma::PackageStructure>(d->packageStructurePluginDir, "Plasma/PackageStructure", constraint, 0);
|
if (internalStructure) {
|
||||||
|
structure = new PackageStructure();
|
||||||
|
structure->d->internalStructure = internalStructure;
|
||||||
|
//fallback to old structures
|
||||||
|
} else {
|
||||||
|
const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(packageFormat);
|
||||||
|
structure = KPluginTrader::createInstanceFromQuery<Plasma::PackageStructure>(d->packageStructurePluginDir, "Plasma/PackageStructure", constraint, 0);
|
||||||
|
if (structure) {
|
||||||
|
structure->d->internalStructure = new PackageStructureWrapper(structure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (structure) {
|
if (structure) {
|
||||||
d->structures.insert(hashkey, structure);
|
d->structures.insert(hashkey, structure);
|
||||||
return Package(structure);
|
return Package(structure);
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "scripting/scriptengine.h"
|
#include "scripting/scriptengine.h"
|
||||||
#include "scripting/appletscript.h"
|
#include "scripting/appletscript.h"
|
||||||
#include "private/containment_p.h"
|
#include "private/containment_p.h"
|
||||||
|
#include "private/package_p.h"
|
||||||
#include "timetracker.h"
|
#include "timetracker.h"
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
@ -142,8 +143,10 @@ void AppletPrivate::init(const QString &packagePath, const QVariantList &args)
|
|||||||
if (path.isEmpty()) {
|
if (path.isEmpty()) {
|
||||||
path = packagePath.isEmpty() ? appletDescription.pluginName() : packagePath;
|
path = packagePath.isEmpty() ? appletDescription.pluginName() : packagePath;
|
||||||
}
|
}
|
||||||
package = new Package(PluginLoader::self()->loadPackage("Plasma/Applet", api));
|
Plasma::Package p = PluginLoader::self()->loadPackage("Plasma/Applet", api);
|
||||||
package->setPath(path);
|
p.setPath(path);
|
||||||
|
|
||||||
|
package = new KPackage::Package(*p.d->internalPackage);
|
||||||
|
|
||||||
if (!package->isValid()) {
|
if (!package->isValid()) {
|
||||||
delete package;
|
delete package;
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
#include <kplugininfo.h>
|
#include <kplugininfo.h>
|
||||||
#include <KNotification>
|
#include <KNotification>
|
||||||
|
|
||||||
|
#include <KPackage/Package>
|
||||||
|
|
||||||
#include "plasma/applet.h"
|
#include "plasma/applet.h"
|
||||||
|
|
||||||
class KKeySequenceWidget;
|
class KKeySequenceWidget;
|
||||||
@ -92,7 +94,7 @@ public:
|
|||||||
|
|
||||||
// sripting and package stuff
|
// sripting and package stuff
|
||||||
AppletScript *script;
|
AppletScript *script;
|
||||||
Package *package;
|
KPackage::Package *package;
|
||||||
KConfigLoader *configLoader;
|
KConfigLoader *configLoader;
|
||||||
|
|
||||||
// actions stuff; put activationAction into actions?
|
// actions stuff; put activationAction into actions?
|
||||||
|
@ -49,7 +49,7 @@ public:
|
|||||||
QList<Plasma::Containment *> importLayout(const KConfigGroup &conf, bool mergeConfig);
|
QList<Plasma::Containment *> importLayout(const KConfigGroup &conf, bool mergeConfig);
|
||||||
|
|
||||||
Corona *q;
|
Corona *q;
|
||||||
Package package;
|
KPackage::Package package;
|
||||||
KConfigGroup desktopDefaultsConfig;
|
KConfigGroup desktopDefaultsConfig;
|
||||||
Types::ImmutabilityType immutability;
|
Types::ImmutabilityType immutability;
|
||||||
QString configName;
|
QString configName;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
|
* Copyright © 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
|
||||||
|
* Copyright 2014 Marco Martin <mart@kde.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Library General Public License version 2 as
|
* it under the terms of the GNU Library General Public License version 2 as
|
||||||
@ -19,79 +20,28 @@
|
|||||||
#ifndef PLASMA_PACKAGE_P_H
|
#ifndef PLASMA_PACKAGE_P_H
|
||||||
#define PLASMA_PACKAGE_P_H
|
#define PLASMA_PACKAGE_P_H
|
||||||
|
|
||||||
#include "../plasma.h"
|
|
||||||
#include "../package.h"
|
#include "../package.h"
|
||||||
#include "../service.h"
|
|
||||||
|
|
||||||
#include <QCryptographicHash>
|
#include <QExplicitlySharedDataPointer>
|
||||||
#include <QDir>
|
|
||||||
#include <QString>
|
#include <kpackage/package.h>
|
||||||
#include <QSharedData>
|
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
|
|
||||||
class ContentStructure
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ContentStructure()
|
|
||||||
: directory(false),
|
|
||||||
required(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentStructure(const ContentStructure &other)
|
|
||||||
{
|
|
||||||
paths = other.paths;
|
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
|
||||||
name = other.name;
|
|
||||||
mimeTypes = other.mimeTypes;
|
|
||||||
#endif
|
|
||||||
directory = other.directory;
|
|
||||||
required = other.required;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString found;
|
|
||||||
QStringList paths;
|
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
|
||||||
QString name;
|
|
||||||
QStringList mimeTypes;
|
|
||||||
#endif
|
|
||||||
bool directory : 1;
|
|
||||||
bool required : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PackagePrivate : public QSharedData
|
class PackagePrivate : public QSharedData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PackagePrivate();
|
PackagePrivate();
|
||||||
PackagePrivate(const PackagePrivate &other);
|
|
||||||
~PackagePrivate();
|
~PackagePrivate();
|
||||||
|
|
||||||
PackagePrivate &operator=(const PackagePrivate &rhs);
|
void installFinished(KJob *job);
|
||||||
|
void uninstallFinished(KJob *job);
|
||||||
|
|
||||||
void createPackageMetadata(const QString &path);
|
|
||||||
QString unpack(const QString &filePath);
|
|
||||||
void updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCryptographicHash &hash);
|
|
||||||
QString fallbackFilePath(const char *key, const QString &filename = QString()) const;
|
|
||||||
bool hasCycle(const Plasma::Package &package);
|
|
||||||
|
|
||||||
QWeakPointer<PackageStructure> structure;
|
|
||||||
QString path;
|
|
||||||
QString tempRoot;
|
|
||||||
QStringList contentsPrefixPaths;
|
|
||||||
QString defaultPackageRoot;
|
|
||||||
QString servicePrefix;
|
QString servicePrefix;
|
||||||
QHash<QString, QString> discoveries;
|
KPackage::Package *internalPackage;
|
||||||
QHash<QByteArray, ContentStructure> contents;
|
|
||||||
Package *fallbackPackage;
|
Package *fallbackPackage;
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
PackageStructure *structure;
|
||||||
QStringList mimeTypes;
|
|
||||||
#endif
|
|
||||||
KPluginInfo *metadata;
|
|
||||||
bool externalPaths : 1;
|
|
||||||
bool valid : 1;
|
|
||||||
bool checkedValid : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* Copyright 2012 Sebastian Kügler <sebas@kde.org> *
|
|
||||||
* *
|
|
||||||
* This library is free software; you can redistribute it and/or *
|
|
||||||
* modify it under the terms of the GNU Library General Public *
|
|
||||||
* License as published by the Free Software Foundation; either *
|
|
||||||
* version 2 of the License, or (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This library is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
||||||
* Library General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU Library General Public License *
|
|
||||||
* along with this library; see the file COPYING.LIB. If not, write to *
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
|
|
||||||
* Boston, MA 02110-1301, USA. *
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include "packagejob_p.h"
|
|
||||||
#include "packagejobthread_p.h"
|
|
||||||
#include "config-plasma.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
namespace Plasma
|
|
||||||
{
|
|
||||||
class PackageJobPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PackageJobThread *thread;
|
|
||||||
QString installPath;
|
|
||||||
};
|
|
||||||
|
|
||||||
PackageJob::PackageJob(const QString &servicePrefix, QObject *parent) :
|
|
||||||
KJob(parent)
|
|
||||||
{
|
|
||||||
d = new PackageJobPrivate;
|
|
||||||
d->thread = new PackageJobThread(servicePrefix, this);
|
|
||||||
connect(d->thread, SIGNAL(finished(bool,QString)),
|
|
||||||
SLOT(slotFinished(bool,QString)), Qt::QueuedConnection);
|
|
||||||
connect(d->thread, SIGNAL(installPathChanged(QString)),
|
|
||||||
SIGNAL(installPathChanged(QString)), Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
PackageJob::~PackageJob()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackageJob::slotFinished(bool ok, const QString &err)
|
|
||||||
{
|
|
||||||
if (ok) {
|
|
||||||
setError(NoError);
|
|
||||||
} else {
|
|
||||||
setError(UserDefinedError);
|
|
||||||
setErrorText(err);
|
|
||||||
}
|
|
||||||
d->thread->exit(0);
|
|
||||||
emitResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackageJob::start()
|
|
||||||
{
|
|
||||||
d->thread->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackageJob::install(const QString &src, const QString &dest)
|
|
||||||
{
|
|
||||||
d->thread->install(src, dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackageJob::uninstall(const QString &installationPath)
|
|
||||||
{
|
|
||||||
d->thread->uninstall(installationPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Plasma
|
|
||||||
|
|
||||||
#include "moc_packagejob_p.cpp"
|
|
@ -1,58 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* Copyright 2012 Sebastian Kügler <sebas@kde.org> *
|
|
||||||
* *
|
|
||||||
* This library is free software; you can redistribute it and/or *
|
|
||||||
* modify it under the terms of the GNU Library General Public *
|
|
||||||
* License as published by the Free Software Foundation; either *
|
|
||||||
* version 2 of the License, or (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This library is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
||||||
* Library General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU Library General Public License *
|
|
||||||
* along with this library; see the file COPYING.LIB. If not, write to *
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
|
|
||||||
* Boston, MA 02110-1301, USA. *
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef PLASMA_PACKAGEJOB_P_H
|
|
||||||
#define PLASMA_PACKAGEJOB_P_H
|
|
||||||
|
|
||||||
#include "kjob.h"
|
|
||||||
|
|
||||||
namespace Plasma
|
|
||||||
{
|
|
||||||
|
|
||||||
class PackageJobPrivate;
|
|
||||||
|
|
||||||
class PackageJob : public KJob
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
PackageJob(const QString &servicePrefix, QObject *parent = 0);
|
|
||||||
~PackageJob();
|
|
||||||
|
|
||||||
virtual void start();
|
|
||||||
|
|
||||||
void install(const QString &src, const QString &dest);
|
|
||||||
void uninstall(const QString &installationPath);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void installPathChanged(const QString &path);
|
|
||||||
|
|
||||||
// Q_SIGNALS:
|
|
||||||
// void finished(bool success);
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void slotFinished(bool ok, const QString &err);
|
|
||||||
|
|
||||||
private:
|
|
||||||
PackageJobPrivate *d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,372 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* Copyright 2007-2009 by Aaron Seigo <aseigo@kde.org> *
|
|
||||||
* Copyright 2012 Sebastian Kügler <sebas@kde.org> *
|
|
||||||
* *
|
|
||||||
* This library is free software; you can redistribute it and/or *
|
|
||||||
* modify it under the terms of the GNU Library General Public *
|
|
||||||
* License as published by the Free Software Foundation; either *
|
|
||||||
* version 2 of the License, or (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This library is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
||||||
* Library General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU Library General Public License *
|
|
||||||
* along with this library; see the file COPYING.LIB. If not, write to *
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
|
|
||||||
* Boston, MA 02110-1301, USA. *
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#include "private/packagejobthread_p.h"
|
|
||||||
|
|
||||||
#include "package.h"
|
|
||||||
#include "config-plasma.h"
|
|
||||||
|
|
||||||
#include <karchive.h>
|
|
||||||
#include <kdesktopfile.h>
|
|
||||||
#include <klocalizedstring.h>
|
|
||||||
#include <ktar.h>
|
|
||||||
#include <kzip.h>
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QDBusInterface>
|
|
||||||
#include <QDBusPendingCall>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QIODevice>
|
|
||||||
#include <QMimeType>
|
|
||||||
#include <QMimeDatabase>
|
|
||||||
#include <QRegExp>
|
|
||||||
#include <QtNetwork/QHostInfo>
|
|
||||||
#include <qtemporarydir.h>
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
namespace Plasma
|
|
||||||
{
|
|
||||||
|
|
||||||
bool copyFolder(QString sourcePath, QString targetPath)
|
|
||||||
{
|
|
||||||
QDir source(sourcePath);
|
|
||||||
if (!source.exists()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDir target(targetPath);
|
|
||||||
if (!target.exists()) {
|
|
||||||
QString targetName = target.dirName();
|
|
||||||
target.cdUp();
|
|
||||||
target.mkdir(targetName);
|
|
||||||
target = QDir(targetPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const QString &fileName, source.entryList(QDir::Files)) {
|
|
||||||
QString sourceFilePath = sourcePath + QDir::separator() + fileName;
|
|
||||||
QString targetFilePath = targetPath + QDir::separator() + fileName;
|
|
||||||
|
|
||||||
if (!QFile::copy(sourceFilePath, targetFilePath)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const QString &subFolderName, source.entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
|
|
||||||
QString sourceSubFolderPath = sourcePath + QDir::separator() + subFolderName;
|
|
||||||
QString targetSubFolderPath = targetPath + QDir::separator() + subFolderName;
|
|
||||||
|
|
||||||
if (!copyFolder(sourceSubFolderPath, targetSubFolderPath)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Qt5 TODO: use QDir::removeRecursively() instead
|
|
||||||
bool removeFolder(QString folderPath)
|
|
||||||
{
|
|
||||||
QDir folder(folderPath);
|
|
||||||
if (!folder.exists()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const QString &fileName, folder.entryList(QDir::Files)) {
|
|
||||||
if (!QFile::remove(folderPath + QDir::separator() + fileName)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const QString &subFolderName, folder.entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
|
|
||||||
if (!removeFolder(folderPath + QDir::separator() + subFolderName)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString folderName = folder.dirName();
|
|
||||||
folder.cdUp();
|
|
||||||
return folder.rmdir(folderName);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PackageJobThreadPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QString installPath;
|
|
||||||
QString errorMessage;
|
|
||||||
QString servicePrefix;
|
|
||||||
};
|
|
||||||
|
|
||||||
PackageJobThread::PackageJobThread(const QString &servicePrefix, QObject *parent) :
|
|
||||||
QThread(parent)
|
|
||||||
{
|
|
||||||
d = new PackageJobThreadPrivate;
|
|
||||||
d->servicePrefix = servicePrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
PackageJobThread::~PackageJobThread()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PackageJobThread::install(const QString &src, const QString &dest)
|
|
||||||
{
|
|
||||||
bool ok = installPackage(src, dest);
|
|
||||||
emit installPathChanged(d->installPath);
|
|
||||||
emit finished(ok, d->errorMessage);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PackageJobThread::installPackage(const QString &src, const QString &dest)
|
|
||||||
{
|
|
||||||
QString packageRoot = dest;
|
|
||||||
QDir root(dest);
|
|
||||||
if (!root.exists()) {
|
|
||||||
QDir().mkpath(dest);
|
|
||||||
if (!root.exists()) {
|
|
||||||
d->errorMessage = i18n("Could not create package root directory: %1", dest);
|
|
||||||
//qWarning() << "Could not create package root directory: " << dest;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileInfo fileInfo(src);
|
|
||||||
if (!fileInfo.exists()) {
|
|
||||||
d->errorMessage = i18n("No such file: %1", src);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString path;
|
|
||||||
QTemporaryDir tempdir;
|
|
||||||
bool archivedPackage = false;
|
|
||||||
|
|
||||||
if (fileInfo.isDir()) {
|
|
||||||
// we have a directory, so let's just install what is in there
|
|
||||||
path = src;
|
|
||||||
// make sure we end in a slash!
|
|
||||||
if (path[path.size() - 1] != '/') {
|
|
||||||
path.append('/');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
KArchive *archive = 0;
|
|
||||||
QMimeDatabase db;
|
|
||||||
QMimeType mimetype = db.mimeTypeForFile(src);
|
|
||||||
if (mimetype.inherits("application/zip")) {
|
|
||||||
archive = new KZip(src);
|
|
||||||
} else if (mimetype.inherits("application/x-compressed-tar") ||
|
|
||||||
mimetype.inherits("application/x-tar") || mimetype.inherits("application/x-bzip-compressed-tar") ||
|
|
||||||
mimetype.inherits("application/x-xz") || mimetype.inherits("application/x-lzma")) {
|
|
||||||
archive = new KTar(src);
|
|
||||||
} else {
|
|
||||||
//qWarning() << "Could not open package file, unsupported archive format:" << src << mimetype.name();
|
|
||||||
d->errorMessage = i18n("Could not open package file, unsupported archive format: %1 %2", src, mimetype.name());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!archive->open(QIODevice::ReadOnly)) {
|
|
||||||
//qWarning() << "Could not open package file:" << src;
|
|
||||||
delete archive;
|
|
||||||
d->errorMessage = i18n("Could not open package file: %1", src);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
archivedPackage = true;
|
|
||||||
path = tempdir.path() + '/';
|
|
||||||
|
|
||||||
d->installPath = path;
|
|
||||||
|
|
||||||
const KArchiveDirectory *source = archive->directory();
|
|
||||||
source->copyTo(path);
|
|
||||||
|
|
||||||
QStringList entries = source->entries();
|
|
||||||
if (entries.count() == 1) {
|
|
||||||
const KArchiveEntry *entry = source->entry(entries[0]);
|
|
||||||
if (entry->isDirectory()) {
|
|
||||||
path.append(entry->name()).append("/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete archive;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString metadataPath = path + "metadata.desktop";
|
|
||||||
if (!QFile::exists(metadataPath)) {
|
|
||||||
qDebug() << "No metadata file in package" << src << metadataPath;
|
|
||||||
d->errorMessage = i18n("No metadata file in package: %1", src);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
KPluginInfo meta(metadataPath);
|
|
||||||
QString pluginName = meta.pluginName();
|
|
||||||
qDebug() << "pluginname: " << meta.pluginName();
|
|
||||||
if (pluginName.isEmpty()) {
|
|
||||||
//qWarning() << "Package plugin name not specified";
|
|
||||||
d->errorMessage = i18n("Package plugin name not specified: %1", src);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that package names are safe so package uninstall can't inject
|
|
||||||
// bad characters into the paths used for removal.
|
|
||||||
QRegExp validatePluginName("^[\\w-\\.]+$"); // Only allow letters, numbers, underscore and period.
|
|
||||||
if (!validatePluginName.exactMatch(pluginName)) {
|
|
||||||
//qDebug() << "Package plugin name " << pluginName << "contains invalid characters";
|
|
||||||
d->errorMessage = i18n("Package plugin name %1 contains invalid characters", pluginName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString targetName = dest;
|
|
||||||
if (targetName[targetName.size() - 1] != '/') {
|
|
||||||
targetName.append('/');
|
|
||||||
}
|
|
||||||
targetName.append(pluginName);
|
|
||||||
|
|
||||||
if (QFile::exists(targetName)) {
|
|
||||||
d->errorMessage = i18n("%1 already exists", targetName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (archivedPackage) {
|
|
||||||
// it's in a temp dir, so just move it over.
|
|
||||||
const bool ok = copyFolder(path, targetName);
|
|
||||||
removeFolder(path);
|
|
||||||
if (!ok) {
|
|
||||||
//qWarning() << "Could not move package to destination:" << targetName;
|
|
||||||
d->errorMessage = i18n("Could not move package to destination: %1", targetName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// it's a directory containing the stuff, so copy the contents rather
|
|
||||||
// than move them
|
|
||||||
const bool ok = copyFolder(path, targetName);
|
|
||||||
if (!ok) {
|
|
||||||
//qWarning() << "Could not copy package to destination:" << targetName;
|
|
||||||
d->errorMessage = i18n("Could not copy package to destination: %1", targetName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (archivedPackage) {
|
|
||||||
// no need to remove the temp dir (which has been successfully moved if it's an archive)
|
|
||||||
tempdir.setAutoRemove(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!d->servicePrefix.isEmpty()) {
|
|
||||||
// and now we register it as a service =)
|
|
||||||
QString metaPath = targetName + "/metadata.desktop";
|
|
||||||
KDesktopFile df(metaPath);
|
|
||||||
KConfigGroup cg = df.desktopGroup();
|
|
||||||
|
|
||||||
// Q: should not installing it as a service disqualify it?
|
|
||||||
// Q: i don't think so since KServiceTypeTrader may not be
|
|
||||||
// used by the installing app in any case, and the
|
|
||||||
// package is properly installed - aseigo
|
|
||||||
|
|
||||||
//TODO: reduce code duplication with registerPackage below
|
|
||||||
|
|
||||||
const QString serviceName = d->servicePrefix + meta.pluginName() + ".desktop";
|
|
||||||
|
|
||||||
QString localServiceDirectory = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/");
|
|
||||||
if (!QDir().mkpath(localServiceDirectory)) {
|
|
||||||
qDebug() << "Failed to create ... " << localServiceDirectory;
|
|
||||||
d->errorMessage = i18n("Could not create local service directory: %1", localServiceDirectory);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QString service = localServiceDirectory + serviceName;
|
|
||||||
|
|
||||||
qDebug() << "-- Copying " << metaPath << service;
|
|
||||||
const bool ok = QFile::copy(metaPath, service);
|
|
||||||
if (ok) {
|
|
||||||
qDebug() << "Copying metadata went ok.";
|
|
||||||
// the icon in the installed file needs to point to the icon in the
|
|
||||||
// installation dir!
|
|
||||||
QString iconPath = targetName + '/' + cg.readEntry("Icon");
|
|
||||||
QFile icon(iconPath);
|
|
||||||
if (icon.exists()) {
|
|
||||||
KDesktopFile df(service);
|
|
||||||
KConfigGroup cg = df.desktopGroup();
|
|
||||||
cg.writeEntry("Icon", iconPath);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qDebug() << "Could not register package as service (this is not necessarily fatal):" << serviceName;
|
|
||||||
d->errorMessage = i18n("Could not register package as service (this is not necessarily fatal): %1", serviceName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QDBusInterface sycoca("org.kde.kded5", "/kbuildsycoca");
|
|
||||||
sycoca.asyncCall("recreate");
|
|
||||||
d->installPath = targetName;
|
|
||||||
|
|
||||||
//qWarning() << "Not updating kbuildsycoca4, since that will go away. Do it yourself for now if needed.";
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PackageJobThread::uninstall(const QString &packagePath)
|
|
||||||
{
|
|
||||||
bool ok = uninstallPackage(packagePath);
|
|
||||||
//qDebug() << "emit installPathChanged " << d->installPath;
|
|
||||||
emit installPathChanged(QString());
|
|
||||||
//qDebug() << "Thread: installFinished" << ok;
|
|
||||||
emit finished(ok, d->errorMessage);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PackageJobThread::uninstallPackage(const QString &packagePath)
|
|
||||||
{
|
|
||||||
if (!QFile::exists(packagePath)) {
|
|
||||||
d->errorMessage = i18n("%1 does not exist", packagePath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QString pkg;
|
|
||||||
{
|
|
||||||
// FIXME: remove, pass in packageroot, type and pluginName separately?
|
|
||||||
QString _path = packagePath;
|
|
||||||
QStringList ps = packagePath.split('/');
|
|
||||||
int ix = ps.count() - 1;
|
|
||||||
if (packagePath.endsWith('/')) {
|
|
||||||
ix = ps.count() - 2;
|
|
||||||
}
|
|
||||||
pkg = ps[ix];
|
|
||||||
}
|
|
||||||
const QString &packageName = pkg;
|
|
||||||
|
|
||||||
const QString serviceName = d->servicePrefix + packageName + ".desktop";
|
|
||||||
|
|
||||||
QString service = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kservices5/") + serviceName;
|
|
||||||
|
|
||||||
bool ok = QFile::remove(service);
|
|
||||||
if (!ok) {
|
|
||||||
qWarning() << "Unable to remove " << service;
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = removeFolder(packagePath);
|
|
||||||
if (!ok) {
|
|
||||||
d->errorMessage = i18n("Could not delete package from: %1", packagePath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDBusInterface sycoca("org.kde.kded5", "/kbuildsycoca");
|
|
||||||
sycoca.asyncCall("recreate");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Plasma
|
|
||||||
|
|
||||||
#include "moc_packagejobthread_p.cpp"
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* Copyright 2007-2009 by Aaron Seigo <aseigo@kde.org> *
|
|
||||||
* Copyright 2012 Sebastian Kügler <sebas@kde.org> *
|
|
||||||
* *
|
|
||||||
* This library is free software; you can redistribute it and/or *
|
|
||||||
* modify it under the terms of the GNU Library General Public *
|
|
||||||
* License as published by the Free Software Foundation; either *
|
|
||||||
* version 2 of the License, or (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This library is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
||||||
* Library General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU Library General Public License *
|
|
||||||
* along with this library; see the file COPYING.LIB. If not, write to *
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
|
|
||||||
* Boston, MA 02110-1301, USA. *
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef PLASMA_PACKAGEJOBTHREAD_P_H
|
|
||||||
#define PLASMA_PACKAGEJOBTHREAD_P_H
|
|
||||||
|
|
||||||
#include "kjob.h"
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
namespace Plasma
|
|
||||||
{
|
|
||||||
|
|
||||||
class PackageJobThreadPrivate;
|
|
||||||
|
|
||||||
class PackageJobThread : public QThread
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
PackageJobThread(const QString &servicePrefix, QObject *parent = 0);
|
|
||||||
virtual ~PackageJobThread();
|
|
||||||
|
|
||||||
bool install(const QString &src, const QString &dest);
|
|
||||||
bool uninstall(const QString &packagePath);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void finished(bool success, const QString &errorMessage = QString());
|
|
||||||
void percentChanged(int percent);
|
|
||||||
void error(const QString &errorMessage);
|
|
||||||
void installPathChanged(const QString &installPath);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool installPackage(const QString &src, const QString &dest);
|
|
||||||
bool uninstallPackage(const QString &packagePath);
|
|
||||||
PackageJobThreadPrivate *d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include <kconfiggroup.h>
|
#include <kconfiggroup.h>
|
||||||
#include <kdesktopfile.h>
|
#include <kdesktopfile.h>
|
||||||
@ -34,10 +35,12 @@
|
|||||||
#include "package.h"
|
#include "package.h"
|
||||||
#include "config-plasma.h"
|
#include "config-plasma.h"
|
||||||
|
|
||||||
|
#include <kpackage/package.h>
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
|
|
||||||
void ChangeableMainScriptPackage::initPackage(Package *package)
|
void ChangeableMainScriptPackage::initPackage(KPackage::Package *package)
|
||||||
{
|
{
|
||||||
package->addFileDefinition("mainscript", "ui/main.qml", i18n("Main Script File"));
|
package->addFileDefinition("mainscript", "ui/main.qml", i18n("Main Script File"));
|
||||||
package->setRequired("mainscript", true);
|
package->setRequired("mainscript", true);
|
||||||
@ -48,7 +51,7 @@ QString ChangeableMainScriptPackage::mainScriptConfigKey() const
|
|||||||
return QLatin1String("X-Plasma-MainScript");
|
return QLatin1String("X-Plasma-MainScript");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChangeableMainScriptPackage::pathChanged(Package *package)
|
void ChangeableMainScriptPackage::pathChanged(KPackage::Package *package)
|
||||||
{
|
{
|
||||||
if (package->path().isEmpty()) {
|
if (package->path().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@ -63,7 +66,7 @@ void ChangeableMainScriptPackage::pathChanged(Package *package)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericPackage::initPackage(Package *package)
|
void GenericPackage::initPackage(KPackage::Package *package)
|
||||||
{
|
{
|
||||||
ChangeableMainScriptPackage::initPackage(package);
|
ChangeableMainScriptPackage::initPackage(package);
|
||||||
|
|
||||||
@ -105,20 +108,18 @@ void GenericPackage::initPackage(Package *package)
|
|||||||
package->addDirectoryDefinition("translations", "locale", i18n("Translations"));
|
package->addDirectoryDefinition("translations", "locale", i18n("Translations"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlasmoidPackage::initPackage(Package *package)
|
void PlasmoidPackage::initPackage(KPackage::Package *package)
|
||||||
{
|
{
|
||||||
GenericPackage::initPackage(package);
|
GenericPackage::initPackage(package);
|
||||||
package->setServicePrefix("plasma-applet-");
|
|
||||||
package->setDefaultPackageRoot(PLASMA_RELATIVE_DATA_INSTALL_DIR "/plasmoids/");
|
package->setDefaultPackageRoot(PLASMA_RELATIVE_DATA_INSTALL_DIR "/plasmoids/");
|
||||||
|
|
||||||
package->addFileDefinition("configmodel", "config/config.qml", i18n("Configuration UI pages model"));
|
package->addFileDefinition("configmodel", "config/config.qml", i18n("Configuration UI pages model"));
|
||||||
package->addFileDefinition("mainconfigxml", "config/main.xml", i18n("Configuration XML file"));
|
package->addFileDefinition("mainconfigxml", "config/main.xml", i18n("Configuration XML file"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataEnginePackage::initPackage(Package *package)
|
void DataEnginePackage::initPackage(KPackage::Package *package)
|
||||||
{
|
{
|
||||||
ChangeableMainScriptPackage::initPackage(package);
|
ChangeableMainScriptPackage::initPackage(package);
|
||||||
package->setServicePrefix("plasma-dataengine-");
|
|
||||||
package->setDefaultPackageRoot(PLASMA_RELATIVE_DATA_INSTALL_DIR "/dataengines/");
|
package->setDefaultPackageRoot(PLASMA_RELATIVE_DATA_INSTALL_DIR "/dataengines/");
|
||||||
|
|
||||||
package->addDirectoryDefinition("data", "data", i18n("Data Files"));
|
package->addDirectoryDefinition("data", "data", i18n("Data Files"));
|
||||||
@ -134,7 +135,7 @@ void DataEnginePackage::initPackage(Package *package)
|
|||||||
package->addDirectoryDefinition("translations", "locale", i18n("Translations"));
|
package->addDirectoryDefinition("translations", "locale", i18n("Translations"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThemePackage::initPackage(Package *package)
|
void ThemePackage::initPackage(KPackage::Package *package)
|
||||||
{
|
{
|
||||||
// by default the packages have "contents/" as contentsPrefixPaths
|
// by default the packages have "contents/" as contentsPrefixPaths
|
||||||
// but for the themes we don't want that, so unset it.
|
// but for the themes we don't want that, so unset it.
|
||||||
@ -234,7 +235,7 @@ void ThemePackage::initPackage(Package *package)
|
|||||||
package->setDefaultMimeTypes(mimetypes);
|
package->setDefaultMimeTypes(mimetypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainmentActionsPackage::initPackage(Package *package)
|
void ContainmentActionsPackage::initPackage(KPackage::Package *package)
|
||||||
{
|
{
|
||||||
ChangeableMainScriptPackage::initPackage(package);
|
ChangeableMainScriptPackage::initPackage(package);
|
||||||
package->setDefaultPackageRoot(PLASMA_RELATIVE_DATA_INSTALL_DIR "/containmentactions/");
|
package->setDefaultPackageRoot(PLASMA_RELATIVE_DATA_INSTALL_DIR "/containmentactions/");
|
||||||
|
@ -20,50 +20,58 @@
|
|||||||
#ifndef LIBS_PLASMA_PACKAGES_P_H
|
#ifndef LIBS_PLASMA_PACKAGES_P_H
|
||||||
#define LIBS_PLASMA_PACKAGES_P_H
|
#define LIBS_PLASMA_PACKAGES_P_H
|
||||||
|
|
||||||
#include "packagestructure.h"
|
|
||||||
#include "plasma.h"
|
#include "plasma.h"
|
||||||
|
|
||||||
|
#include <kpackage/package.h>
|
||||||
|
#include <kpackage/packagestructure.h>
|
||||||
|
|
||||||
namespace Plasma
|
namespace Plasma
|
||||||
{
|
{
|
||||||
|
|
||||||
class ChangeableMainScriptPackage : public PackageStructure
|
class ChangeableMainScriptPackage : public KPackage::PackageStructure
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
void initPackage(Package *package);
|
void initPackage(KPackage::Package *package);
|
||||||
|
void pathChanged(KPackage::Package *package);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QString mainScriptConfigKey() const;
|
virtual QString mainScriptConfigKey() const;
|
||||||
void pathChanged(Package *package);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class GenericPackage : public ChangeableMainScriptPackage
|
class GenericPackage : public ChangeableMainScriptPackage
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
void initPackage(Package *package);
|
void initPackage(KPackage::Package *package);
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlasmoidPackage : public GenericPackage
|
class PlasmoidPackage : public GenericPackage
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
void initPackage(Package *package);
|
void initPackage(KPackage::Package *package);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DataEnginePackage : public ChangeableMainScriptPackage
|
class DataEnginePackage : public ChangeableMainScriptPackage
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
void initPackage(Package *package);
|
void initPackage(KPackage::Package *package);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThemePackage : public PackageStructure
|
class ThemePackage : public KPackage::PackageStructure
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
void initPackage(Package *package);
|
void initPackage(KPackage::Package *package);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContainmentActionsPackage : public ChangeableMainScriptPackage
|
class ContainmentActionsPackage : public ChangeableMainScriptPackage
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
void initPackage(Package *package);
|
void initPackage(KPackage::Package *package);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Plasma
|
} // namespace Plasma
|
||||||
|
71
src/plasma/private/packagestructure_p.h
Normal file
71
src/plasma/private/packagestructure_p.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl>
|
||||||
|
* Copyright 2014 Marco Martin <mart@kde.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Library General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this program; if not, write to the
|
||||||
|
* Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PLASMA_PACKAGESTRUCTURE_P_H
|
||||||
|
#define PLASMA_PACKAGESTRUCTURE_P_H
|
||||||
|
|
||||||
|
#include "../packagestructure.h"
|
||||||
|
|
||||||
|
#include <kpackage/package.h>
|
||||||
|
#include <kpackage/packagestructure.h>
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
|
namespace Plasma
|
||||||
|
{
|
||||||
|
|
||||||
|
class PackageStructureWrapper : public KPackage::PackageStructure {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PackageStructureWrapper(Plasma::PackageStructure *structure, QObject *parent = 0, const QVariantList &args = QVariantList());
|
||||||
|
|
||||||
|
~PackageStructureWrapper();
|
||||||
|
|
||||||
|
virtual void initPackage(KPackage::Package *package);
|
||||||
|
|
||||||
|
virtual void pathChanged(KPackage::Package *package);
|
||||||
|
|
||||||
|
virtual KJob *install(KPackage::Package *package, const QString &archivePath, const QString &packageRoot);
|
||||||
|
virtual KJob *uninstall(KPackage::Package *package, const QString &packageRoot);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointer<Plasma::PackageStructure> m_struct;
|
||||||
|
static QHash<KPackage::Package *, Plasma::Package *> s_packagesMap;
|
||||||
|
friend class Package;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PackageStructurePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PackageStructurePrivate(PackageStructure *str)
|
||||||
|
: internalStructure(0),
|
||||||
|
q(str)
|
||||||
|
{}
|
||||||
|
~PackageStructurePrivate()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void installPathChanged(const QString &path);
|
||||||
|
|
||||||
|
PackageStructure *q;
|
||||||
|
KPackage::PackageStructure *internalStructure;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -91,6 +91,7 @@ QUrl PackageUrlInterceptor::intercept(const QUrl &path, QQmlAbstractUrlIntercept
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//should never happen
|
//should never happen
|
||||||
Q_ASSERT(!relativePath.isEmpty());
|
Q_ASSERT(!relativePath.isEmpty());
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user