1 /*
2     SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "view.h"
8 #include "configview.h"
9 
10 #if PLASMAQUICK_BUILD_DEPRECATED_SINCE(5, 12)
11 #include <QDebug>
12 #include <QQmlContext>
13 #include <QQmlEngine>
14 #include <QQuickItem>
15 #include <QScreen>
16 #include <QTimer>
17 
18 #include <KLocalizedContext>
19 
20 #include "plasma/pluginloader.h"
21 #include <kdeclarative/kdeclarative.h>
22 #include <packageurlinterceptor.h>
23 
24 namespace PlasmaQuick
25 {
26 class ViewPrivate
27 {
28 public:
29     ViewPrivate(Plasma::Corona *corona, View *view);
30     ~ViewPrivate();
31 
32     void setContainment(Plasma::Containment *cont);
33     Plasma::Types::FormFactor formFactor() const;
34     Plasma::Types::Location location() const;
35     void showConfigurationInterface(Plasma::Applet *applet);
36     void updateDestroyed(bool destroyed);
37 
38     View *q;
39     friend class View;
40     Plasma::Corona *corona;
41     QPointer<Plasma::Containment> containment;
42     QPointer<ConfigView> configView;
43 };
44 
ViewPrivate(Plasma::Corona * cor,View * view)45 ViewPrivate::ViewPrivate(Plasma::Corona *cor, View *view)
46     : q(view)
47     , corona(cor)
48 {
49 }
50 
~ViewPrivate()51 ViewPrivate::~ViewPrivate()
52 {
53 }
54 
setContainment(Plasma::Containment * cont)55 void ViewPrivate::setContainment(Plasma::Containment *cont)
56 {
57     if (containment == cont) {
58         return;
59     }
60 
61     Plasma::Types::Location oldLoc = location();
62     Plasma::Types::FormFactor oldForm = formFactor();
63 
64     if (containment) {
65         QObject::disconnect(containment, nullptr, q, nullptr);
66         QObject *oldGraphicObject = containment->property("_plasma_graphicObject").value<QObject *>();
67         if (oldGraphicObject) {
68             //             qDebug() << "Old graphics Object:" << oldGraphicObject << "Old containment" << containment.data();
69             // make sure the graphic object won't die with us
70             // FIXME:we need a way to reparent to *NO* graphics item, but this makes Qt crash
71             oldGraphicObject->setParent(containment);
72         }
73         containment->reactToScreenChange();
74     }
75 
76     containment = cont;
77 
78     if (oldLoc != location()) {
79         Q_EMIT q->locationChanged(location());
80     }
81     if (oldForm != formFactor()) {
82         Q_EMIT q->formFactorChanged(formFactor());
83     }
84 
85     Q_EMIT q->containmentChanged();
86 
87     if (cont) {
88         cont->reactToScreenChange();
89         QObject::connect(cont, &Plasma::Containment::locationChanged, q, &View::locationChanged);
90         QObject::connect(cont, &Plasma::Containment::formFactorChanged, q, &View::formFactorChanged);
91         QObject::connect(cont, &Plasma::Containment::configureRequested, q, &View::showConfigurationInterface);
92         QObject::connect(cont, SIGNAL(destroyedChanged(bool)), q, SLOT(updateDestroyed(bool)));
93         if (cont->containmentType() == Plasma::Types::PanelContainment || cont->containmentType() == Plasma::Types::CustomPanelContainment) {
94             q->setVisible(!cont->destroyed() && cont->isUiReady());
95         }
96     } else {
97         return;
98     }
99 
100     QQuickItem *graphicObject = qobject_cast<QQuickItem *>(containment->property("_plasma_graphicObject").value<QObject *>());
101 
102     if (graphicObject) {
103         //         qDebug() << "using as graphic containment" << graphicObject << containment.data();
104 
105         // by resizing before adding, it will avoid some resizes in most cases
106         graphicObject->setSize(q->size());
107         graphicObject->setParentItem(q->rootObject());
108         if (q->rootObject()) {
109             q->rootObject()->setProperty("containment", QVariant::fromValue(graphicObject));
110             QObject *wpGraphicObject = containment->property("wallpaperGraphicsObject").value<QObject *>();
111             if (wpGraphicObject) {
112                 q->rootObject()->setProperty("wallpaper", QVariant::fromValue(wpGraphicObject));
113             }
114         } else {
115             qWarning() << "Could not set containment property on rootObject";
116         }
117     } else {
118         qWarning() << "Containment graphic object not valid";
119     }
120 }
121 
location() const122 Plasma::Types::Location ViewPrivate::location() const
123 {
124     if (!containment) {
125         return Plasma::Types::Desktop;
126     }
127     return containment->location();
128 }
129 
formFactor() const130 Plasma::Types::FormFactor ViewPrivate::formFactor() const
131 {
132     if (!containment) {
133         return Plasma::Types::Planar;
134     }
135     return containment->formFactor();
136 }
137 
showConfigurationInterface(Plasma::Applet * applet)138 void ViewPrivate::showConfigurationInterface(Plasma::Applet *applet)
139 {
140     if (configView) {
141         if (configView->applet() != applet) {
142             configView->hide();
143             configView->deleteLater();
144         } else {
145             configView->raise();
146             configView->requestActivate();
147             return;
148         }
149     }
150 
151     if (!applet || !applet->containment()) {
152         return;
153     }
154 
155     configView = new ConfigView(applet);
156 
157     configView->init();
158     configView->show();
159 }
160 
updateDestroyed(bool destroyed)161 void ViewPrivate::updateDestroyed(bool destroyed)
162 {
163     q->setVisible(!destroyed);
164 }
165 
View(Plasma::Corona * corona,QWindow * parent)166 View::View(Plasma::Corona *corona, QWindow *parent)
167     : QQuickView(parent)
168     , d(new ViewPrivate(corona, this))
169 {
170     setColor(Qt::transparent);
171 
172     QObject::connect(screen(), &QScreen::geometryChanged, this, &View::screenGeometryChanged);
173 
174     const auto pkg = corona->kPackage();
175     if (pkg.isValid()) {
176         PackageUrlInterceptor *interceptor = new PackageUrlInterceptor(engine(), pkg);
177         interceptor->setForcePlasmaStyle(true);
178         engine()->setUrlInterceptor(interceptor);
179 
180         KLocalizedContext *localizedContextObject = new KLocalizedContext(engine());
181         localizedContextObject->setTranslationDomain(QStringLiteral("plasma_shell_") + pkg.metadata().pluginId());
182         engine()->rootContext()->setContextObject(localizedContextObject);
183 
184         // binds things like kconfig and icons
185         KDeclarative::KDeclarative::setupEngine(engine()); // ### how to make sure to do this only once per engine?
186     } else {
187         qWarning() << "Invalid home screen package";
188     }
189 
190     // Force QtQuickControls to use the "Plasma" style for this engine.
191     // this way is possible to mix QtQuickControls and plasma components in applets
192     // while still having the desktop style in configuration dialogs
193     QQmlComponent c(engine());
194     c.setData(
195         "import QtQuick 2.1\n\
196         import QtQuick.Controls 1.0\n\
197         import QtQuick.Controls.Private 1.0\n \
198         Item {\
199           Component.onCompleted: {\
200             Settings.styleName = \"Plasma\";\
201           }\
202         }",
203         QUrl());
204     QObject *o = c.create();
205     o->deleteLater();
206 
207     setResizeMode(View::SizeRootObjectToView);
208 }
209 
~View()210 View::~View()
211 {
212     delete d;
213 }
214 
corona() const215 Plasma::Corona *View::corona() const
216 {
217     return d->corona;
218 }
219 
config() const220 KConfigGroup View::config() const
221 {
222     if (!containment()) {
223         return KConfigGroup();
224     }
225     KConfigGroup views(KSharedConfig::openConfig(), "PlasmaViews");
226     return KConfigGroup(&views, QString::number(containment()->screen()));
227 }
228 
setContainment(Plasma::Containment * cont)229 void View::setContainment(Plasma::Containment *cont)
230 {
231     d->setContainment(cont);
232 }
233 
containment() const234 Plasma::Containment *View::containment() const
235 {
236     return d->containment;
237 }
238 
setLocation(Plasma::Types::Location location)239 void View::setLocation(Plasma::Types::Location location)
240 {
241     d->containment->setLocation(location);
242 }
243 
location() const244 Plasma::Types::Location View::location() const
245 {
246     return d->location();
247 }
248 
formFactor() const249 Plasma::Types::FormFactor View::formFactor() const
250 {
251     return d->formFactor();
252 }
253 
screenGeometry()254 QRectF View::screenGeometry()
255 {
256     return screen()->geometry();
257 }
258 
showConfigurationInterface(Plasma::Applet * applet)259 void View::showConfigurationInterface(Plasma::Applet *applet)
260 {
261     d->showConfigurationInterface(applet);
262 }
263 
264 }
265 #include "moc_view.cpp"
266 #endif
267