diff --git a/src/scriptengines/qml/declarative/qmlobject.cpp b/src/scriptengines/qml/declarative/qmlobject.cpp index 238989fbd..2163b3ddb 100644 --- a/src/scriptengines/qml/declarative/qmlobject.cpp +++ b/src/scriptengines/qml/declarative/qmlobject.cpp @@ -41,13 +41,13 @@ public: : q(parent), engine(0), component(0), - root(0), delay(false) { } ~QmlObjectPrivate() { + delete root.data(); } void errorPrint(); @@ -67,7 +67,7 @@ public: QQmlEngine* engine; QQmlIncubator incubator; QQmlComponent* component; - QObject *root; + QWeakPointer root; bool delay : 1; }; @@ -95,8 +95,7 @@ void QmlObjectPrivate::execute(const QString &fileName) delete component; component = new QQmlComponent(engine, q); - delete root; - root = 0; + delete root.data(); KDeclarative kdeclarative; kdeclarative.setDeclarativeEngine(engine); @@ -168,7 +167,7 @@ QQmlEngine* QmlObject::engine() QObject *QmlObject::rootObject() const { - return d->root; + return d->root.data(); } QQmlComponent *QmlObject::mainComponent() const diff --git a/src/scriptengines/qml/plasmoid/appletinterface.cpp b/src/scriptengines/qml/plasmoid/appletinterface.cpp index 721a7fe9e..b43323cc4 100644 --- a/src/scriptengines/qml/plasmoid/appletinterface.cpp +++ b/src/scriptengines/qml/plasmoid/appletinterface.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -35,14 +36,18 @@ #include #include #include +#include #include #include #include #include +#include #include "containmentinterface.h" #include "declarative/configpropertymap.h" +#include "declarative/qmlobject.h" +#include "declarative/packageaccessmanagerfactory.h" Q_DECLARE_METATYPE(AppletInterface*) @@ -68,41 +73,103 @@ AppletInterface::AppletInterface(DeclarativeAppletScript *script, QQuickItem *pa this, SIGNAL(locationChanged())); connect(m_appletScriptEngine, SIGNAL(contextChanged()), this, SIGNAL(contextChanged())); - + + m_qmlObject = new QmlObject(this); + m_qmlObject->setInitializationDelayed(true); + m_creationTimer = new QTimer(this); m_creationTimer->setSingleShot(true); - connect(m_creationTimer, &QTimer::timeout, m_appletScriptEngine, &DeclarativeAppletScript::delayedInit); + connect(m_creationTimer, &QTimer::timeout, this, &AppletInterface::init); } AppletInterface::~AppletInterface() { } -void AppletInterface::setUiObject(QObject *object) +void AppletInterface::init() { - if (m_uiObject.data() == object) { + if (m_qmlObject->rootObject()) { return; } - m_uiObject = object; + //use our own custom network access manager that will access Plasma packages and to manage security (i.e. deny access to remote stuff when the proper extension isn't enabled + QQmlEngine *engine = m_qmlObject->engine(); + QQmlNetworkAccessManagerFactory *factory = engine->networkAccessManagerFactory(); + engine->setNetworkAccessManagerFactory(0); + delete factory; + engine->setNetworkAccessManagerFactory(new PackageAccessManagerFactory(m_appletScriptEngine->package())); + + m_qmlObject->setQmlPath(m_appletScriptEngine->mainScript()); + + + if (!m_qmlObject->engine() || !m_qmlObject->engine()->rootContext() || !m_qmlObject->engine()->rootContext()->isValid() || m_qmlObject->mainComponent()->isError()) { + QString reason; + foreach (QQmlError error, m_qmlObject->mainComponent()->errors()) { + reason += error.toString()+'\n'; + } + reason = i18n("Error loading QML file: %1", reason); + + m_qmlObject->setQmlPath(applet()->containment()->corona()->package().filePath("ui", "AppletError.qml")); + m_qmlObject->completeInitialization(); + + + //even the error message QML may fail + if (m_qmlObject->mainComponent()->isError()) { + return; + } else { + m_qmlObject->rootObject()->setProperty("reason", reason); + } + + m_appletScriptEngine->setLaunchErrorMessage(reason); + } + + + m_qmlObject->engine()->rootContext()->setContextProperty("plasmoid", this); + + m_qmlObject->completeInitialization(); + + qDebug() << "Graphic object created:" << applet() << applet()->property("graphicObject"); + + //Create the ToolBox + Plasma::Containment *pc = qobject_cast(applet()); + if (pc) { + Plasma::Package pkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic"); + pkg.setPath("org.kde.toolbox"); + + if (pkg.isValid()) { + QQmlComponent *toolBoxComponent = new QQmlComponent(m_qmlObject->engine(), this); + toolBoxComponent->loadUrl(QUrl::fromLocalFile(pkg.filePath("mainscript"))); + QObject *toolBoxObject = toolBoxComponent->create(engine->rootContext()); + + QObject *containmentGraphicObject = m_qmlObject->rootObject(); + + if (containmentGraphicObject && toolBoxObject) { + //memory management + toolBoxComponent->setParent(toolBoxObject); + toolBoxObject->setProperty("parent", QVariant::fromValue(containmentGraphicObject)); + + containmentGraphicObject->setProperty("toolBox", QVariant::fromValue(toolBoxObject)); + } else { + delete toolBoxComponent; + delete toolBoxObject; + } + } else { + kWarning() << "Could not load org.kde.toolbox package."; + } + } //set parent, both as object hyerarchy and visually - object->setProperty("parent", QVariant::fromValue(this)); + m_qmlObject->rootObject()->setProperty("parent", QVariant::fromValue(this)); //set anchors - QQmlExpression expr(m_appletScriptEngine->engine()->rootContext(), object, "parent"); - QQmlProperty prop(object, "anchors.fill"); + QQmlExpression expr(m_qmlObject->engine()->rootContext(), m_qmlObject->rootObject(), "parent"); + QQmlProperty prop(m_qmlObject->rootObject(), "anchors.fill"); prop.write(expr.evaluate()); geometryChanged(QRectF(), QRectF(x(), y(), width(), height())); emit busyChanged(); } -QObject *AppletInterface::uiObject() const -{ - return m_uiObject.data(); -} - AppletInterface::FormFactor AppletInterface::formFactor() const { return static_cast(applet()->formFactor()); @@ -145,7 +212,7 @@ void AppletInterface::setTitle(const QString &title) bool AppletInterface::isBusy() const { - return !m_uiObject || m_busy; + return !m_qmlObject->rootObject() || m_busy; } void AppletInterface::setBusy(bool busy) @@ -435,7 +502,7 @@ void AppletInterface::geometryChanged(const QRectF &newGeometry, const QRectF &o QQuickItem::geometryChanged(newGeometry, oldGeometry); - if (!m_uiObject || qobject_cast(this)) { + if (!m_qmlObject->rootObject() || qobject_cast(this)) { return; } @@ -448,21 +515,21 @@ void AppletInterface::geometryChanged(const QRectF &newGeometry, const QRectF &o return; } - QQmlComponent *component = new QQmlComponent(m_appletScriptEngine->engine(), this); + QQmlComponent *component = new QQmlComponent(m_qmlObject->engine(), this); component->loadUrl(QUrl::fromLocalFile(applet()->containment()->corona()->package().filePath("ui", "CompactApplet.qml"))); - m_compactUiObject = component->create(m_appletScriptEngine->engine()->rootContext()); + m_compactUiObject = component->create(m_qmlObject->engine()->rootContext()); QObject *compactRepresentation = 0; //build the icon representation if (m_compactUiObject) { - QQmlComponent *compactComponent = m_uiObject.data()->property("compactRepresentation").value(); + QQmlComponent *compactComponent = m_qmlObject->rootObject()->property("compactRepresentation").value(); if (!compactComponent) { - compactComponent = new QQmlComponent(m_appletScriptEngine->engine(), this); + compactComponent = new QQmlComponent(m_qmlObject->engine(), this); compactComponent->loadUrl(QUrl::fromLocalFile(applet()->containment()->corona()->package().filePath("ui", "DefaultCompactRepresentation.qml"))); } - compactRepresentation = compactComponent->create(m_appletScriptEngine->engine()->rootContext()); + compactRepresentation = compactComponent->create(m_qmlObject->engine()->rootContext()); if (compactRepresentation) { compactComponent->setParent(compactRepresentation); } else { @@ -482,12 +549,12 @@ void AppletInterface::geometryChanged(const QRectF &newGeometry, const QRectF &o m_compactUiObject.data()->setProperty("visible", true); m_compactUiObject.data()->setProperty("parent", QVariant::fromValue(this)); //set anchors - QQmlExpression expr(m_appletScriptEngine->engine()->rootContext(), m_compactUiObject.data(), "parent"); + QQmlExpression expr(m_qmlObject->engine()->rootContext(), m_compactUiObject.data(), "parent"); QQmlProperty prop(m_compactUiObject.data(), "anchors.fill"); prop.write(expr.evaluate()); - m_uiObject.data()->setProperty("parent", QVariant::fromValue(m_compactUiObject.data())); - m_compactUiObject.data()->setProperty("applet", QVariant::fromValue(m_uiObject.data())); + m_qmlObject->rootObject()->setProperty("parent", QVariant::fromValue(m_compactUiObject.data())); + m_compactUiObject.data()->setProperty("applet", QVariant::fromValue(m_qmlObject->rootObject())); //failed to create UI, don't do anything, return in expanded status } else { @@ -507,7 +574,7 @@ void AppletInterface::geometryChanged(const QRectF &newGeometry, const QRectF &o return; } - m_uiObject.data()->setProperty("parent", QVariant::fromValue(this)); + m_qmlObject->rootObject()->setProperty("parent", QVariant::fromValue(this)); m_compactUiObject.data()->deleteLater(); } } @@ -516,8 +583,8 @@ void AppletInterface::itemChange(ItemChange change, const ItemChangeData &value) { if (change == QQuickItem::ItemSceneChange) { //we have a window: create the - if (value.window && !m_uiObject && !m_creationTimer->isActive()) { - m_appletScriptEngine->delayedInit(); + if (value.window && !m_qmlObject->rootObject() && !m_creationTimer->isActive()) { + init(); /*Experiment on even more delayed, doesn't seem to be good QTime time = QTime::currentTime(); @@ -530,4 +597,9 @@ void AppletInterface::itemChange(ItemChange change, const ItemChangeData &value) QQuickItem::itemChange(change, value); } +QmlObject *AppletInterface::qmlObject() +{ + return m_qmlObject; +} + #include "moc_appletinterface.cpp" diff --git a/src/scriptengines/qml/plasmoid/appletinterface.h b/src/scriptengines/qml/plasmoid/appletinterface.h index ccaefb9d8..c559bd5cf 100644 --- a/src/scriptengines/qml/plasmoid/appletinterface.h +++ b/src/scriptengines/qml/plasmoid/appletinterface.h @@ -37,6 +37,7 @@ class QSizeF; class ConfigPropertyMap; +class QmlObject; namespace Plasma { @@ -76,8 +77,7 @@ public: ~AppletInterface(); //API not intended for the QML part - void setUiObject(QObject *object); - QObject *uiObject() const; + QmlObject *qmlObject(); //------------------------------------------------------------------ //enums copy&pasted from plasma.h because qtscript is evil @@ -226,6 +226,10 @@ Q_SIGNALS: void busyChanged(); void expandedChanged(); +//it's important this slot is private because must not be invokable by qml +public Q_SLOTS: + void init(); + protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); void itemChange(ItemChange change, const ItemChangeData &value); @@ -242,7 +246,7 @@ private: ConfigPropertyMap *m_configuration; //UI-specific members ------------------ - QWeakPointer m_uiObject; + QmlObject *m_qmlObject; QWeakPointer m_compactUiObject; QTimer *m_creationTimer; diff --git a/src/scriptengines/qml/plasmoid/containmentinterface.cpp b/src/scriptengines/qml/plasmoid/containmentinterface.cpp index 9f9035718..231ed74e6 100644 --- a/src/scriptengines/qml/plasmoid/containmentinterface.cpp +++ b/src/scriptengines/qml/plasmoid/containmentinterface.cpp @@ -135,7 +135,7 @@ void ContainmentInterface::appletAddedForward(Plasma::Applet *applet) //if an appletGraphicObject is not set, we have to display some error message } else if (applet && contGraphicObject) { - QQmlComponent *component = new QQmlComponent(m_appletScriptEngine->engine(), applet); + QQmlComponent *component = new QQmlComponent(qmlObject()->engine(), applet); component->loadUrl(QUrl::fromLocalFile(containment()->corona()->package().filePath("ui", "AppletError.qml"))); QObject *errorUi = component->create(); @@ -180,7 +180,7 @@ void ContainmentInterface::loadWallpaper() m_wallpaperQmlObject->rootObject()->setProperty("parent", QVariant::fromValue(this)); //set anchors - QQmlExpression expr(m_appletScriptEngine->engine()->rootContext(), m_wallpaperQmlObject->rootObject(), "parent"); + QQmlExpression expr(qmlObject()->engine()->rootContext(), m_wallpaperQmlObject->rootObject(), "parent"); QQmlProperty prop(m_wallpaperQmlObject->rootObject(), "anchors.fill"); prop.write(expr.evaluate()); diff --git a/src/scriptengines/qml/plasmoid/declarativeappletscript.cpp b/src/scriptengines/qml/plasmoid/declarativeappletscript.cpp index c9d00ab58..ffc2478c2 100644 --- a/src/scriptengines/qml/plasmoid/declarativeappletscript.cpp +++ b/src/scriptengines/qml/plasmoid/declarativeappletscript.cpp @@ -55,7 +55,6 @@ K_EXPORT_PLASMA_APPLETSCRIPTENGINE(declarativeappletscript, DeclarativeAppletScr DeclarativeAppletScript::DeclarativeAppletScript(QObject *parent, const QVariantList &args) : Plasma::AppletScript(parent), - m_qmlObject(0), m_interface(0) { qmlRegisterType(); @@ -68,6 +67,13 @@ DeclarativeAppletScript::~DeclarativeAppletScript() bool DeclarativeAppletScript::init() { + //FIXME: what replaced this? + //KGlobal::locale()->insertCatalog("plasma_applet_" % description().pluginName()); + + //make possible to import extensions from the package + //FIXME: probably to be removed, would make possible to use native code from within the package :/ + //m_interface->qmlObject()->engine()->addImportPath(package()->path()+"/contents/imports"); + Plasma::Applet *a = applet(); Plasma::Containment *pc = qobject_cast(a); @@ -100,93 +106,11 @@ bool DeclarativeAppletScript::init() //FIXME: everything should be delayed if (pc) { - delayedInit(); + m_interface->init(); } return true; } -bool DeclarativeAppletScript::delayedInit() -{ - m_qmlObject = new QmlObject(applet()); - m_qmlObject->setInitializationDelayed(true); - //FIXME: what replaced this? - //KGlobal::locale()->insertCatalog("plasma_applet_" % description().pluginName()); - - //make possible to import extensions from the package - //FIXME: probably to be removed, would make possible to use native code from within the package :/ - //m_qmlObject->engine()->addImportPath(package()->path()+"/contents/imports"); - - //use our own custom network access manager that will access Plasma packages and to manage security (i.e. deny access to remote stuff when the proper extension isn't enabled - QQmlEngine *engine = m_qmlObject->engine(); - QQmlNetworkAccessManagerFactory *factory = engine->networkAccessManagerFactory(); - engine->setNetworkAccessManagerFactory(0); - delete factory; - engine->setNetworkAccessManagerFactory(new PackageAccessManagerFactory(package())); - - m_qmlObject->setQmlPath(mainScript()); - - - if (!m_qmlObject->engine() || !m_qmlObject->engine()->rootContext() || !m_qmlObject->engine()->rootContext()->isValid() || m_qmlObject->mainComponent()->isError()) { - QString reason; - foreach (QQmlError error, m_qmlObject->mainComponent()->errors()) { - reason += error.toString()+'\n'; - } - reason = i18n("Error loading QML file: %1", reason); - - m_qmlObject->setQmlPath(applet()->containment()->corona()->package().filePath("ui", "AppletError.qml")); - m_qmlObject->completeInitialization(); - - - //even the error message QML may fail - if (m_qmlObject->mainComponent()->isError()) { - return false; - } else { - m_qmlObject->rootObject()->setProperty("reason", reason); - } - - setLaunchErrorMessage(reason); - } - - - setupObjects(); - - m_qmlObject->completeInitialization(); - - m_interface->setUiObject(m_qmlObject->rootObject()); - - qDebug() << "Graphic object created:" << applet() << applet()->property("graphicObject"); - - //Create the ToolBox - Plasma::Containment *pc = qobject_cast(applet()); - if (pc) { - Plasma::Package pkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic"); - pkg.setPath("org.kde.toolbox"); - - if (pkg.isValid()) { - QQmlComponent *toolBoxComponent = new QQmlComponent(m_qmlObject->engine(), this); - toolBoxComponent->loadUrl(QUrl::fromLocalFile(pkg.filePath("mainscript"))); - QObject *toolBoxObject = toolBoxComponent->create(engine->rootContext()); - - QObject *containmentGraphicObject = m_interface->uiObject(); - - if (containmentGraphicObject && toolBoxObject) { - //memory management - toolBoxComponent->setParent(toolBoxObject); - toolBoxObject->setProperty("parent", QVariant::fromValue(containmentGraphicObject)); - - containmentGraphicObject->setProperty("toolBox", QVariant::fromValue(toolBoxObject)); - } else { - delete toolBoxComponent; - delete toolBoxObject; - } - } else { - kWarning() << "Could not load org.kde.toolbox package."; - } - } - - return !applet()->failedToLaunch(); -} - QString DeclarativeAppletScript::filePath(const QString &type, const QString &file) const { return package().filePath(type.toLocal8Bit().constData(), file); @@ -248,8 +172,8 @@ TODO: callEventListeners is broken without qscriptengine void DeclarativeAppletScript::executeAction(const QString &name) { - if (m_qmlObject->rootObject()) { - QMetaObject::invokeMethod(m_qmlObject->rootObject(), QString("action_" + name).toLatin1(), Qt::DirectConnection); + if (m_interface->qmlObject()->rootObject()) { + QMetaObject::invokeMethod(m_interface->qmlObject()->rootObject(), QString("action_" + name).toLatin1(), Qt::DirectConnection); } } @@ -261,76 +185,6 @@ bool DeclarativeAppletScript::include(const QString &path) return false; } -void DeclarativeAppletScript::setupObjects() -{ - m_qmlObject->engine()->rootContext()->setContextProperty("plasmoid", m_interface); - -#if 0 -TODO: make this work with QQmlEngine - m_engine = m_qmlObject->scriptEngine(); - if (!m_engine) { - return; - } - - connect(m_engine, SIGNAL(signalHandlerException(const QScriptValue &)), - this, SLOT(signalHandlerException(const QScriptValue &))); - - delete m_env; - m_env = new ScriptEnv(this, m_engine); - - QScriptValue global = m_engine->globalObject(); - - QScriptValue v = m_engine->newVariant(QVariant::fromValue(*applet()->package())); - global.setProperty("__plasma_package", v, - QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); - - m_self = m_engine->newQObject(m_interface); - m_self.setScope(global); - global.setProperty("plasmoid", m_self); - m_env->addMainObjectProperties(m_self); - - QScriptValue args = m_engine->newArray(); - int i = 0; - foreach (const QVariant &arg, applet()->startupArguments()) { - args.setProperty(i, m_engine->newVariant(arg)); - ++i; - } - global.setProperty("startupArguments", args); - - // Add a global loadui method for ui files - QScriptValue fun = m_engine->newFunction(DeclarativeAppletScript::loadui); - global.setProperty("loadui", fun); - - ScriptEnv::registerEnums(global, AppletInterface::staticMetaObject); - //Make enum values accessible also as plasmoid.Planar etc - ScriptEnv::registerEnums(m_self, AppletInterface::staticMetaObject); - - global.setProperty("service", m_engine->newFunction(DeclarativeAppletScript::service)); - global.setProperty("loadService", m_engine->newFunction(DeclarativeAppletScript::loadService)); - - //Add stuff from Qt - //TODO: move to libkdeclarative? - ByteArrayClass *baClass = new ByteArrayClass(m_engine); - global.setProperty("ByteArray", baClass->constructor()); - global.setProperty("QPoint", constructQPointClass(m_engine)); - - // Add stuff from KDE libs - qScriptRegisterSequenceMetaType(m_engine); - global.setProperty("Url", constructKUrlClass(m_engine)); - - // Add stuff from Plasma - global.setProperty("Svg", m_engine->newFunction(DeclarativeAppletScript::newPlasmaSvg)); - global.setProperty("FrameSvg", m_engine->newFunction(DeclarativeAppletScript::newPlasmaFrameSvg)); - - if (!m_env->importExtensions(description(), m_self, m_auth)) { - return; - } - - registerSimpleAppletMetaTypes(m_engine); - QTimer::singleShot(0, this, SLOT(configChanged())); -#endif -} - QObject *DeclarativeAppletScript::loadService(const QString &pluginName) { return Plasma::PluginLoader::self()->loadService(pluginName, QVariantList(), applet()); @@ -345,11 +199,6 @@ QList DeclarativeAppletScript::contextualActions() return m_interface->contextualActions(); } -QQmlEngine *DeclarativeAppletScript::engine() const -{ - return m_qmlObject->engine(); -} - #include "declarativeappletscript.moc" diff --git a/src/scriptengines/qml/plasmoid/declarativeappletscript.h b/src/scriptengines/qml/plasmoid/declarativeappletscript.h index b4fa1adb5..3473ab889 100644 --- a/src/scriptengines/qml/plasmoid/declarativeappletscript.h +++ b/src/scriptengines/qml/plasmoid/declarativeappletscript.h @@ -47,7 +47,6 @@ public: bool include(const QString &path); - QQmlEngine *engine() const; static QObject *loadui(const QString &filename); QObject *loadService(const QString &pluginName); @@ -56,11 +55,9 @@ public Q_SLOTS: void executeAction(const QString &name); void activate(); void configChanged(); - bool delayedInit(); protected: bool init(); - void setupObjects(); Q_SIGNALS: void formFactorChanged(); @@ -68,8 +65,8 @@ Q_SIGNALS: void contextChanged(); private: - QmlObject *m_qmlObject; AppletInterface *m_interface; + friend class AppletInterface; }; #endif