File indexing completed on 2024-04-28 16:49:26

0001 /*
0002 *  Copyright 2019  Michail Vourlakos <mvourlakos@gmail.com>
0003 *
0004 *  This file is part of Latte-Dock
0005 *
0006 *  Latte-Dock is free software; you can redistribute it and/or
0007 *  modify it under the terms of the GNU General Public License as
0008 *  published by the Free Software Foundation; either version 2 of
0009 *  the License, or (at your option) any later version.
0010 *
0011 *  Latte-Dock is distributed in the hope that it will be useful,
0012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 *  GNU General Public License for more details.
0015 *
0016 *  You should have received a copy of the GNU General Public License
0017 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018 */
0019 
0020 #include "indicator.h"
0021 
0022 // local
0023 #include "indicatorinfo.h"
0024 #include "../view.h"
0025 #include "../../lattecorona.h"
0026 #include "../../indicator/factory.h"
0027 #include "../../../liblatte2/types.h"
0028 
0029 // Qt
0030 #include <QFileDialog>
0031 
0032 // KDE
0033 #include <KLocalizedString>
0034 #include <KPluginMetaData>
0035 #include <KDeclarative/ConfigPropertyMap>
0036 #include <KDeclarative/QmlObjectSharedEngine>
0037 
0038 namespace Latte {
0039 namespace ViewPart {
0040 
0041 Indicator::Indicator(Latte::View *parent)
0042     : QObject(parent),
0043       m_view(parent),
0044       m_info(new IndicatorPart::Info(this)),
0045       m_resources(new IndicatorPart::Resources(this))
0046 {
0047     m_corona = qobject_cast<Latte::Corona *>(m_view->corona());
0048     loadConfig();
0049 
0050     connect(this, &Indicator::enabledChanged, this, &Indicator::saveConfig);
0051     connect(this, &Indicator::enabledForAppletsChanged, this, &Indicator::saveConfig);
0052     connect(this, &Indicator::paddingChanged, this, &Indicator::saveConfig);
0053     connect(this, &Indicator::pluginChanged, this, &Indicator::saveConfig);
0054 
0055     connect(m_view, &Latte::View::latteTasksArePresentChanged, this, &Indicator::latteTasksArePresentChanged);
0056 
0057     connect(m_view, &Latte::View::customPluginsChanged, [this]() {
0058         if (m_corona && !m_corona->indicatorFactory()->pluginExists(m_type)) {
0059             setType("org.kde.latte.default");
0060         }
0061 
0062         emit customPluginsChanged();
0063     });
0064 
0065     connect(this, &Indicator::pluginChanged, [this]() {
0066         if ((m_type != "org.kde.latte.default") && m_type != "org.kde.latte.plasma") {
0067             setCustomType(m_type);
0068         }
0069     });
0070 
0071     load(m_type);
0072 
0073     loadPlasmaComponent();
0074 }
0075 
0076 Indicator::~Indicator()
0077 {
0078     if (m_component) {
0079         m_component->deleteLater();
0080     }
0081 
0082     if (m_configLoader) {
0083         m_configLoader->deleteLater();
0084     }
0085 
0086     if (m_configuration) {
0087         m_configuration->deleteLater();
0088     }
0089 
0090     if (m_info) {
0091         m_info->deleteLater();
0092     }
0093 }
0094 
0095 bool Indicator::enabled() const
0096 {
0097     return m_enabled;
0098 }
0099 
0100 void Indicator::setEnabled(bool enabled)
0101 {
0102     if (m_enabled == enabled) {
0103         return;
0104     }
0105 
0106     m_enabled = enabled;
0107     emit enabledChanged();
0108 }
0109 
0110 bool Indicator::enabledForApplets() const
0111 {
0112     return m_enabledForApplets;
0113 }
0114 
0115 void Indicator::setEnabledForApplets(bool enabled)
0116 {
0117     if (m_enabledForApplets == enabled) {
0118         return;
0119     }
0120 
0121     m_enabledForApplets = enabled;
0122     emit enabledForAppletsChanged();
0123 }
0124 
0125 bool Indicator::latteTasksArePresent()
0126 {
0127     return m_view->latteTasksArePresent();
0128 }
0129 
0130 bool Indicator::providesConfigUi() const
0131 {
0132     return m_providesConfigUi;
0133 }
0134 
0135 void Indicator::setProvidesConfigUi(bool provides)
0136 {
0137     if (m_providesConfigUi == provides) {
0138         return;
0139     }
0140 
0141     m_providesConfigUi = provides;
0142     emit providesConfigUiChanged();
0143 }
0144 
0145 float Indicator::padding() const
0146 {
0147     return m_padding;
0148 }
0149 
0150 void Indicator::setPadding(float padding)
0151 {
0152     if (m_padding == padding) {
0153         return;
0154     }
0155 
0156     m_padding = padding;
0157     emit paddingChanged();
0158 }
0159 
0160 bool Indicator::pluginIsReady()
0161 {
0162     return m_pluginIsReady;
0163 }
0164 
0165 void Indicator::setPluginIsReady(bool ready)
0166 {
0167     if (m_pluginIsReady == ready) {
0168         return;
0169     }
0170 
0171     m_pluginIsReady = ready;
0172     emit pluginIsReadyChanged();
0173 }
0174 
0175 QString Indicator::type() const
0176 {
0177     return m_type;
0178 }
0179 
0180 void Indicator::setType(QString type)
0181 {
0182     if (m_type == type) {
0183         return;
0184     }
0185 
0186     load(type);
0187 }
0188 
0189 QString Indicator::customType() const
0190 {
0191     return m_customType;
0192 }
0193 
0194 void Indicator::setCustomType(QString type)
0195 {
0196     if (m_customType == type) {
0197         return;
0198     }
0199 
0200     m_customType = type;
0201     emit customPluginChanged();
0202 }
0203 
0204 int Indicator::customPluginsCount() const
0205 {
0206     return m_corona->indicatorFactory()->customPluginsCount();
0207 }
0208 
0209 QString Indicator::uiPath() const
0210 {
0211     return m_corona->indicatorFactory()->uiPath(m_type);
0212 }
0213 
0214 QStringList Indicator::customPluginIds() const
0215 {
0216     return m_corona->indicatorFactory()->customPluginIds();
0217 }
0218 
0219 QStringList Indicator::customPluginNames() const
0220 {
0221     return m_corona->indicatorFactory()->customPluginNames();
0222 }
0223 
0224 QStringList Indicator::customLocalPluginIds() const
0225 {
0226     return m_corona->indicatorFactory()->customLocalPluginIds();
0227 }
0228 
0229 IndicatorPart::Info *Indicator::info() const
0230 {
0231     return m_info;
0232 }
0233 
0234 IndicatorPart::Resources *Indicator::resources() const
0235 {
0236     return m_resources;
0237 }
0238 
0239 QQmlComponent *Indicator::component() const
0240 {
0241     return m_component;
0242 }
0243 
0244 QQmlComponent *Indicator::plasmaComponent() const
0245 {
0246     return m_plasmaComponent;
0247 }
0248 
0249 QObject *Indicator::configuration() const
0250 {
0251     return m_configuration;
0252 }
0253 
0254 void Indicator::load(QString type)
0255 {
0256     KPluginMetaData metadata = m_corona->indicatorFactory()->metadata(type);
0257 
0258     if (metadata.isValid()) {
0259         bool state{m_enabled};
0260         //! remove all previous indicators
0261         setPluginIsReady(false);
0262 
0263         m_metadata = metadata;
0264         m_type = type;
0265 
0266         QString path = m_metadata.fileName();
0267         m_pluginPath = path.remove("metadata.desktop");
0268 
0269         updateScheme();
0270         updateComponent();
0271 
0272         emit pluginChanged();
0273 
0274         //! create all indicators with the new type
0275         setPluginIsReady(true);
0276     } else if (type!="org.kde.latte.default") {
0277         qDebug() << " Indicator metadata are not valid : " << type;
0278         setType("org.kde.latte.default");
0279     }
0280 }
0281 
0282 void Indicator::updateComponent()
0283 {
0284     auto prevComponent = m_component;
0285 
0286     QString uiPath = m_metadata.value("X-Latte-MainScript");
0287 
0288     if (!uiPath.isEmpty()) {
0289         uiPath = m_pluginPath + "package/" + uiPath;
0290         m_component = new QQmlComponent(m_view->engine(), uiPath);
0291     }
0292 
0293     if (prevComponent) {
0294         prevComponent->deleteLater();
0295     }
0296 }
0297 
0298 void Indicator::loadPlasmaComponent()
0299 {
0300     auto prevComponent = m_plasmaComponent;
0301 
0302     KPluginMetaData metadata = m_corona->indicatorFactory()->metadata("org.kde.latte.plasma");
0303     QString uiPath = metadata.value("X-Latte-MainScript");
0304 
0305     if (!uiPath.isEmpty()) {
0306         QString path = metadata.fileName();
0307         path = path.remove("metadata.desktop");
0308 
0309         uiPath = path + "package/" + uiPath;
0310         m_plasmaComponent = new QQmlComponent(m_view->engine(), uiPath);
0311     }
0312 
0313     if (prevComponent) {
0314         prevComponent->deleteLater();
0315     }
0316 
0317     emit plasmaComponentChanged();
0318 }
0319 
0320 void Indicator::configUiFor(QString type, QQuickItem *parent)
0321 {
0322     if (m_lastCreatedConfigUi) {
0323         delete m_lastCreatedConfigUi;
0324         m_lastCreatedConfigUi = nullptr;
0325     }
0326     auto prevConfigUi = m_lastCreatedConfigUi;
0327 
0328     KPluginMetaData metadata;
0329 
0330     if (m_metadata.pluginId() == type) {
0331         metadata = m_metadata;
0332     } else {
0333         metadata = m_corona->indicatorFactory()->metadata(type);
0334     }
0335 
0336     if (metadata.isValid()) {
0337         QString uiPath = metadata.value("X-Latte-ConfigUi");
0338 
0339         if (!uiPath.isEmpty()) {
0340             m_lastCreatedConfigUi = new KDeclarative::QmlObjectSharedEngine(parent);
0341             m_lastCreatedConfigUi->setTranslationDomain(QLatin1String("latte_indicator_") + m_metadata.pluginId());
0342             m_lastCreatedConfigUi->setInitializationDelayed(true);
0343             uiPath = m_pluginPath + "package/" + uiPath;
0344             m_lastCreatedConfigUi->setSource(QUrl::fromLocalFile(uiPath));
0345             m_lastCreatedConfigUi->rootContext()->setContextProperty(QStringLiteral("dialog"), parent);
0346             m_lastCreatedConfigUi->rootContext()->setContextProperty(QStringLiteral("indicator"), this);
0347             m_lastCreatedConfigUi->completeInitialization();
0348 
0349             QQuickItem *qmlItem = qobject_cast<QQuickItem*>(m_lastCreatedConfigUi->rootObject());
0350             qmlItem->setParentItem(parent);
0351 
0352             setProvidesConfigUi(true);
0353         } else {
0354             setProvidesConfigUi(false);
0355         }
0356     }
0357 }
0358 
0359 void Indicator::unloadIndicators()
0360 {
0361     setPluginIsReady(false);
0362 }
0363 
0364 void Indicator::updateScheme()
0365 {
0366     auto prevConfigLoader = m_configLoader;
0367     auto prevConfiguration = m_configuration;
0368 
0369     QString xmlPath = m_metadata.value("X-Latte-ConfigXml");
0370 
0371     if (!xmlPath.isEmpty()) {
0372         QFile file(m_pluginPath + "package/" + xmlPath);
0373         m_configLoader = new KConfigLoader(m_view->containment()->config().group("Indicator").group(m_metadata.pluginId()), &file);
0374         m_configuration = new KDeclarative::ConfigPropertyMap(m_configLoader, this);
0375     } else {
0376         m_configLoader = nullptr;
0377         m_configuration = nullptr;
0378     }
0379 
0380     if (prevConfigLoader) {
0381         prevConfigLoader->deleteLater();
0382     }
0383 
0384     if (prevConfiguration) {
0385         prevConfiguration->deleteLater();
0386     }
0387 }
0388 
0389 void Indicator::addIndicator()
0390 {
0391     QFileDialog *fileDialog = new QFileDialog(nullptr
0392                                               , i18nc("add indicator", "Add Indicator")
0393                                               , QDir::homePath()
0394                                               , QStringLiteral("indicator.latte"));
0395 
0396     fileDialog->setFileMode(QFileDialog::AnyFile);
0397     fileDialog->setAcceptMode(QFileDialog::AcceptOpen);
0398     fileDialog->setDefaultSuffix("indicator.latte");
0399 
0400     QStringList filters;
0401     filters << QString(i18nc("add indicator file", "Latte Indicator") + "(*.indicator.latte)");
0402     fileDialog->setNameFilters(filters);
0403 
0404     connect(fileDialog, &QFileDialog::finished, fileDialog, &QFileDialog::deleteLater);
0405 
0406     connect(fileDialog, &QFileDialog::fileSelected, this, [&](const QString & file) {
0407         qDebug() << "Trying to import indicator file ::: " << file;
0408         m_corona->indicatorFactory()->importIndicatorFile(file);
0409     });
0410 
0411     fileDialog->open();
0412 }
0413 
0414 void Indicator::downloadIndicator()
0415 {
0416     //! call asynchronously in order to not crash when view settings window
0417     //! loses focus and it closes
0418     QTimer::singleShot(0, [this]() {
0419         m_corona->indicatorFactory()->downloadIndicator();
0420     });
0421 }
0422 
0423 void Indicator::removeIndicator(QString pluginId)
0424 {    //! call asynchronously in order to not crash when view settings window
0425     //! loses focus and it closes
0426     QTimer::singleShot(0, [this, pluginId]() {
0427         m_corona->indicatorFactory()->removeIndicator(pluginId);
0428     });
0429 }
0430 
0431 void Indicator::loadConfig()
0432 {
0433     auto config = m_view->containment()->config().group("Indicator");
0434     m_customType = config.readEntry("customType", QString());
0435     m_enabled = config.readEntry("enabled", true);
0436     m_enabledForApplets = config.readEntry("enabledForApplets", true);
0437     m_padding = config.readEntry("padding", (float)0.08);
0438     m_type = config.readEntry("type", "org.kde.latte.default");
0439 }
0440 
0441 void Indicator::saveConfig()
0442 {
0443     auto config = m_view->containment()->config().group("Indicator");
0444     config.writeEntry("customType", m_customType);
0445     config.writeEntry("enabled", m_enabled);
0446     config.writeEntry("enabledForApplets", m_enabledForApplets);
0447     config.writeEntry("padding", m_padding);
0448     config.writeEntry("type", m_type);
0449 
0450     config.sync();
0451 }
0452 
0453 }
0454 }