File indexing completed on 2024-10-06 13:22:22
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 "factory.h" 0021 0022 // local 0023 #include "../layouts/importer.h" 0024 0025 // Qt 0026 #include <QDebug> 0027 #include <QDir> 0028 #include <QDirIterator> 0029 #include <QMessageBox> 0030 #include <QProcess> 0031 #include <QTemporaryDir> 0032 0033 // KDE 0034 #include <KDirWatch> 0035 #include <KLocalizedString> 0036 #include <KNotification> 0037 #include <KPluginMetaData> 0038 #include <KArchive/KTar> 0039 #include <KArchive/KZip> 0040 #include <KArchive/KArchiveEntry> 0041 #include <KArchive/KArchiveDirectory> 0042 #include <KNewStuff3/KNS3/DownloadDialog> 0043 0044 namespace Latte { 0045 namespace Indicator { 0046 0047 Factory::Factory(QObject *parent) 0048 : QObject(parent) 0049 { 0050 m_parentWidget = new QWidget(); 0051 0052 m_watchedPaths = Latte::Layouts::Importer::standardPaths(); 0053 0054 for(int i=0; i<m_watchedPaths.count(); ++i) { 0055 m_watchedPaths[i] = m_watchedPaths[i] + "/latte/indicators"; 0056 } 0057 0058 reload(); 0059 0060 //! track paths for changes 0061 for(const auto &dir : m_watchedPaths) { 0062 KDirWatch::self()->addDir(dir); 0063 } 0064 0065 connect(KDirWatch::self(), &KDirWatch::dirty, this, [ & ](const QString & path) { 0066 if (m_watchedPaths.contains(path)) { 0067 reload(); 0068 emit pluginsUpdated(); 0069 } 0070 }); 0071 0072 qDebug() << m_plugins["org.kde.latte.default"].name(); 0073 } 0074 0075 Factory::~Factory() 0076 { 0077 m_parentWidget->deleteLater(); 0078 } 0079 0080 bool Factory::pluginExists(QString id) const 0081 { 0082 return m_plugins.contains(id); 0083 } 0084 0085 int Factory::customPluginsCount() 0086 { 0087 return m_customPluginIds.count(); 0088 } 0089 0090 QStringList Factory::customPluginIds() 0091 { 0092 return m_customPluginIds; 0093 } 0094 0095 QStringList Factory::customPluginNames() 0096 { 0097 return m_customPluginNames; 0098 } 0099 0100 QStringList Factory::customLocalPluginIds() 0101 { 0102 return m_customLocalPluginIds; 0103 } 0104 0105 KPluginMetaData Factory::metadata(QString pluginId) 0106 { 0107 if (m_plugins.contains(pluginId)) { 0108 return m_plugins[pluginId]; 0109 } 0110 0111 return KPluginMetaData(); 0112 } 0113 0114 void Factory::reload() 0115 { 0116 m_plugins.clear(); 0117 m_pluginUiPaths.clear(); 0118 m_customPluginIds.clear(); 0119 m_customPluginNames.clear(); 0120 m_customLocalPluginIds.clear(); 0121 0122 for(const auto &path : m_watchedPaths) { 0123 QDir standard(path); 0124 0125 if (standard.exists()) { 0126 QStringList pluginDirs = standard.entryList(QStringList(),QDir::AllDirs | QDir::NoSymLinks); 0127 0128 for (const auto &pluginDir : pluginDirs) { 0129 if (pluginDir != "." && pluginDir != "..") { 0130 QString metadataFile = standard.absolutePath() + "/" + pluginDir + "/metadata.desktop"; 0131 0132 if(QFileInfo(metadataFile).exists()) { 0133 KPluginMetaData metadata = KPluginMetaData::fromDesktopFile(metadataFile); 0134 0135 if (metadataAreValid(metadata)) { 0136 QString uiFile = standard.absolutePath() + "/" + pluginDir + "/package/" + metadata.value("X-Latte-MainScript"); 0137 0138 if (QFileInfo(uiFile).exists() && !m_plugins.contains(metadata.pluginId())) { 0139 m_plugins[metadata.pluginId()] = metadata; 0140 0141 if ((metadata.pluginId() != "org.kde.latte.default") 0142 && (metadata.pluginId() != "org.kde.latte.plasma")) { 0143 m_customPluginIds << metadata.pluginId(); 0144 m_customPluginNames << metadata.name(); 0145 } 0146 0147 if (standard.absolutePath().startsWith(QDir::homePath())) { 0148 m_customLocalPluginIds << metadata.pluginId(); 0149 } 0150 0151 m_pluginUiPaths[metadata.pluginId()] = QFileInfo(uiFile).absolutePath(); 0152 0153 QString pluginPath = metadata.fileName().remove("metadata.desktop"); 0154 qDebug() << " Indicator Package Loaded ::: " << metadata.name() << " [" << metadata.pluginId() << "]" << " - [" <<pluginPath<<"]"; 0155 0156 /*qDebug() << " Indicator value ::: " << metadata.pluginId(); 0157 qDebug() << " Indicator value ::: " << metadata.fileName(); 0158 qDebug() << " Indicator value ::: " << metadata.value("X-Latte-MainScript"); 0159 qDebug() << " Indicator value ::: " << metadata.value("X-Latte-ConfigUi"); 0160 qDebug() << " Indicator value ::: " << metadata.value("X-Latte-ConfigXml");*/ 0161 } 0162 } 0163 } 0164 } 0165 } 0166 } 0167 } 0168 0169 emit customPluginsChanged(); 0170 } 0171 0172 bool Factory::metadataAreValid(KPluginMetaData &metadata) 0173 { 0174 return metadata.isValid() 0175 && metadata.category() == "Latte Indicator" 0176 && !metadata.value("X-Latte-MainScript").isEmpty(); 0177 } 0178 0179 bool Factory::metadataAreValid(QString &file) 0180 { 0181 if (QFileInfo(file).exists()) { 0182 KPluginMetaData metadata = KPluginMetaData::fromDesktopFile(file); 0183 return metadata.isValid(); 0184 } 0185 0186 return false; 0187 } 0188 0189 QString Factory::uiPath(QString pluginName) const 0190 { 0191 if (!m_pluginUiPaths.contains(pluginName)) { 0192 return ""; 0193 } 0194 0195 return m_pluginUiPaths[pluginName]; 0196 } 0197 0198 Latte::Types::ImportExportState Factory::importIndicatorFile(QString compressedFile) 0199 { 0200 auto showNotificationError = []() { 0201 auto notification = new KNotification("import-fail", KNotification::CloseOnTimeout); 0202 notification->setText(i18n("Failed to import indicator")); 0203 notification->sendEvent(); 0204 }; 0205 0206 auto showNotificationSucceed = [](QString name, bool updated) { 0207 auto notification = new KNotification("import-done", KNotification::CloseOnTimeout); 0208 notification->setText(updated ? i18nc("indicator_name, imported updated","%0 indicator updated successfully").arg(name) : 0209 i18nc("indicator_name, imported success","%0 indicator installed successfully").arg(name)); 0210 notification->sendEvent(); 0211 }; 0212 0213 KArchive *archive; 0214 0215 KZip *zipArchive = new KZip(compressedFile); 0216 zipArchive->open(QIODevice::ReadOnly); 0217 0218 //! if the file isnt a zip archive 0219 if (!zipArchive->isOpen()) { 0220 delete zipArchive; 0221 0222 KTar *tarArchive = new KTar(compressedFile, QStringLiteral("application/x-tar")); 0223 tarArchive->open(QIODevice::ReadOnly); 0224 0225 if (!tarArchive->isOpen()) { 0226 delete tarArchive; 0227 showNotificationError(); 0228 return Latte::Types::Failed; 0229 } else { 0230 archive = tarArchive; 0231 } 0232 } else { 0233 archive = zipArchive; 0234 } 0235 0236 QTemporaryDir archiveTempDir; 0237 archive->directory()->copyTo(archiveTempDir.path()); 0238 0239 //metadata file 0240 QString packagePath = archiveTempDir.path(); 0241 QString metadataFile = archiveTempDir.path() + "/metadata.desktop"; 0242 0243 if (!QFileInfo(metadataFile).exists()){ 0244 QDirIterator iter(archiveTempDir.path(), QDir::Dirs | QDir::NoDotAndDotDot); 0245 0246 while(iter.hasNext() ) { 0247 QString currentPath = iter.next(); 0248 0249 QString tempMetadata = currentPath + "/metadata.desktop"; 0250 0251 if (QFileInfo(tempMetadata).exists()) { 0252 metadataFile = tempMetadata; 0253 packagePath = currentPath; 0254 } 0255 } 0256 } 0257 0258 KPluginMetaData metadata = KPluginMetaData::fromDesktopFile(metadataFile); 0259 0260 if (metadataAreValid(metadata)) { 0261 QStringList standardPaths = Latte::Layouts::Importer::standardPaths(); 0262 QString installPath = standardPaths[0] + "/latte/indicators/" + metadata.pluginId(); 0263 0264 bool updated{QDir(installPath).exists()}; 0265 0266 if (QDir(installPath).exists()) { 0267 QDir(installPath).removeRecursively(); 0268 } 0269 0270 QProcess process; 0271 process.start(QString("mv " +packagePath + " " + installPath)); 0272 process.waitForFinished(); 0273 QString output(process.readAllStandardOutput()); 0274 0275 showNotificationSucceed(metadata.name(), updated); 0276 return Latte::Types::Installed; 0277 } 0278 0279 showNotificationError(); 0280 return Latte::Types::Failed; 0281 } 0282 0283 void Factory::removeIndicator(QString id) 0284 { 0285 if (m_plugins.contains(id)) { 0286 QString pluginName = m_plugins[id].name(); 0287 0288 auto msg = new QMessageBox(m_parentWidget); 0289 msg->setIcon(QMessageBox::Warning); 0290 msg->setWindowTitle(i18n("Remove Indicator")); 0291 msg->setText( 0292 i18n("Do you want to remove <b>%0</b> indicator from your system?").arg(pluginName)); 0293 msg->setStandardButtons(QMessageBox::Yes | QMessageBox::No); 0294 msg->setDefaultButton(QMessageBox::No); 0295 0296 connect(msg, &QMessageBox::finished, this, [ &, msg, id, pluginName](int result) { 0297 auto showRemovedSucceed = [](QString name) { 0298 auto notification = new KNotification("remove-done", KNotification::CloseOnTimeout); 0299 notification->setText(i18nc("indicator_name, removed success","<b>%0</b> indicator removed successfully").arg(name)); 0300 notification->sendEvent(); 0301 }; 0302 0303 if (result == QMessageBox::Yes) { 0304 qDebug() << "Trying to remove indicator :: " << id; 0305 QProcess process; 0306 process.start(QString("kpackagetool5 -r " +id + " -t Latte/Indicator")); 0307 process.waitForFinished(); 0308 showRemovedSucceed(pluginName); 0309 } 0310 }); 0311 0312 msg->open(); 0313 } 0314 } 0315 0316 void Factory::downloadIndicator() 0317 { 0318 KNS3::DownloadDialog dialog(QStringLiteral("latte-indicators.knsrc"), m_parentWidget); 0319 0320 dialog.exec(); 0321 } 0322 0323 } 0324 }