File indexing completed on 2024-04-28 16:53:01

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 
0024 class ViewerCorona : public Plasma::Corona
0025 {
0026 public:
0027     ViewerCorona()
0028         : Plasma::Corona()
0029         , m_view(nullptr)
0030     {
0031     }
0032 
0033     void setView(View *view)
0034     {
0035         m_view = view;
0036     }
0037 
0038     QRect screenGeometry(int id) const override
0039     {
0040         Q_UNUSED(id);
0041         if (m_view) {
0042             return m_view->geometry();
0043         } else {
0044             return QRect();
0045         }
0046     }
0047 
0048     int screenForContainment(const Plasma::Containment *containment) const override
0049     {
0050         return 0;
0051     }
0052 
0053 private:
0054     View *m_view;
0055 };
0056 
0057 View::View(ViewerCorona *cor, bool konsoleVisible, QWindow *parent)
0058     : PlasmaQuick::ContainmentView(cor, parent)
0059 {
0060     cor->setView(this);
0061     m_konsoleVisible = konsoleVisible;
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();
0074     emit corona()->availableScreenRegionChanged();
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         const QString localePath = a->kPackage().filePath("translations");
0112         if (!localePath.isEmpty()) {
0113             const QString localeDomain = QByteArray("plasma_applet_") + a->pluginMetaData().pluginId();
0114             KLocalizedString::addDomainLocaleDir(localeDomain.toLatin1(), localePath);
0115         }
0116 
0117         containment()->addApplet(a);
0118     }
0119 
0120     if (!a->pluginMetaData().isValid()) {
0121         // xgettext:no-c-format
0122         qCritical() << i18n("Applet %1 does not exist.", applet);
0123         return;
0124     }
0125     m_lastAppletName = applet;
0126 }
0127 
0128 void View::addContainment(const QString &cont)
0129 {
0130     QString actualCont = pluginFromPath(cont);
0131     if (actualCont.isEmpty()) {
0132         actualCont = cont;
0133     }
0134 
0135     Plasma::Containment *c = corona()->createContainment(actualCont);
0136 
0137     if (!c->pluginMetaData().isValid()) {
0138         // xgettext:no-c-format
0139         qCritical() << i18n("Containment %1 does not exist.", actualCont);
0140         return;
0141     }
0142 
0143     setContainment(c);
0144 
0145     connect(containment(), &Plasma::Containment::appletRemoved, [=](Plasma::Applet *applet) {
0146         if (applet && applet->pluginMetaData().isValid()) {
0147             addApplet(applet->pluginMetaData().pluginId());
0148         }
0149     });
0150 }
0151 
0152 void View::addFormFactor(const QString &formFactor)
0153 {
0154     Plasma::Types::FormFactor formFactorType = Plasma::Types::Planar;
0155     const QString ff = formFactor.toLower();
0156 
0157     if (ff.isEmpty() || ff == QStringLiteral("planar")) {
0158         formFactorType = Plasma::Types::Planar;
0159     } else if (ff == QStringLiteral("vertical")) {
0160         formFactorType = Plasma::Types::Vertical;
0161     } else if (ff == QStringLiteral("horizontal")) {
0162         formFactorType = Plasma::Types::Horizontal;
0163     } else if (ff == QStringLiteral("mediacenter")) {
0164         formFactorType = Plasma::Types::MediaCenter;
0165     } else if (ff == QStringLiteral("application")) {
0166         formFactorType = Plasma::Types::Application;
0167     } else {
0168         qWarning() << "FormFactor " << ff << "doesn't exist. Planar formFactor has been used!!";
0169     }
0170 
0171     Plasma::Containment *c = containment();
0172     if (!c) {
0173         qCritical("Containment doesn't exist!");
0174         return;
0175     }
0176 
0177     c->setFormFactor(formFactorType);
0178 }
0179 
0180 void View::changeFormFactor(int formFactor)
0181 {
0182     QString formFactorType = "planar";
0183     switch (formFactor) {
0184     case Plasma::Types::Planar:
0185         formFactorType = "planar";
0186         break;
0187     case Plasma::Types::Vertical:
0188         formFactorType = "vertical";
0189         break;
0190     case Plasma::Types::Horizontal:
0191         formFactorType = "horizontal";
0192         break;
0193     case Plasma::Types::MediaCenter:
0194         formFactorType = "mediacenter";
0195         break;
0196     case Plasma::Types::Application:
0197         formFactorType = "application";
0198         break;
0199     }
0200 
0201     addFormFactor(formFactorType);
0202 }
0203 
0204 void View::addLocation(const QString &location)
0205 {
0206     Plasma::Types::Location locationType = Plasma::Types::Floating;
0207 
0208     const QString l = location.toLower();
0209 
0210     if (l.isEmpty() || l == QStringLiteral("floating")) {
0211         locationType = Plasma::Types::Floating;
0212     } else if (l == QStringLiteral("desktop")) {
0213         locationType = Plasma::Types::Desktop;
0214     } else if (l == QStringLiteral("fullscreen")) {
0215         locationType = Plasma::Types::FullScreen;
0216     } else if (l == QStringLiteral("topedge")) {
0217         locationType = Plasma::Types::TopEdge;
0218     } else if (l == QStringLiteral("bottomedge")) {
0219         locationType = Plasma::Types::BottomEdge;
0220     } else if (l == QStringLiteral("rightedge")) {
0221         locationType = Plasma::Types::RightEdge;
0222     } else if (l == QStringLiteral("leftedge")) {
0223         locationType = Plasma::Types::LeftEdge;
0224     } else {
0225         qWarning() << "Location " << l << "doesn't exist. Floating location has been used!!";
0226     }
0227 
0228     Plasma::Containment *c = containment();
0229     if (!c) {
0230         qCritical("Containment doesn't exist!");
0231         return;
0232     }
0233 
0234     setLocation(locationType);
0235 }
0236 
0237 void View::emitExternalData(const QString &data)
0238 {
0239     if (data.isEmpty()) {
0240         return;
0241     }
0242 
0243     Plasma::Applet *applet = containment()->applets().constFirst();
0244 
0245     QObject *graphicsObject = qobject_cast<QQuickItem *>(applet->property("_plasma_graphicObject").value<QObject *>());
0246     if (!graphicsObject) {
0247         return;
0248     }
0249 
0250     QMetaObject::invokeMethod(graphicsObject, "externalData", Q_ARG(QString, QString()), Q_ARG(QVariant, data));
0251 }
0252 
0253 bool View::konsoleVisible()
0254 {
0255     return m_konsoleVisible;
0256 }
0257 
0258 void View::changeLocation(int location)
0259 {
0260     QString locationType = "floating";
0261     switch (location) {
0262     case Plasma::Types::Floating:
0263         locationType = "floating";
0264         break;
0265     case Plasma::Types::Desktop:
0266         locationType = "desktop";
0267         break;
0268     case Plasma::Types::FullScreen:
0269         locationType = "fullscreen";
0270         break;
0271     case Plasma::Types::TopEdge:
0272         locationType = "topedge";
0273         break;
0274     case Plasma::Types::BottomEdge:
0275         locationType = "bottomedge";
0276         break;
0277     case Plasma::Types::RightEdge:
0278         locationType = "rightedge";
0279         break;
0280     case Plasma::Types::LeftEdge:
0281         locationType = "leftedge";
0282         break;
0283     }
0284 
0285     addLocation(locationType);
0286 }
0287 
0288 ViewerCorona *View::createCorona()
0289 {
0290     KPackage::Package package = KPackage::PackageLoader::self()->loadPackage("Plasma/Shell");
0291     package.setPath("org.kde.plasma.plasmoidviewershell");
0292 
0293     ViewerCorona *cor = new ViewerCorona();
0294     cor->setKPackage(package);
0295 
0296     return cor;
0297 }
0298 
0299 void View::takeScreenShot()
0300 {
0301     QDBusInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QStringLiteral("org.kde.kwin.Screenshot"));
0302 
0303     QDBusPendingCall async = interface.asyncCall(QStringLiteral("screenshotArea"), x(), y(), width(), height());
0304 
0305     QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this);
0306 
0307     connect(watcher, &QDBusPendingCallWatcher::finished, [](QDBusPendingCallWatcher *call) {
0308         QDBusPendingReply<QString> reply = *call;
0309         call->deleteLater();
0310 
0311         if (!reply.isValid()) {
0312             qDebug() << "The screenshot has failed, the reply is invalid with error" << reply.error().message();
0313             return;
0314         }
0315 
0316         QString dest = QFileDialog::getSaveFileName(nullptr, i18nc("@title:window", "Save Screenshot"), QDir::homePath(), QStringLiteral("Images (*.png)"));
0317 
0318         if (dest.isEmpty()) {
0319             return;
0320         }
0321 
0322         if (!dest.endsWith(QStringLiteral(".png"))) {
0323             dest.append(QStringLiteral(".png"));
0324         }
0325 
0326         QFile f(reply.value());
0327         f.rename(dest);
0328     });
0329 }
0330 
0331 #include "moc_view.cpp"