1 /*
2     SPDX-FileCopyrightText: 2017 Roman Gilg <subdiff@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "touchpadconfiglibinput.h"
8 
9 #include <KAboutData>
10 #include <KLocalizedString>
11 #include <kdeclarative/kdeclarative.h>
12 
13 #include <QMetaObject>
14 #include <QQmlContext>
15 #include <QQmlProperty>
16 #include <QQuickItem>
17 #include <QQuickWidget>
18 #include <QVBoxLayout>
19 
20 #include "../touchpadconfigcontainer.h"
21 #include "touchpadbackend.h"
22 
23 #include "plasma_version.h"
24 
TouchpadConfigLibinput(TouchpadConfigContainer * parent,TouchpadBackend * backend,const QVariantList &)25 TouchpadConfigLibinput::TouchpadConfigLibinput(TouchpadConfigContainer *parent, TouchpadBackend *backend, const QVariantList & /*args*/)
26     : TouchpadConfigPlugin(parent, backend)
27 {
28     KAboutData *data = new KAboutData(QStringLiteral("kcm_touchpad"),
29                                       i18n("Touchpad KCM"),
30                                       PLASMA_VERSION_STRING,
31                                       i18n("System Settings module for managing your touchpad"),
32                                       KAboutLicense::GPL_V2,
33                                       i18n("Copyright © 2016 Roman Gilg"),
34                                       QString());
35 
36     data->addAuthor(i18n("Roman Gilg"), i18n("Developer"), QStringLiteral("subdiff@gmail.com"));
37 
38     m_parent->setAboutData(data);
39 
40     m_initError = !m_backend->errorString().isNull();
41 
42     m_view = new QQuickWidget(this);
43 
44     QVBoxLayout *layout = new QVBoxLayout(parent);
45 
46     layout->addWidget(m_view);
47     parent->setLayout(layout);
48 
49     m_view->setResizeMode(QQuickWidget::SizeRootObjectToView);
50     m_view->setClearColor(Qt::transparent);
51     m_view->setAttribute(Qt::WA_AlwaysStackOnTop);
52 
53     m_view->rootContext()->setContextProperty("backend", m_backend);
54     m_view->rootContext()->setContextProperty("deviceModel", QVariant::fromValue(m_backend->getDevices().toList()));
55 
56     qmlRegisterSingletonInstance("org.kde.touchpad.kcm", 1, 0, "TouchpadConfig", this);
57 
58     KDeclarative::KDeclarative kdeclarative;
59     kdeclarative.setDeclarativeEngine(m_view->engine());
60     kdeclarative.setupBindings();
61     m_view->setSource(QUrl("qrc:/libinput/touchpad.qml"));
62 
63     if (m_initError) {
64         Q_EMIT showMessage(m_backend->errorString());
65     } else {
66         connect(m_backend, SIGNAL(touchpadAdded(bool)), this, SLOT(onTouchpadAdded(bool)));
67         connect(m_backend, SIGNAL(touchpadRemoved(int)), this, SLOT(onTouchpadRemoved(int)));
68         connect(m_view->rootObject(), SIGNAL(changeSignal()), this, SLOT(onChange()));
69     }
70 
71     m_view->show();
72 }
73 
sizeHint() const74 QSize TouchpadConfigLibinput::sizeHint() const
75 {
76     return QQmlProperty::read(m_view->rootObject(), "sizeHint").toSize();
77 }
78 
minimumSizeHint() const79 QSize TouchpadConfigLibinput::minimumSizeHint() const
80 {
81     return QQmlProperty::read(m_view->rootObject(), "minimumSizeHint").toSize();
82 }
83 
load()84 void TouchpadConfigLibinput::load()
85 {
86     // in case of critical init error in backend, don't try
87     if (m_initError) {
88         return;
89     }
90 
91     if (!m_backend->getConfig()) {
92         Q_EMIT showMessage(i18n("Error while loading values. See logs for more information. Please restart this configuration module."));
93     } else {
94         if (!m_backend->touchpadCount()) {
95             Q_EMIT showMessage(i18n("No touchpad found. Connect touchpad now."));
96         }
97     }
98     QMetaObject::invokeMethod(m_view->rootObject(), "syncValuesFromBackend");
99 }
100 
save()101 void TouchpadConfigLibinput::save()
102 {
103     if (!m_backend->applyConfig()) {
104         Q_EMIT showMessage(i18n("Not able to save all changes. See logs for more information. Please restart this configuration module and try again."));
105     } else {
106         Q_EMIT showMessage(QString());
107     }
108 
109     // load newly written values
110     load();
111     // in case of error, config still in changed state
112     Q_EMIT m_parent->changed(m_backend->isChangedConfig());
113 }
114 
defaults()115 void TouchpadConfigLibinput::defaults()
116 {
117     // in case of critical init error in backend, don't try
118     if (m_initError) {
119         return;
120     }
121 
122     if (!m_backend->getDefaultConfig()) {
123         Q_EMIT showMessage(i18n("Error while loading default values. Failed to set some options to their default values."));
124     }
125     QMetaObject::invokeMethod(m_view->rootObject(), "syncValuesFromBackend");
126     Q_EMIT m_parent->changed(m_backend->isChangedConfig());
127 }
128 
onChange()129 void TouchpadConfigLibinput::onChange()
130 {
131     if (!m_backend->touchpadCount()) {
132         return;
133     }
134     hideErrorMessage();
135     Q_EMIT m_parent->changed(m_backend->isChangedConfig());
136 }
137 
onTouchpadAdded(bool success)138 void TouchpadConfigLibinput::onTouchpadAdded(bool success)
139 {
140     QQuickItem *rootObj = m_view->rootObject();
141 
142     if (!success) {
143         Q_EMIT showMessage(i18n("Error while adding newly connected device. Please reconnect it and restart this configuration module."));
144     }
145 
146     int activeIndex;
147     if (m_backend->touchpadCount() == 1) {
148         // if no touchpad was connected previously, show the new device and hide the no-device-message
149         activeIndex = 0;
150         hideErrorMessage();
151     } else {
152         activeIndex = QQmlProperty::read(rootObj, "deviceIndex").toInt();
153     }
154     m_view->rootContext()->setContextProperty("deviceModel", QVariant::fromValue(m_backend->getDevices()));
155     QMetaObject::invokeMethod(rootObj, "resetModel", Q_ARG(QVariant, activeIndex));
156     QMetaObject::invokeMethod(rootObj, "syncValuesFromBackend");
157 }
158 
onTouchpadRemoved(int index)159 void TouchpadConfigLibinput::onTouchpadRemoved(int index)
160 {
161     QQuickItem *rootObj = m_view->rootObject();
162 
163     int activeIndex = QQmlProperty::read(rootObj, "deviceIndex").toInt();
164     if (activeIndex == index) {
165         if (m_backend->touchpadCount()) {
166             Q_EMIT showMessage(i18n("Touchpad disconnected. Closed its setting dialog."), 0 /*Kirigami.MessageType.Information*/);
167         } else {
168             Q_EMIT showMessage(i18n("Touchpad disconnected. No other touchpads found."), 0 /*Kirigami.MessageType.Information*/);
169         }
170         activeIndex = 0;
171     } else {
172         if (index < activeIndex) {
173             activeIndex--;
174         }
175     }
176     m_view->rootContext()->setContextProperty("deviceModel", QVariant::fromValue(m_backend->getDevices()));
177     QMetaObject::invokeMethod(m_view->rootObject(), "resetModel", Q_ARG(QVariant, activeIndex));
178     QMetaObject::invokeMethod(rootObj, "syncValuesFromBackend");
179 
180     Q_EMIT m_parent->changed(m_backend->isChangedConfig());
181 }
182 
hideErrorMessage()183 void TouchpadConfigLibinput::hideErrorMessage()
184 {
185     Q_EMIT showMessage(QString());
186 }
187