Changeset View
Changeset View
Standalone View
Standalone View
src/kcmoduleqml.cpp
Show All 25 Lines | |||||
26 | #include <QQmlContext> | 26 | #include <QQmlContext> | ||
27 | #include <QQuickWindow> | 27 | #include <QQuickWindow> | ||
28 | #include <QQuickItem> | 28 | #include <QQuickItem> | ||
29 | #include <QGuiApplication> | 29 | #include <QGuiApplication> | ||
30 | #include <QQuickWidget> | 30 | #include <QQuickWidget> | ||
31 | 31 | | |||
32 | #include <kdeclarative/kdeclarative.h> | 32 | #include <kdeclarative/kdeclarative.h> | ||
33 | #include <kquickaddons/configmodule.h> | 33 | #include <kquickaddons/configmodule.h> | ||
34 | #include <kdeclarative/qmlobjectsharedengine.h> | ||||
34 | #include <KAboutData> | 35 | #include <KAboutData> | ||
35 | #include <KLocalizedString> | 36 | #include <KLocalizedString> | ||
36 | #include <KPackage/Package> | 37 | #include <KPackage/Package> | ||
37 | #include <KPackage/PackageLoader> | 38 | #include <KPackage/PackageLoader> | ||
39 | #include <KPageWidget> | ||||
38 | 40 | | |||
39 | class KCModuleQmlPrivate | 41 | class KCModuleQmlPrivate | ||
40 | { | 42 | { | ||
41 | public: | 43 | public: | ||
42 | KCModuleQmlPrivate(KQuickAddons::ConfigModule *cm) | 44 | KCModuleQmlPrivate(KQuickAddons::ConfigModule *cm, KCModuleQml *q) | ||
43 | : quickWindow(nullptr), | 45 | : q(q), | ||
46 | quickWindow(nullptr), | ||||
44 | configModule(cm) | 47 | configModule(cm) | ||
45 | { | 48 | { | ||
46 | } | 49 | } | ||
47 | 50 | | |||
51 | ~KCModuleQmlPrivate() | ||||
52 | { | ||||
53 | } | ||||
54 | | ||||
55 | KCModuleQml *q; | ||||
48 | QQuickWindow *quickWindow; | 56 | QQuickWindow *quickWindow; | ||
49 | QQuickWidget *quickWidget; | 57 | QQuickWidget *quickWidget; | ||
50 | QQuickItem *rootPlaceHolder; | 58 | QQuickItem *rootPlaceHolder; | ||
59 | QQuickItem *pageRow; | ||||
51 | KQuickAddons::ConfigModule *configModule; | 60 | KQuickAddons::ConfigModule *configModule; | ||
61 | KDeclarative::QmlObjectSharedEngine *qmlObject; | ||||
52 | }; | 62 | }; | ||
53 | 63 | | |||
54 | KCModuleQml::KCModuleQml(KQuickAddons::ConfigModule *configModule, QWidget* parent, const QVariantList& args) | 64 | KCModuleQml::KCModuleQml(KQuickAddons::ConfigModule *configModule, QWidget* parent, const QVariantList& args) | ||
55 | : KCModule(parent, args), | 65 | : KCModule(parent, args), | ||
56 | d(new KCModuleQmlPrivate(configModule)) | 66 | d(new KCModuleQmlPrivate(configModule, this)) | ||
57 | { | 67 | { | ||
58 | 68 | | |||
59 | connect(configModule, &KQuickAddons::ConfigModule::quickHelpChanged, | 69 | connect(configModule, &KQuickAddons::ConfigModule::quickHelpChanged, | ||
60 | this, &KCModuleQml::quickHelpChanged); | 70 | this, &KCModuleQml::quickHelpChanged); | ||
61 | //HACK:Here is important those two enums keep having the exact same values | 71 | //HACK:Here is important those two enums keep having the exact same values | ||
62 | //but the kdeclarative one can't use the KCModule's enum | 72 | //but the kdeclarative one can't use the KCModule's enum | ||
63 | setButtons((KCModule::Buttons)(int)d->configModule->buttons()); | 73 | setButtons((KCModule::Buttons)(int)d->configModule->buttons()); | ||
64 | connect(configModule, &KQuickAddons::ConfigModule::buttonsChanged, [=] { | 74 | connect(configModule, &KQuickAddons::ConfigModule::buttonsChanged, [=] { | ||
Show All 22 Lines | |||||
87 | }); | 97 | }); | ||
88 | 98 | | |||
89 | if (!d->configModule->authActionName().isEmpty()) { | 99 | if (!d->configModule->authActionName().isEmpty()) { | ||
90 | setAuthAction(KAuth::Action(d->configModule->authActionName())); | 100 | setAuthAction(KAuth::Action(d->configModule->authActionName())); | ||
91 | } | 101 | } | ||
92 | connect(configModule, &KQuickAddons::ConfigModule::authActionNameChanged, [=] { | 102 | connect(configModule, &KQuickAddons::ConfigModule::authActionNameChanged, [=] { | ||
93 | setAuthAction(d->configModule->authActionName()); | 103 | setAuthAction(d->configModule->authActionName()); | ||
94 | }); | 104 | }); | ||
105 | setAboutData(d->configModule->aboutData()); | ||||
95 | setFocusPolicy(Qt::StrongFocus); | 106 | setFocusPolicy(Qt::StrongFocus); | ||
96 | } | | |||
97 | 107 | | |||
98 | KCModuleQml::~KCModuleQml() | | |||
99 | { | | |||
100 | delete d; | | |||
101 | } | | |||
102 | 108 | | |||
103 | void KCModuleQml::showEvent(QShowEvent *event) | | |||
104 | { | | |||
105 | if (d->quickWindow || !d->configModule->mainUi()) { | | |||
106 | KCModule::showEvent(event); | | |||
107 | return; | | |||
108 | } | | |||
109 | 109 | | |||
110 | //Build the UI | ||||
110 | QVBoxLayout* layout = new QVBoxLayout(this); | 111 | QVBoxLayout* layout = new QVBoxLayout(this); | ||
111 | layout->setContentsMargins(0, 0, 0, 0); | 112 | layout->setContentsMargins(0, 0, 0, 0); | ||
112 | 113 | | |||
113 | d->quickWidget = new QQuickWidget(d->configModule->engine(), this); | 114 | d->qmlObject = new KDeclarative::QmlObjectSharedEngine(this); | ||
115 | d->quickWidget = new QQuickWidget(d->qmlObject->engine(), this); | ||||
114 | d->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); | 116 | d->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); | ||
115 | d->quickWidget->setFocusPolicy(Qt::StrongFocus); | 117 | d->quickWidget->setFocusPolicy(Qt::StrongFocus); | ||
116 | d->quickWidget->installEventFilter(this); | 118 | d->quickWidget->installEventFilter(this); | ||
117 | d->quickWindow = d->quickWidget->quickWindow(); | 119 | d->quickWindow = d->quickWidget->quickWindow(); | ||
118 | d->quickWindow->setColor(QGuiApplication::palette().window().color()); | 120 | d->quickWindow->setColor(QGuiApplication::palette().window().color()); | ||
119 | connect(qApp, &QGuiApplication::paletteChanged, d->quickWindow, [=]() { | 121 | connect(qApp, &QGuiApplication::paletteChanged, d->quickWindow, [=]() { | ||
120 | d->quickWindow->setColor(QGuiApplication::palette().window().color()); | 122 | d->quickWindow->setColor(QGuiApplication::palette().window().color()); | ||
121 | }); | 123 | }); | ||
122 | 124 | | |||
123 | QQmlComponent *component = new QQmlComponent(d->configModule->engine(), this); | 125 | QQmlComponent *component = new QQmlComponent(d->qmlObject->engine(), this); | ||
124 | //this has activeFocusOnTab to notice when the navigation wraps | 126 | //this has activeFocusOnTab to notice when the navigation wraps | ||
125 | //around, so when we need to go outside and inside | 127 | //around, so when we need to go outside and inside | ||
128 | //pushPage/popPage are needed as push of StackView can't be directly invoked from c++ | ||||
129 | //because its parameters are QQmlV4Function which is not public | ||||
126 | //the managers of onEnter/ReturnPressed are a workaround of | 130 | //the managers of onEnter/ReturnPressed are a workaround of | ||
127 | //Qt bug https://bugreports.qt.io/browse/QTBUG-70934 | 131 | //Qt bug https://bugreports.qt.io/browse/QTBUG-70934 | ||
128 | component->setData(QByteArrayLiteral("import QtQuick 2.3\nItem{activeFocusOnTab:true;Keys.onReturnPressed:{event.accepted=true}Keys.onEnterPressed:{event.accepted=true}}"), QUrl()); | 132 | component->setData(QByteArrayLiteral("import QtQuick 2.3\n" | ||
133 | "import org.kde.kirigami 2.4 as Kirigami\n" | ||||
134 | "Kirigami.ApplicationItem{" | ||||
135 | //purely cosmetic space | ||||
136 | "header: Item {height: Kirigami.Units.largeSpacing}" | ||||
137 | // allow only one column by default | ||||
138 | "pageStack.defaultColumnWidth:width;" | ||||
139 | "pageStack.separatorVisible:false;" | ||||
140 | "pageStack.globalToolBar.style: pageStack.wideScreen ? Kirigami.ApplicationHeaderStyle.Titles : Kirigami.ApplicationHeaderStyle.Breadcrumb;" | ||||
141 | "pageStack.globalToolBar.showNavigationButtons:false;" | ||||
142 | "pageStack.globalToolBar.preferredHeight:Kirigami.Units.gridUnit*1.6;" | ||||
143 | "pageStack.globalToolBar.separatorVisible:false;" | ||||
144 | "activeFocusOnTab:true;" | ||||
145 | "Keys.onReturnPressed:{event.accepted=true}" | ||||
146 | "Keys.onEnterPressed:{event.accepted=true}" | ||||
147 | "}"), QUrl()); | ||||
148 | | ||||
129 | d->rootPlaceHolder = qobject_cast<QQuickItem *>(component->create()); | 149 | d->rootPlaceHolder = qobject_cast<QQuickItem *>(component->create()); | ||
130 | d->quickWidget->setContent(QUrl(), component, d->rootPlaceHolder); | 150 | d->quickWidget->setContent(QUrl(), component, d->rootPlaceHolder); | ||
131 | 151 | | |||
132 | d->configModule->mainUi()->setParentItem(d->quickWidget->rootObject()); | 152 | d->pageRow = d->rootPlaceHolder->property("pageStack").value<QQuickItem *>(); | ||
153 | if (d->pageRow) { | ||||
154 | QMetaObject::invokeMethod(d->pageRow, "push", Qt::DirectConnection, Q_ARG(QVariant, QVariant::fromValue(d->configModule->mainUi())), Q_ARG(QVariant, QVariant())); | ||||
155 | | ||||
156 | connect(d->configModule, &KQuickAddons::ConfigModule::pagePushed, this, [this](QQuickItem *page) { | ||||
157 | QMetaObject::invokeMethod(d->pageRow, "push", Qt::DirectConnection, Q_ARG(QVariant, QVariant::fromValue(page)), Q_ARG(QVariant, QVariant())); | ||||
158 | } | ||||
159 | ); | ||||
160 | connect(d->configModule, &KQuickAddons::ConfigModule::pageRemoved, this, [this]() { | ||||
161 | QMetaObject::invokeMethod(d->pageRow, "pop", Qt::DirectConnection, Q_ARG(QVariant, QVariant())); | ||||
162 | } | ||||
163 | ); | ||||
164 | | ||||
165 | auto syncColumnWidth = [this](){ | ||||
166 | d->pageRow->setProperty("defaultColumnWidth", d->configModule->columnWidth() > 0 ? d->configModule->columnWidth() : d->rootPlaceHolder->width()); | ||||
167 | }; | ||||
168 | syncColumnWidth(); | ||||
133 | 169 | | |||
134 | //set anchors | 170 | connect(d->configModule, &KQuickAddons::ConfigModule::columnWidthChanged, | ||
135 | QQmlExpression expr(d->configModule->engine()->rootContext(), d->configModule->mainUi(), QStringLiteral("parent")); | 171 | this, syncColumnWidth); | ||
136 | QQmlProperty prop(d->configModule->mainUi(), QStringLiteral("anchors.fill")); | 172 | connect(d->rootPlaceHolder, &QQuickItem::widthChanged, | ||
137 | prop.write(expr.evaluate()); | 173 | this, syncColumnWidth); | ||
174 | | ||||
175 | //HACK: in order to work with old Systemsettings | ||||
176 | //search if we are in a KPageWidget, search ofr its page, and if it has | ||||
177 | //an header set, disable our own title | ||||
178 | //FIXME: eventually remove this hack | ||||
179 | QObject *candidate = this; | ||||
180 | while (candidate) { | ||||
181 | candidate = candidate->parent(); | ||||
182 | KPageWidget *page = qobject_cast<KPageWidget *>(candidate); | ||||
183 | if (page && !page->currentPage()->header().isEmpty()) { | ||||
184 | QObject *globalToolBar = d->pageRow->property("globalToolBar").value<QObject *>(); | ||||
185 | //5 is None | ||||
186 | globalToolBar->setProperty("style", 5); | ||||
187 | } | ||||
188 | } | ||||
189 | } | ||||
138 | 190 | | |||
139 | layout->addWidget(d->quickWidget); | 191 | layout->addWidget(d->quickWidget); | ||
140 | KCModule::showEvent(event); | 192 | } | ||
193 | | ||||
194 | KCModuleQml::~KCModuleQml() | ||||
195 | { | ||||
196 | delete d; | ||||
141 | } | 197 | } | ||
142 | 198 | | |||
143 | bool KCModuleQml::eventFilter(QObject* watched, QEvent* event) | 199 | bool KCModuleQml::eventFilter(QObject* watched, QEvent* event) | ||
144 | { | 200 | { | ||
145 | //FIXME: those are all workarounds around the QQuickWidget brokeness | 201 | //FIXME: those are all workarounds around the QQuickWidget brokeness | ||
146 | //BUG https://bugreports.qt.io/browse/QTBUG-64561 | 202 | //BUG https://bugreports.qt.io/browse/QTBUG-64561 | ||
147 | if (watched == d->quickWidget && event->type() == QEvent::KeyPress) { | 203 | if (watched == d->quickWidget && event->type() == QEvent::KeyPress) { | ||
148 | //allow tab navigation inside the qquickwidget | 204 | //allow tab navigation inside the qquickwidget | ||
▲ Show 20 Lines • Show All 92 Lines • Show Last 20 Lines |