File indexing completed on 2024-04-28 05:34:20

0001 /*
0002  *  SPDX-FileCopyrightText: 2013 Giorgos Tsiapaliokas <terietor@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "view.h"
0008 
0009 #include <QDBusInterface>
0010 #include <QDBusReply>
0011 #include <QDebug>
0012 #include <QFileDialog>
0013 #include <QQmlContext>
0014 #include <QQmlEngine>
0015 #include <QQuickItem>
0016 
0017 #include <KDesktopFile>
0018 #include <KLocalizedString>
0019 
0020 #include <KPackage/Package>
0021 #include <KPackage/PackageLoader>
0022 #include <Plasma/PluginLoader>
0023 #include <plasmaquick/appletquickitem.h>
0024 
0025 class ViewerCorona : public Plasma::Corona
0026 {
0027 public:
0028     ViewerCorona()
0029         : Plasma::Corona()
0030         , m_view(nullptr)
0031     {
0032     }
0033 
0034     void setView(View *view)
0035     {
0036         m_view = view;
0037     }
0038 
0039     QRect screenGeometry(int id) const override
0040     {
0041         Q_UNUSED(id);
0042         if (m_view) {
0043             return m_view->geometry();
0044         } else {
0045             return QRect();
0046         }
0047     }
0048 
0049     int screenForContainment(const Plasma::Containment *containment) const override
0050     {
0051         return 0;
0052     }
0053 
0054 private:
0055     View *m_view;
0056 };
0057 
0058 View::View(ViewerCorona *cor, QWindow *parent)
0059     : PlasmaQuick::ContainmentView(cor, parent)
0060 {
0061     cor->setView(this);
0062     engine()->rootContext()->setContextProperty("desktop", this);
0063     setSource(QUrl::fromLocalFile(cor->kPackage().filePath("views", "Desktop.qml")));
0064 }
0065 
0066 View::~View()
0067 {
0068 }
0069 
0070 void View::resizeEvent(QResizeEvent *event)
0071 {
0072     emit corona()->screenGeometryChanged(0);
0073     emit corona()->availableScreenRectChanged(0);
0074     emit corona()->availableScreenRegionChanged(0);
0075     PlasmaQuick::ContainmentView::resizeEvent(event);
0076 }
0077 
0078 QString View::pluginFromPath(const QString &path) const
0079 {
0080     QDir dir(path);
0081     if (!dir.exists()) {
0082         return QString();
0083     }
0084 
0085     QString metadataPath = dir.absolutePath();
0086     if (!QFile(metadataPath).exists()) {
0087         return QString();
0088     } else {
0089         return metadataPath;
0090     }
0091 }
0092 
0093 void View::addApplet(const QString &applet)
0094 {
0095     QString metadataPath = pluginFromPath(applet);
0096 
0097     Plasma::Containment *c = containment();
0098 
0099     if (!c) {
0100         qCritical("Containment doesn't exist");
0101         return;
0102     }
0103 
0104     Plasma::Applet *a = nullptr;
0105     if (metadataPath.isEmpty()) {
0106         a = containment()->createApplet(applet);
0107     } else {
0108         a = Plasma::PluginLoader::self()->loadApplet(metadataPath);
0109 
0110         // Load translations from KPackage files if bundled
0111         // TODO: what to do in KF6?
0112         /*const QString localePath = a->kPackage().filePath("translations");
0113         if (!localePath.isEmpty()) {
0114             const QString localeDomain = QByteArray("plasma_applet_") + a->pluginMetaData().pluginId();
0115             KLocalizedString::addDomainLocaleDir(localeDomain.toLatin1(), localePath);
0116         }*/
0117 
0118         containment()->addApplet(a);
0119     }
0120 
0121     if (!a->pluginMetaData().isValid()) {
0122         // xgettext:no-c-format
0123         qCritical() << i18n("Applet %1 does not exist.", applet);
0124         return;
0125     }
0126     m_lastAppletName = applet;
0127 }
0128 
0129 void View::addContainment(const QString &cont)
0130 {
0131     QString actualCont = pluginFromPath(cont);
0132     if (actualCont.isEmpty()) {
0133         actualCont = cont;
0134     }
0135 
0136     Plasma::Containment *c = corona()->createContainment(actualCont);
0137 
0138     if (!c->pluginMetaData().isValid()) {
0139         // xgettext:no-c-format
0140         qCritical() << i18n("Containment %1 does not exist.", actualCont);
0141         return;
0142     }
0143 
0144     setContainment(c);
0145 
0146     connect(containment(), &Plasma::Containment::appletRemoved, [=](Plasma::Applet *applet) {
0147         if (applet && applet->pluginMetaData().isValid()) {
0148             addApplet(applet->pluginMetaData().pluginId());
0149         }
0150     });
0151 }
0152 
0153 void View::addFormFactor(const QString &formFactor)
0154 {
0155     Plasma::Types::FormFactor formFactorType = Plasma::Types::Planar;
0156     const QString ff = formFactor.toLower();
0157 
0158     if (ff.isEmpty() || ff == QStringLiteral("planar")) {
0159         formFactorType = Plasma::Types::Planar;
0160     } else if (ff == QStringLiteral("vertical")) {
0161         formFactorType = Plasma::Types::Vertical;
0162     } else if (ff == QStringLiteral("horizontal")) {
0163         formFactorType = Plasma::Types::Horizontal;
0164     } else if (ff == QStringLiteral("mediacenter")) {
0165         formFactorType = Plasma::Types::MediaCenter;
0166     } else if (ff == QStringLiteral("application")) {
0167         formFactorType = Plasma::Types::Application;
0168     } else {
0169         qWarning() << "FormFactor " << ff << "doesn't exist. Planar formFactor has been used!!";
0170     }
0171 
0172     Plasma::Containment *c = containment();
0173     if (!c) {
0174         qCritical("Containment doesn't exist!");
0175         return;
0176     }
0177 
0178     c->setFormFactor(formFactorType);
0179 }
0180 
0181 void View::changeFormFactor(int formFactor)
0182 {
0183     QString formFactorType = "planar";
0184     switch (formFactor) {
0185     case Plasma::Types::Planar:
0186         formFactorType = "planar";
0187         break;
0188     case Plasma::Types::Vertical:
0189         formFactorType = "vertical";
0190         break;
0191     case Plasma::Types::Horizontal:
0192         formFactorType = "horizontal";
0193         break;
0194     case Plasma::Types::MediaCenter:
0195         formFactorType = "mediacenter";
0196         break;
0197     case Plasma::Types::Application:
0198         formFactorType = "application";
0199         break;
0200     }
0201 
0202     addFormFactor(formFactorType);
0203 }
0204 
0205 void View::addLocation(const QString &location)
0206 {
0207     Plasma::Types::Location locationType = Plasma::Types::Floating;
0208 
0209     const QString l = location.toLower();
0210 
0211     if (l.isEmpty() || l == QStringLiteral("floating")) {
0212         locationType = Plasma::Types::Floating;
0213     } else if (l == QStringLiteral("desktop")) {
0214         locationType = Plasma::Types::Desktop;
0215     } else if (l == QStringLiteral("fullscreen")) {
0216         locationType = Plasma::Types::FullScreen;
0217     } else if (l == QStringLiteral("topedge")) {
0218         locationType = Plasma::Types::TopEdge;
0219     } else if (l == QStringLiteral("bottomedge")) {
0220         locationType = Plasma::Types::BottomEdge;
0221     } else if (l == QStringLiteral("rightedge")) {
0222         locationType = Plasma::Types::RightEdge;
0223     } else if (l == QStringLiteral("leftedge")) {
0224         locationType = Plasma::Types::LeftEdge;
0225     } else {
0226         qWarning() << "Location " << l << "doesn't exist. Floating location has been used!!";
0227     }
0228 
0229     Plasma::Containment *c = containment();
0230     if (!c) {
0231         qCritical("Containment doesn't exist!");
0232         return;
0233     }
0234 
0235     setLocation(locationType);
0236 }
0237 
0238 void View::emitExternalData(const QString &data)
0239 {
0240     if (data.isEmpty()) {
0241         return;
0242     }
0243 
0244     Plasma::Applet *applet = containment()->applets().constFirst();
0245 
0246     PlasmaQuick::AppletQuickItem *graphicsObject = PlasmaQuick::AppletQuickItem::itemForApplet(applet);
0247 
0248     if (!graphicsObject) {
0249         return;
0250     }
0251 
0252     QMetaObject::invokeMethod(graphicsObject, "externalData", Q_ARG(QString, QString()), Q_ARG(QVariant, data));
0253 }
0254 
0255 void View::changeLocation(int location)
0256 {
0257     QString locationType = "floating";
0258     switch (location) {
0259     case Plasma::Types::Floating:
0260         locationType = "floating";
0261         break;
0262     case Plasma::Types::Desktop:
0263         locationType = "desktop";
0264         break;
0265     case Plasma::Types::FullScreen:
0266         locationType = "fullscreen";
0267         break;
0268     case Plasma::Types::TopEdge:
0269         locationType = "topedge";
0270         break;
0271     case Plasma::Types::BottomEdge:
0272         locationType = "bottomedge";
0273         break;
0274     case Plasma::Types::RightEdge:
0275         locationType = "rightedge";
0276         break;
0277     case Plasma::Types::LeftEdge:
0278         locationType = "leftedge";
0279         break;
0280     }
0281 
0282     addLocation(locationType);
0283 }
0284 
0285 ViewerCorona *View::createCorona()
0286 {
0287     KPackage::Package package = KPackage::PackageLoader::self()->loadPackage("Plasma/Shell");
0288     package.setPath("org.kde.plasma.plasmoidviewershell");
0289 
0290     ViewerCorona *cor = new ViewerCorona();
0291     cor->setKPackage(package);
0292 
0293     return cor;
0294 }
0295 
0296 void View::takeScreenShot()
0297 {
0298     QDBusInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QStringLiteral("org.kde.kwin.Screenshot"));
0299 
0300     QDBusPendingCall async = interface.asyncCall(QStringLiteral("screenshotArea"), x(), y(), width(), height());
0301 
0302     QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this);
0303 
0304     connect(watcher, &QDBusPendingCallWatcher::finished, [](QDBusPendingCallWatcher *call) {
0305         QDBusPendingReply<QString> reply = *call;
0306         call->deleteLater();
0307 
0308         if (!reply.isValid()) {
0309             qDebug() << "The screenshot has failed, the reply is invalid with error" << reply.error().message();
0310             return;
0311         }
0312 
0313         QString dest = QFileDialog::getSaveFileName(nullptr, i18nc("@title:window", "Save Screenshot"), QDir::homePath(), QStringLiteral("Images (*.png)"));
0314 
0315         if (dest.isEmpty()) {
0316             return;
0317         }
0318 
0319         if (!dest.endsWith(QStringLiteral(".png"))) {
0320             dest.append(QStringLiteral(".png"));
0321         }
0322 
0323         QFile f(reply.value());
0324         f.rename(dest);
0325     });
0326 }
0327 
0328 #include "moc_view.cpp"