File indexing completed on 2024-05-12 05:46:37

0001 /*
0002  *  Copyright 2013 Marco Martin <mart@kde.org>
0003  *
0004  *  This program is free software; you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation; either version 2 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program; if not, write to the Free Software
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0017  */
0018 
0019 #include "view.h"
0020 #include "configview.h"
0021 
0022 #include <QDebug>
0023 #include <QQuickItem>
0024 #include <QQmlContext>
0025 #include <QTimer>
0026 #include <QScreen>
0027 #include <QQmlEngine>
0028 
0029 #include "plasma/pluginloader.h"
0030 #include <packageurlinterceptor.h>
0031 #include <kdeclarative/kdeclarative.h>
0032 
0033 namespace PlasmaQuick
0034 {
0035 
0036 class ViewPrivate
0037 {
0038 public:
0039 
0040     ViewPrivate(Plasma::Corona *corona, View *view);
0041     ~ViewPrivate();
0042 
0043     void setContainment(Plasma::Containment *cont);
0044     Plasma::Types::FormFactor formFactor() const;
0045     Plasma::Types::Location location() const;
0046     void showConfigurationInterface(Plasma::Applet *applet);
0047     void updateDestroyed(bool destroyed);
0048 
0049     View *q;
0050     friend class View;
0051     Plasma::Corona *corona;
0052     QPointer<Plasma::Containment> containment;
0053     QPointer<ConfigView> configView;
0054 };
0055 
0056 ViewPrivate::ViewPrivate(Plasma::Corona *cor, View *view)
0057     : q(view),
0058       corona(cor)
0059 {
0060 }
0061 
0062 ViewPrivate::~ViewPrivate()
0063 {
0064 }
0065 
0066 void ViewPrivate::setContainment(Plasma::Containment *cont)
0067 {
0068     if (containment == cont) {
0069         return;
0070     }
0071 
0072     Plasma::Types::Location oldLoc = location();
0073     Plasma::Types::FormFactor oldForm = formFactor();
0074 
0075     if (containment) {
0076         QObject::disconnect(containment, nullptr, q, nullptr);
0077         QObject *oldGraphicObject = containment->property("_plasma_graphicObject").value<QObject *>();
0078         if (oldGraphicObject) {
0079 //             qDebug() << "Old graphics Object:" << oldGraphicObject << "Old containment" << containment.data();
0080             //make sure the graphic object won't die with us
0081             //FIXME:we need a way to reparent to *NO* graphics item, but this makes Qt crash
0082             oldGraphicObject->setParent(containment);
0083         }
0084         containment->reactToScreenChange();
0085     }
0086 
0087     containment = cont;
0088 
0089     if (oldLoc != location()) {
0090         emit q->locationChanged(location());
0091     }
0092     if (oldForm != formFactor()) {
0093         emit q->formFactorChanged(formFactor());
0094     }
0095 
0096     emit q->containmentChanged();
0097 
0098     if (cont) {
0099         cont->reactToScreenChange();
0100         QObject::connect(cont, &Plasma::Containment::locationChanged,
0101                          q, &View::locationChanged);
0102         QObject::connect(cont, &Plasma::Containment::formFactorChanged,
0103                          q, &View::formFactorChanged);
0104         QObject::connect(cont, &Plasma::Containment::configureRequested,
0105                          q, &View::showConfigurationInterface);
0106         QObject::connect(cont, SIGNAL(destroyedChanged(bool)),
0107                          q, SLOT(updateDestroyed(bool)));
0108         if (cont->containmentType() == Plasma::Types::PanelContainment ||
0109             cont->containmentType() == Plasma::Types::CustomPanelContainment) {
0110             q->setVisible(!cont->destroyed() && cont->isUiReady());
0111         }
0112     } else {
0113         return;
0114     }
0115 
0116     QQuickItem *graphicObject = qobject_cast<QQuickItem *>(containment->property("_plasma_graphicObject").value<QObject *>());
0117 
0118     if (graphicObject) {
0119 //         qDebug() << "using as graphic containment" << graphicObject << containment.data();
0120 
0121         //by resizing before adding, it will avoid some resizes in most cases
0122         graphicObject->setSize(q->size());
0123         graphicObject->setParentItem(q->rootObject());
0124         if (q->rootObject()) {
0125             q->rootObject()->setProperty("containment", QVariant::fromValue(graphicObject));
0126             QObject *wpGraphicObject = containment->property("wallpaperGraphicsObject").value<QObject *>();
0127             if (wpGraphicObject) {
0128                 q->rootObject()->setProperty("wallpaper", QVariant::fromValue(wpGraphicObject));
0129             }
0130         } else {
0131             qWarning() << "Could not set containment property on rootObject";
0132         }
0133     } else {
0134         qWarning() << "Containment graphic object not valid";
0135     }
0136 }
0137 
0138 Plasma::Types::Location ViewPrivate::location() const
0139 {
0140     if (!containment) {
0141         return Plasma::Types::Desktop;
0142     }
0143     return containment->location();
0144 }
0145 
0146 Plasma::Types::FormFactor ViewPrivate::formFactor() const
0147 {
0148     if (!containment) {
0149         return Plasma::Types::Planar;
0150     }
0151     return containment->formFactor();
0152 }
0153 
0154 void ViewPrivate::showConfigurationInterface(Plasma::Applet *applet)
0155 {
0156     if (configView) {
0157         if (configView->applet() != applet) {
0158             configView->hide();
0159             configView->deleteLater();
0160         } else {
0161             configView->raise();
0162             configView->requestActivate();
0163             return;
0164         }
0165     }
0166 
0167     if (!applet || !applet->containment()) {
0168         return;
0169     }
0170 
0171     configView = new ConfigView(applet);
0172 
0173     configView->init();
0174     configView->show();
0175 }
0176 
0177 void ViewPrivate::updateDestroyed(bool destroyed)
0178 {
0179     q->setVisible(!destroyed);
0180 }
0181 
0182 View::View(Plasma::Corona *corona, QWindow *parent)
0183     : QQuickView(parent),
0184       d(new ViewPrivate(corona, this))
0185 {
0186     setColor(Qt::transparent);
0187 
0188     QObject::connect(screen(), &QScreen::geometryChanged,
0189                      this, &View::screenGeometryChanged);
0190 
0191     const auto pkg = corona->kPackage();
0192     if (pkg.isValid()) {
0193         PackageUrlInterceptor *interceptor = new PackageUrlInterceptor(engine(), pkg);
0194         interceptor->setForcePlasmaStyle(true);
0195         engine()->setUrlInterceptor(interceptor);
0196 
0197         KDeclarative::KDeclarative kdeclarative;
0198         kdeclarative.setDeclarativeEngine(engine());
0199         //binds things like kconfig and icons
0200         kdeclarative.setTranslationDomain(QStringLiteral("plasma_shell_") + pkg.metadata().pluginId());
0201         kdeclarative.setupBindings();
0202     } else {
0203         qWarning() << "Invalid home screen package";
0204     }
0205 
0206     //Force QtQuickControls to use the "Plasma" style for this engine.
0207     //this way is possible to mix QtQuickControls and plasma components in applets
0208     //while still having the desktop style in configuration dialogs
0209     QQmlComponent c(engine());
0210     c.setData("import QtQuick 2.1\n\
0211         import QtQuick.Controls 1.0\n\
0212         import QtQuick.Controls.Private 1.0\n \
0213         Item {\
0214           Component.onCompleted: {\
0215             Settings.styleName = \"Plasma\";\
0216           }\
0217         }", QUrl());
0218     QObject *o = c.create();
0219     o->deleteLater();
0220 
0221     setResizeMode(View::SizeRootObjectToView);
0222 }
0223 
0224 View::~View()
0225 {
0226     delete d;
0227 }
0228 
0229 Plasma::Corona *View::corona() const
0230 {
0231     return d->corona;
0232 }
0233 
0234 KConfigGroup View::config() const
0235 {
0236     if (!containment()) {
0237         return KConfigGroup();
0238     }
0239     KConfigGroup views(KSharedConfig::openConfig(), "PlasmaViews");
0240     return KConfigGroup(&views, QString::number(containment()->screen()));
0241 }
0242 
0243 void View::setContainment(Plasma::Containment *cont)
0244 {
0245     d->setContainment(cont);
0246 }
0247 
0248 Plasma::Containment *View::containment() const
0249 {
0250     return d->containment;
0251 }
0252 
0253 void View::setLocation(Plasma::Types::Location location)
0254 {
0255     d->containment->setLocation(location);
0256 }
0257 
0258 Plasma::Types::Location View::location() const
0259 {
0260     return d->location();
0261 }
0262 
0263 Plasma::Types::FormFactor View::formFactor() const
0264 {
0265     return d->formFactor();
0266 }
0267 
0268 QRectF View::screenGeometry()
0269 {
0270     return screen()->geometry();
0271 }
0272 
0273 void View::showConfigurationInterface(Plasma::Applet *applet)
0274 {
0275     d->showConfigurationInterface(applet);
0276 }
0277 
0278 }
0279 
0280 #include "moc_view.cpp"