diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,6 +35,7 @@ KF5::ItemViews # KWidgetItemDelegate KF5::XmlGui # KAboutApplicationDialog KF5::QuickAddons + KF5::Declarative KF5::Package ) set_target_properties(KF5KCMUtils PROPERTIES diff --git a/src/kcmoduleqml.cpp b/src/kcmoduleqml.cpp --- a/src/kcmoduleqml.cpp +++ b/src/kcmoduleqml.cpp @@ -39,21 +39,52 @@ class KCModuleQmlPrivate { public: - KCModuleQmlPrivate(KQuickAddons::ConfigModule *cm) - : quickWindow(nullptr), + KCModuleQmlPrivate(KQuickAddons::ConfigModule *cm, KCModuleQml *q) + : q(q), + quickWindow(nullptr), configModule(cm) { + //ensure the engine is present, then ref it + engine(); + engineRef = s_engine; } + ~KCModuleQmlPrivate() + { + //when the only remaining are out two refs, reset the pointers, causing deletion + //when the refcount is 2, we are sure that the only refs are s_engine and our copy + //of engineRef + if (engineRef.use_count() == 2) { + s_engine.reset(); + } + } + + static QQmlEngine *engine() + { + if (!s_engine) { + s_engine = std::make_shared(); + KDeclarative::KDeclarative::setupEngine(s_engine.get()); + } + return s_engine.get(); + } + + KCModuleQml *q; QQuickWindow *quickWindow; QQuickWidget *quickWidget; QQuickItem *rootPlaceHolder; + QQuickItem *pageRow; KQuickAddons::ConfigModule *configModule; + + //used to delete the engine + std::shared_ptr engineRef; + static std::shared_ptr s_engine; }; +std::shared_ptr KCModuleQmlPrivate::s_engine = std::shared_ptr(); + KCModuleQml::KCModuleQml(KQuickAddons::ConfigModule *configModule, QWidget* parent, const QVariantList& args) : KCModule(parent, args), - d(new KCModuleQmlPrivate(configModule)) + d(new KCModuleQmlPrivate(configModule, this)) { connect(configModule, &KQuickAddons::ConfigModule::quickHelpChanged, @@ -92,25 +123,16 @@ connect(configModule, &KQuickAddons::ConfigModule::authActionNameChanged, [=] { setAuthAction(d->configModule->authActionName()); }); + setAboutData(d->configModule->aboutData()); setFocusPolicy(Qt::StrongFocus); -} -KCModuleQml::~KCModuleQml() -{ - delete d; -} -void KCModuleQml::showEvent(QShowEvent *event) -{ - if (d->quickWindow || !d->configModule->mainUi()) { - KCModule::showEvent(event); - return; - } + //Build the UI QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); - d->quickWidget = new QQuickWidget(d->configModule->engine(), this); + d->quickWidget = new QQuickWidget(d->engine(), this); d->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); d->quickWidget->setFocusPolicy(Qt::StrongFocus); d->quickWidget->installEventFilter(this); @@ -120,22 +142,39 @@ d->quickWindow->setColor(QGuiApplication::palette().window().color()); }); - QQmlComponent *component = new QQmlComponent(d->configModule->engine(), this); + QQmlComponent *component = new QQmlComponent(d->quickWidget->engine(), this); //this has activeFocusOnTab to notice when the navigation wraps //around, so when we need to go outside and inside - component->setData(QByteArrayLiteral("import QtQuick 2.3\nItem{activeFocusOnTab:true}"), QUrl()); + //pushPage/popPage are needed as push of StackView can't be directly invoked from c++ + //because its parameters are QQmlV4Function which is not public + component->setData(QByteArrayLiteral("import QtQuick 2.3\n" + "import org.kde.kirigami 2.4 as Kirigami\n" + "Kirigami.ApplicationItem{" + // allow only one column for now + "pageStack.defaultColumnWidth:width;" + "pageStack.separatorVisible:false;" + "pageStack.globalToolBar.style:Kirigami.ApplicationHeaderStyle.Breadcrumb;" + "pageStack.globalToolBar.showNavigationButtons:false;" + "pageStack.globalToolBar.preferredHeight:Kirigami.Units.gridUnit*1.6;" + "pageStack.globalToolBar.separatorVisible:false;" + "activeFocusOnTab:true" + "}"), QUrl()); d->rootPlaceHolder = qobject_cast(component->create()); d->quickWidget->setContent(QUrl(), component, d->rootPlaceHolder); - d->configModule->mainUi()->setParentItem(d->quickWidget->rootObject()); + QQmlEngine::setContextForObject(d->configModule, QQmlEngine::contextForObject(d->rootPlaceHolder)); - //set anchors - QQmlExpression expr(d->configModule->engine()->rootContext(), d->configModule->mainUi(), QStringLiteral("parent")); - QQmlProperty prop(d->configModule->mainUi(), QStringLiteral("anchors.fill")); - prop.write(expr.evaluate()); + d->pageRow = d->rootPlaceHolder->property("pageStack").value(); + if (d->pageRow) { + QMetaObject::invokeMethod(d->pageRow, "push", Qt::DirectConnection, Q_ARG(QVariant, QVariant::fromValue(d->configModule->mainUi())), Q_ARG(QVariant, QVariant())); + } layout->addWidget(d->quickWidget); - KCModule::showEvent(event); +} + +KCModuleQml::~KCModuleQml() +{ + delete d; } bool KCModuleQml::eventFilter(QObject* watched, QEvent* event) diff --git a/src/kcmoduleqml_p.h b/src/kcmoduleqml_p.h --- a/src/kcmoduleqml_p.h +++ b/src/kcmoduleqml_p.h @@ -45,7 +45,6 @@ void defaults() Q_DECL_OVERRIDE; protected: - void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE; QSize sizeHint() const Q_DECL_OVERRIDE; bool eventFilter(QObject* watched, QEvent* event) Q_DECL_OVERRIDE;