heuristic for finding out what package we want

based on the absolute path requested

Change-Id: Ie99bfdc322a409e7ef275499eb8b254d834a98b7
This commit is contained in:
Marco Martin 2015-05-11 11:49:37 +02:00
parent f9e61de51b
commit ac2f76d9c8
4 changed files with 74 additions and 25 deletions

View File

@ -46,6 +46,9 @@ Comment[zh_TW]=Plasma 小程式
[PropertyDef::X-Plasma-API]
Type=QString
[PropertyDef::X-Plasma-MinimumAPIVersion]
Type=int
[PropertyDef::X-Plasma-RootPath]
Type=QString

View File

@ -53,6 +53,8 @@ AppletQuickItemPrivate::AppletQuickItemPrivate(Plasma::Applet *a, AppletQuickIte
{
if (!s_engine) {
s_engine = new QQmlEngine;
PackageUrlInterceptor *interceptor = new PackageUrlInterceptor(s_engine, Plasma::Package());
s_engine->setUrlInterceptor(interceptor);
}
}
@ -450,11 +452,13 @@ void AppletQuickItem::init()
//Initialize the main QML file
QQmlEngine *engine = d->qmlObject->engine();
//TODO: fallback to one engine per applet
/*
if (d->applet->package().isValid()) {
PackageUrlInterceptor *interceptor = new PackageUrlInterceptor(engine, d->applet->package());
interceptor->addAllowedPath(d->coronaPackage.path());
engine->setUrlInterceptor(interceptor);
}
}*/
//Force QtQuickControls to use the "Plasma" style for this engine.
//this way is possible to mix QtQuickControls and plasma components in applets

View File

@ -24,17 +24,36 @@
#include <QFile>
#include <QStandardPaths>
#include <Plasma/PluginLoader>
#include <kdeclarative/kdeclarative.h>
namespace PlasmaQuick
{
class PackageUrlInterceptorPrivate {
public:
PackageUrlInterceptorPrivate(QQmlEngine *engine, const Plasma::Package &p)
: package(p),
engine(engine)
{
}
Plasma::Package package;
QStringList allowedPaths;
QQmlEngine *engine;
static QHash<QString, Plasma::Package> s_packages;
};
QHash<QString, Plasma::Package> PackageUrlInterceptorPrivate::s_packages = QHash<QString, Plasma::Package>();
PackageUrlInterceptor::PackageUrlInterceptor(QQmlEngine *engine, const Plasma::Package &p)
: QQmlAbstractUrlInterceptor(),
m_package(p),
m_engine(engine)
d(new PackageUrlInterceptorPrivate(engine, p))
{
//m_allowedPaths << m_engine->importPathList();
//d->allowedPaths << d->engine->importPathList();
}
PackageUrlInterceptor::~PackageUrlInterceptor()
@ -43,29 +62,52 @@ PackageUrlInterceptor::~PackageUrlInterceptor()
void PackageUrlInterceptor::addAllowedPath(const QString &path)
{
m_allowedPaths << path;
d->allowedPaths << path;
}
void PackageUrlInterceptor::removeAllowedPath(const QString &path)
{
m_allowedPaths.removeAll(path);
d->allowedPaths.removeAll(path);
}
QStringList PackageUrlInterceptor::allowedPaths() const
{
return m_allowedPaths;
return d->allowedPaths;
}
QUrl PackageUrlInterceptor::intercept(const QUrl &path, QQmlAbstractUrlInterceptor::DataType type)
{
//qDebug() << "Intercepted URL:" << path << type;
QString pkgRoot;
Plasma::Package package;
if (d->package.isValid()) {
package = d->package;
} else {
foreach (const QString &base, QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) {
pkgRoot = base + "/plasma/plasmoids/";
if (path.path().startsWith(pkgRoot)) {
const QString pkgName = path.path().mid(pkgRoot.length()).split('/').first();
if (PackageUrlInterceptorPrivate::s_packages.contains(pkgName)) {
package = PackageUrlInterceptorPrivate::s_packages.value(pkgName);
} else {
package = Plasma::PluginLoader::self()->loadPackage("Plasma/Applet");
package.setPath(pkgName);
PackageUrlInterceptorPrivate::s_packages[pkgName] = package;
}
break;
}
}
}
if (!package.isValid()) {
return path;
}
if (path.scheme() == QStringLiteral("plasmapackage")) {
if (d->package.isValid() && path.scheme() == QStringLiteral("plasmapackage")) {
//FIXME: this is incorrect but works around a bug in qml in resolution of urls of qmldir files
if (type == QQmlAbstractUrlInterceptor::QmldirFile) {
return QUrl(m_package.filePath(0, path.path()));
return QUrl(d->package.filePath(0, path.path()));
} else {
return QUrl::fromLocalFile(m_package.filePath(0, path.path()));
return QUrl::fromLocalFile(d->package.filePath(0, path.path()));
}
}
@ -80,13 +122,13 @@ QUrl PackageUrlInterceptor::intercept(const QUrl &path, QQmlAbstractUrlIntercept
}
//asked a file inside a package: let's rewrite the url!
if (path.path().startsWith(m_package.path())) {
if (path.path().startsWith(package.path())) {
//qDebug() << "Found URL in package" << path;
//tries to isolate the relative path asked relative to the contentsPrefixPath: like ui/foo.qml
QString relativePath;
foreach (const QString &prefix, m_package.contentsPrefixPaths()) {
QString root = m_package.path() + prefix;
foreach (const QString &prefix, package.contentsPrefixPaths()) {
QString root = package.path() + prefix;
if (path.path().startsWith(root)) {
//obtain a string in the form ui/foo/bar/baz.qml
relativePath = path.path().mid(root.length());
@ -105,9 +147,9 @@ QUrl PackageUrlInterceptor::intercept(const QUrl &path, QQmlAbstractUrlIntercept
//obtain a string in the form foo/bar/baz.qml: ui/ gets discarded
const QString &filename = components.join("/");
//qDebug() << "Returning" << QUrl::fromLocalFile(m_package.filePath(prefixForType(type, filename), filename));
//qDebug() << "Returning" << QUrl::fromLocalFile(package.filePath(prefixForType(type, filename), filename));
QUrl ret = QUrl::fromLocalFile(m_package.filePath(prefixForType(type, filename), filename));
QUrl ret = QUrl::fromLocalFile(package.filePath(prefixForType(type, filename), filename));
if (ret.path().isEmpty()) {
return path;
@ -116,15 +158,15 @@ QUrl PackageUrlInterceptor::intercept(const QUrl &path, QQmlAbstractUrlIntercept
//forbid to load random absolute paths
} else {
if (m_package.allowExternalPaths() || m_package.metadata().property("X-Plasma-RequiredExtensions").toString().contains(QStringLiteral("ExternalScripts"))) {
if (package.allowExternalPaths() || package.metadata().property("X-Plasma-RequiredExtensions").toString().contains(QStringLiteral("ExternalScripts"))) {
return path;
}
//NOTE: It's needed to build this on the fly because importPathList
//can change at runtime
QStringList allowedPaths;
allowedPaths << m_engine->importPathList();
allowedPaths << m_allowedPaths;
allowedPaths << d->engine->importPathList();
allowedPaths << d->allowedPaths;
foreach (const QString &allowed, allowedPaths) {
//It's a private import
@ -132,7 +174,7 @@ QUrl PackageUrlInterceptor::intercept(const QUrl &path, QQmlAbstractUrlIntercept
QString pathCheck(path.path());
pathCheck = pathCheck.replace(QRegExp(".*org/kde/plasma/private/(.*)/.*"), "org.kde.plasma.\\1");
if (pathCheck == m_package.metadata().pluginName() || allowed.contains(pathCheck)) {
if (pathCheck == package.metadata().pluginName() || allowed.contains(pathCheck)) {
return path;
} else {
continue;
@ -144,12 +186,12 @@ QUrl PackageUrlInterceptor::intercept(const QUrl &path, QQmlAbstractUrlIntercept
return path;
}
}
qWarning() << "WARNING: Access denied for URL" << path << m_package.path();
return path;
qWarning() << "WARNING: Access denied for URL" << path << package.path();
return QUrl::fromLocalFile( allowedPaths.first() + "/org/kde/plasma/accessdenied/qmldir");
}
qWarning() << "WARNING: Access denied for URL" << path << m_package.path();
qWarning() << "WARNING: Access denied for URL" << path << package.path();
return QUrl();
}

View File

@ -42,6 +42,8 @@ class QQmlEngine;
namespace PlasmaQuick
{
class PackageUrlInterceptorPrivate;
//depends from https://codereview.qt-project.org/#change,65626
class PLASMAQUICK_EXPORT PackageUrlInterceptor: public QQmlAbstractUrlInterceptor
{
@ -85,9 +87,7 @@ public:
}
private:
Plasma::Package m_package;
QStringList m_allowedPaths;
QQmlEngine *m_engine;
PackageUrlInterceptorPrivate *const d;
};
}