diff --git a/KF5PlasmaMacros.cmake b/KF5PlasmaMacros.cmake --- a/KF5PlasmaMacros.cmake +++ b/KF5PlasmaMacros.cmake @@ -30,7 +30,7 @@ set(type applet) endif() - kpackage_install_package(${dir} ${component} ${root} ${PLASMA_RELATIVE_DATA_INSTALL_DIR}) + kpackage_install_bundled_package(${dir} ${component} ${root} ${PLASMA_RELATIVE_DATA_INSTALL_DIR}) install(FILES ${dir}/metadata.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} RENAME plasma-${type}-${component}.desktop) endmacro() diff --git a/autotests/configmodeltest.cpp b/autotests/configmodeltest.cpp --- a/autotests/configmodeltest.cpp +++ b/autotests/configmodeltest.cpp @@ -41,7 +41,7 @@ qmlRegisterType("org.kde.plasma.configuration", 2, 0, "ConfigCategory"); QQmlEngine engine; - QQmlComponent *component = new QQmlComponent(&engine, QUrl::fromLocalFile(applet->package().filePath("configmodel")), this); + QQmlComponent *component = new QQmlComponent(&engine, applet->kPackage().fileUrl("configmodel"), this); QObject *object = component->create(engine.rootContext()); PlasmaQuick::ConfigModel *configModel = qobject_cast(object); diff --git a/examples/shell/customcorona.cpp b/examples/shell/customcorona.cpp --- a/examples/shell/customcorona.cpp +++ b/examples/shell/customcorona.cpp @@ -38,7 +38,7 @@ qmlRegisterUncreatableType("org.kde.plasma.shell", 2, 0, "Desktop", QStringLiteral("It is not possible to create objects of type Desktop")); m_view = new PlasmaQuick::ContainmentView(this); - m_view->setSource(QUrl::fromLocalFile(package.filePath("views", QStringLiteral("Desktop.qml")))); + m_view->setSource(package.fileUrl("views", QStringLiteral("Desktop.qml"))); m_view->show(); load(); diff --git a/src/plasmaquick/appletquickitem.cpp b/src/plasmaquick/appletquickitem.cpp --- a/src/plasmaquick/appletquickitem.cpp +++ b/src/plasmaquick/appletquickitem.cpp @@ -519,7 +519,7 @@ engine->setProperty(("_plasma_qqc_style_set"), true); } - d->qmlObject->setSource(QUrl::fromLocalFile(d->applet->kPackage().filePath("mainscript"))); + d->qmlObject->setSource(d->applet->kPackage().fileUrl("mainscript")); if (!engine || !engine->rootContext() || !engine->rootContext()->isValid() || !d->qmlObject->mainComponent() || d->qmlObject->mainComponent()->isError() || d->applet->failedToLaunch()) { QString reason; @@ -534,7 +534,7 @@ reason = i18n("Error loading Applet: package inexistent. %1", applet()->launchErrorMessage()); } - d->qmlObject->setSource(QUrl::fromLocalFile(d->coronaPackage.filePath("appleterror"))); + d->qmlObject->setSource(d->coronaPackage.fileUrl("appleterror")); d->qmlObject->completeInitialization(); //even the error message QML may fail @@ -579,20 +579,20 @@ //default compactRepresentation is a simple icon provided by the shell package if (!d->compactRepresentation) { d->compactRepresentation = new QQmlComponent(engine, this); - d->compactRepresentation->loadUrl(QUrl::fromLocalFile(d->coronaPackage.filePath("defaultcompactrepresentation"))); + d->compactRepresentation->loadUrl(d->coronaPackage.fileUrl("defaultcompactrepresentation")); emit compactRepresentationChanged(d->compactRepresentation); } //default compactRepresentationExpander is the popup in which fullRepresentation goes if (!d->compactRepresentationExpander) { d->compactRepresentationExpander = new QQmlComponent(engine, this); - QString compactExpanderPath = d->containmentPackage.filePath("compactapplet"); + QUrl compactExpanderUrl = d->containmentPackage.fileUrl("compactapplet"); - if (compactExpanderPath.isEmpty()) { - compactExpanderPath = d->coronaPackage.filePath("compactapplet"); + if (compactExpanderUrl.isEmpty()) { + compactExpanderUrl = d->coronaPackage.fileUrl("compactapplet"); } - d->compactRepresentationExpander->loadUrl(QUrl::fromLocalFile(compactExpanderPath)); + d->compactRepresentationExpander->loadUrl(compactExpanderUrl); } d->compactRepresentationCheck(); @@ -674,7 +674,7 @@ QObject *AppletQuickItem::testItem() { if (!d->testItem) { - const QUrl url = QUrl::fromLocalFile(d->appletPackage.filePath("test")); + const QUrl url(d->appletPackage.fileUrl("test")); if (url.isEmpty()) { return nullptr; } diff --git a/src/plasmaquick/configmodel.cpp b/src/plasmaquick/configmodel.cpp --- a/src/plasmaquick/configmodel.cpp +++ b/src/plasmaquick/configmodel.cpp @@ -239,7 +239,7 @@ if (d->appletInterface && !source.isEmpty() && !(source.startsWith(QLatin1Char('/')) && source.endsWith(QLatin1String("qml")))) { if(!d->appletInterface.data()->kPackage().isValid()) qWarning() << "wrong applet" << d->appletInterface.data()->pluginMetaData().name(); - return QUrl::fromLocalFile(d->appletInterface.data()->kPackage().filePath("ui", source)); + return d->appletInterface.data()->kPackage().fileUrl("ui", source); } else { return source; } diff --git a/src/plasmaquick/configview.cpp b/src/plasmaquick/configview.cpp --- a/src/plasmaquick/configview.cpp +++ b/src/plasmaquick/configview.cpp @@ -133,7 +133,7 @@ q->setResizeMode(QQuickView::SizeViewToRootObject); //config model local of the applet - QQmlComponent *component = new QQmlComponent(q->engine(), QUrl::fromLocalFile(applet.data()->kPackage().filePath("configmodel")), q); + QQmlComponent *component = new QQmlComponent(q->engine(), applet.data()->kPackage().fileUrl("configmodel"), q); QObject *object = component->beginCreate(q->engine()->rootContext()); configModel = qobject_cast(object); @@ -298,7 +298,7 @@ void ConfigView::init() { - setSource(QUrl::fromLocalFile(d->corona->kPackage().filePath("appletconfigurationui"))); + setSource(d->corona->kPackage().fileUrl("appletconfigurationui")); } Plasma::Applet *ConfigView::applet() diff --git a/src/plasmaquick/packageurlinterceptor.h b/src/plasmaquick/packageurlinterceptor.h --- a/src/plasmaquick/packageurlinterceptor.h +++ b/src/plasmaquick/packageurlinterceptor.h @@ -66,7 +66,7 @@ case QQmlAbstractUrlInterceptor::QmlFile: return QByteArray("ui"); case QQmlAbstractUrlInterceptor::JavaScriptFile: - return QByteArray("scripts"); + return QByteArray("code"); default: break; } @@ -80,8 +80,8 @@ return QByteArray("images"); //FIXME: are those necessary? are they *always* catched by type? } else if (extension == QStringLiteral("js")) { - return QByteArray("scripts"); - } else if (extension == QStringLiteral("qml")) { + return QByteArray("code"); + } else if (extension == QStringLiteral("qml") || extension == QStringLiteral("qmldir")) { return QByteArray("ui"); //everything else, throw it in "data" } else { diff --git a/src/plasmaquick/packageurlinterceptor.cpp b/src/plasmaquick/packageurlinterceptor.cpp --- a/src/plasmaquick/packageurlinterceptor.cpp +++ b/src/plasmaquick/packageurlinterceptor.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -46,14 +47,8 @@ QStringList allowedPaths; QQmlEngine *engine; bool forcePlasmaStyle = false; - - //FIXME: those are going to be stuffed here and stay.. - // they should probably be removed when the last applet of that type is removed - static QHash s_packages; }; -QHash PackageUrlInterceptorPrivate::s_packages = QHash(); - PackageUrlInterceptor::PackageUrlInterceptor(QQmlEngine *engine, const KPackage::Package &p) : QQmlAbstractUrlInterceptor(), @@ -96,86 +91,26 @@ { //qDebug() << "Intercepted URL:" << path << type; - if (d->forcePlasmaStyle && path.path().contains(QLatin1String("Controls.2/org.kde.desktop/"))) { - return QUrl::fromLocalFile(path.path().replace(QLatin1String("Controls.2/org.kde.desktop/"), QLatin1String("Controls.2/Plasma/"))); - } - QString pkgRoot; - KPackage::Package package; - if (d->package.isValid()) { - package = d->package; - } else { - foreach (const QString &base, QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) { - pkgRoot = QFileInfo(base + QStringLiteral("/plasma/plasmoids/")).canonicalFilePath(); - if (!pkgRoot.isEmpty() && path.path().startsWith(pkgRoot)) { - const QString pkgName = path.path().midRef(pkgRoot.length() + 1).split(QLatin1Char('/')).first().toString(); - - auto it = PackageUrlInterceptorPrivate::s_packages.constFind(pkgName); - if (it != PackageUrlInterceptorPrivate::s_packages.constEnd()) { - package = *it; - } else { - package = Plasma::PluginLoader::self()->loadPackage(QStringLiteral("Plasma/Applet")).kPackage(); - package.setPath(pkgName); - PackageUrlInterceptorPrivate::s_packages[pkgName] = package; - } - break; - } - } - } - if (!package.isValid()) { + //we assume we never rewritten qml/qmldir files + if (path.path().endsWith(QStringLiteral("qml")) || path.path().endsWith(QStringLiteral("qmldir"))) { return path; } + const QString prefix = QString::fromUtf8(prefixForType(type, path.path())); + QRegularExpression match(QStringLiteral("/ui/(.*)")); - 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(d->package.filePath(0, path.path())); - } else { - return QUrl::fromLocalFile(d->package.filePath(0, path.path())); - } - } - - //TODO: security: permission for remote urls - if (!path.isLocalFile()) { - return path; - } + QString plainPath = path.toString(); + if (plainPath.contains(match)) { + QString rewritten = plainPath.replace(match, QStringLiteral("/%1/\\1").arg(prefix)); - //if is just a normal string, no qml file was asked, allow it - if (type == QQmlAbstractUrlInterceptor::UrlString) { - return path; - } - - //asked a file inside a package: let's rewrite the url! - 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, 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()); - break; - } - } - - //should never happen - Q_ASSERT(!relativePath.isEmpty()); - - const int firstSlash = relativePath.indexOf(QLatin1Char('/')) + 1; - const QString filename = firstSlash > 0 ? relativePath.mid(firstSlash) : relativePath; - const QUrl ret = QUrl::fromLocalFile(package.filePath(prefixForType(type, filename), filename)); - - //qDebug() << "Returning" << ret; - - if (ret.path().isEmpty()) { + //search it in a resource or as a file on disk + if (!(rewritten.contains(QStringLiteral("qrc")) && + QFile::exists(QStringLiteral(":") + QUrl(rewritten).path())) && + !QFile::exists(QUrl(rewritten).path())) { return path; } - return ret; - - //forbid to load random absolute paths + qWarning()<<"Warning: all files used by qml by the plasmoid should be in ui/. The file in the path" << rewritten << "was expected at" <createObjectFromSource(QUrl::fromLocalFile(pkg.filePath("mainscript")), 0, toolboxProperties); + QObject *toolBoxObject = qmlObject()->createObjectFromSource(pkg.fileUrl("mainscript"), 0, toolboxProperties); if (toolBoxObject && containmentGraphicObject) { containmentGraphicObject->setProperty("toolBox", QVariant::fromValue(toolBoxObject)); } diff --git a/src/scriptengines/qml/plasmoid/wallpaperinterface.cpp b/src/scriptengines/qml/plasmoid/wallpaperinterface.cpp --- a/src/scriptengines/qml/plasmoid/wallpaperinterface.cpp +++ b/src/scriptengines/qml/plasmoid/wallpaperinterface.cpp @@ -147,7 +147,7 @@ } m_qmlObject->rootContext()->setContextProperty(QStringLiteral("wallpaper"), this); - m_qmlObject->setSource(QUrl::fromLocalFile(m_pkg.filePath("mainscript"))); + m_qmlObject->setSource(m_pkg.fileUrl("mainscript")); const QString rootPath = m_pkg.metadata().value(QStringLiteral("X-Plasma-RootPath")); if (!rootPath.isEmpty()) {