Commit 79c683bc authored by Alexander Lohnau's avatar Alexander Lohnau 💬
Browse files

Create wrapper class for QML dialog

This will allow KCMs and applications to utilize the
QtQuick dialog without needing to be rewritten in QML.

Also some signals are directly forwarded from the engine,
this will make the consumers more flexible when
reacting to installed/updated/uninstalled entries or
the adoption command.

Once the existing usages have been ported we can
officially deprecate the old QWidgets stuff.
parent 82005274
......@@ -8,6 +8,7 @@ find_dependency(KF5XmlGui "@KF5_DEP_VERSION@")
find_dependency(KF5Service "@KF5_DEP_VERSION@")
find_dependency(KF5NewStuffCore "@KF5_VERSION@")
find_dependency(KF5NewStuffQuick "@KF5_VERSION@")
include("${CMAKE_CURRENT_LIST_DIR}/KF5NewStuffTargets.cmake")
@PACKAGE_INCLUDE_QCHTARGETS@
......@@ -22,6 +22,8 @@ set(KNewStuff_SRCS
ui/widgetquestionlistener.cpp
uploaddialog.cpp
qtquickdialogwrapper.cpp
)
ecm_qt_declare_logging_category(KNewStuff_SRCS
......@@ -69,6 +71,7 @@ target_link_libraries(KF5NewStuff
KF5::I18n # For translations
KF5::ItemViews # For buttons on download dialog
KF5::IconThemes # For KIcon
Qt5::Qml
KF5::TextWidgets # For KTextEdit in upload dialog
)
......@@ -90,6 +93,7 @@ ecm_generate_headers(KNewStuff_CamelCase_HEADERS
UploadDialog
Entry
Button
QtQuickDialogWrapper
REQUIRED_HEADERS KNewStuff_HEADERS
PREFIX KNS3
......
/*
SPDX-FileCopyrightText: 2020 Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "qtquickdialogwrapper.h"
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQmlContext>
#include <QTimer>
#include <QEventLoop>
#include "core/engine.h"
using namespace KNS3;
class KNS3::QtQuickDialogWrapperPrivate
{
public:
QQmlEngine *engine = nullptr;
QObject *item = nullptr;
KNSCore::Engine *coreEngine = nullptr;
QList<KNSCore::EntryInternal> changedEntries;
};
QtQuickDialogWrapper::QtQuickDialogWrapper(const QString &configFile, QObject *parent)
: QObject(parent),
d(new QtQuickDialogWrapperPrivate())
{
d->engine = new QQmlEngine(this);
QQmlComponent component(d->engine);
d->engine->rootContext()->setContextProperty(QStringLiteral("knsrcfile"), configFile);
component.setData(QByteArrayLiteral("import QtQuick 2.7\n"
"import org.kde.newstuff 1.62 as NewStuff\n"
"\n"
"NewStuff.Dialog {\n"
" id: component\n"
" signal closed()\n"
" configFile: knsrcfile\n"
" onVisibleChanged: if (!visible) {closed()}\n"
"}"), QUrl());
d->item = component.create();
// If there is an error on the QML side of things we get a nullptr
if (d->item) {
QObject *qtquickEngine = d->item->property("engine").value<QObject *>();
Q_ASSERT(qtquickEngine);
d->coreEngine = qtquickEngine->property("engine").value<KNSCore::Engine *>();
Q_ASSERT(d->coreEngine);
connect(d->coreEngine, &KNSCore::Engine::signalEntryEvent,
this, [this](const KNSCore::EntryInternal &entry, KNSCore::EntryInternal::EntryEvent event){
if (event == KNSCore::EntryInternal::StatusChangedEvent) {
if (entry.status() == KNS3::Entry::Installing || entry.status() == KNS3::Entry::Updating) {
return; // We do not care about intermediate states
}
// To make sure we have no duplicates and always the latest entry
d->changedEntries.removeOne(entry);
d->changedEntries.append(entry);
}
});
// Forward relevant signals
connect(d->item, SIGNAL(closed()), this, SIGNAL(closed()));
}
}
QtQuickDialogWrapper::~QtQuickDialogWrapper()
{
// Empty destructor needed for std::unique_ptr to incomplete class.
}
void QtQuickDialogWrapper::open()
{
if (d->item) {
d->changedEntries.clear();
QMetaObject::invokeMethod(d->item, "open");
}
}
KNSCore::Engine *QtQuickDialogWrapper::engine()
{
return d->coreEngine;
}
QList<KNSCore::EntryInternal> QtQuickDialogWrapper::exec()
{
open();
QEventLoop loop;
connect(this, &QtQuickDialogWrapper::closed, &loop, &QEventLoop::quit);
loop.exec();
return d->changedEntries;
}
#include "qtquickdialogwrapper.moc"
/*
SPDX-FileCopyrightText: 2020 Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef KNEWSTUFF_QTQUICKDIALOGWRAPPER_H
#define KNEWSTUFF_QTQUICKDIALOGWRAPPER_H
#include <QObject>
#include <KNSCore/ErrorCode>
#include <KNSCore/EntryInternal>
namespace KNSCore
{
class Engine;
}
namespace KNS3
{
class QtQuickDialogWrapperPrivate;
/**
* This class is a wrapper around the QtQuick QML dialog. This dialog is loaded using the QQmlEngine.
* The constructor will create the QML component, to show the dialog the show() method must be called.
* It is recommended to reuse an instance of this class if it is expected that the user reopens the dialog.
* @since 5.78
*/
class KNEWSTUFF_EXPORT QtQuickDialogWrapper : public QObject
{
Q_OBJECT
public:
QtQuickDialogWrapper(const QString &configFile, QObject *parent = nullptr);
~QtQuickDialogWrapper();
/**
* Opens the dialog
*/
void open();
/**
* Similar to QDialog::exec. Shows the dialog and blocks until the user closes it.
* @return changedEntries, useful if you want to refresh the UI after entries were changed
* @see open
*/
QList<KNSCore::EntryInternal> exec();
/**
* This signal gets emitted when the dialog is closed
*/
Q_SIGNAL void closed();
/**
* Engine that is used by the dialog, might be null if the engine failed to initialize.
* @return KNSCore::Engine used by the dialog
*/
KNSCore::Engine* engine();
private:
std::unique_ptr<QtQuickDialogWrapperPrivate> d;
Q_DISABLE_COPY(QtQuickDialogWrapper)
};
}
#endif //KNEWSTUFF_QTQUICKDIALOGWRAPPER_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment