File indexing completed on 2024-04-28 04:38:39

0001 /*
0002     SPDX-FileCopyrightText: 2009 Andreas Pakulat <apaku@gmx.de>
0003     SPDX-FileCopyrightText: 2009 Niko Sams <niko.sams@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "plasmoidexecutionconfig.h"
0009 #include "plasmoidexecutionjob.h"
0010 #include "debug.h"
0011 
0012 #include <KLocalizedString>
0013 #include <interfaces/ilaunchconfiguration.h>
0014 #include <interfaces/icore.h>
0015 #include <interfaces/iprojectcontroller.h>
0016 #include <interfaces/iproject.h>
0017 #include <interfaces/iruncontroller.h>
0018 #include <interfaces/iuicontroller.h>
0019 #include <project/projectmodel.h>
0020 #include <project/builderjob.h>
0021 #include <serialization/indexedstring.h>
0022 #include <util/kdevstringhandler.h>
0023 #include <util/executecompositejob.h>
0024 #include <util/path.h>
0025 
0026 #include <KMessageBox>
0027 #include <KParts/MainWindow>
0028 #include <KConfigGroup>
0029 #include <QMenu>
0030 #include <QLineEdit>
0031 class la;
0032 
0033 QIcon PlasmoidExecutionConfig::icon() const
0034 {
0035     return QIcon::fromTheme(QStringLiteral("system-run"));
0036 }
0037 
0038 QStringList readProcess(QProcess* p)
0039 {
0040     QStringList ret;
0041     while(!p->atEnd()) {
0042         QByteArray line = p->readLine();
0043         int nameEnd=line.indexOf(' ');
0044         if(nameEnd>0) {
0045             ret += QString::fromUtf8(line.left(nameEnd));
0046         }
0047     }
0048     return ret;
0049 }
0050 
0051 PlasmoidExecutionConfig::PlasmoidExecutionConfig( QWidget* parent )
0052     : LaunchConfigurationPage( parent )
0053 {
0054     setupUi(this);
0055     connect( identifier->lineEdit(), &QLineEdit::textEdited, this, &PlasmoidExecutionConfig::changed );
0056 
0057     QProcess pPlasmoids;
0058     pPlasmoids.start(QStringLiteral("plasmoidviewer"), QStringList(QStringLiteral("--list")), QIODevice::ReadOnly);
0059 
0060     QProcess pThemes;
0061     pThemes.start(QStringLiteral("plasmoidviewer"), QStringList(QStringLiteral("--list-themes")), QIODevice::ReadOnly);
0062     pThemes.waitForFinished();
0063     pPlasmoids.waitForFinished();
0064 
0065     const auto plasmoidListing = readProcess(&pPlasmoids);
0066     for (const QString& plasmoid : plasmoidListing) {
0067         identifier->addItem(plasmoid);
0068     }
0069 
0070     themes->addItem(QString());
0071     const auto themeListing = readProcess(&pThemes);
0072     for (const QString& theme : themeListing) {
0073         themes->addItem(theme);
0074     }
0075 
0076     connect( dependencies, &KDevelop::DependenciesWidget::changed, this, &PlasmoidExecutionConfig::changed );
0077 }
0078 
0079 void PlasmoidExecutionConfig::saveToConfiguration( KConfigGroup cfg, KDevelop::IProject* project ) const
0080 {
0081     Q_UNUSED( project );
0082     cfg.writeEntry("PlasmoidIdentifier", identifier->lineEdit()->text());
0083     QStringList args{
0084         QStringLiteral("--formfactor"),
0085         formFactor->currentText(),
0086     };
0087     if(!themes->currentText().isEmpty()) {
0088         args += QStringLiteral("--theme");
0089         args += themes->currentText();
0090     }
0091     cfg.writeEntry("Arguments", args);
0092 
0093     QVariantList deps = dependencies->dependencies();
0094     cfg.writeEntry( "Dependencies", KDevelop::qvariantToString( QVariant( deps ) ) );
0095 }
0096 
0097 void PlasmoidExecutionConfig::loadFromConfiguration(const KConfigGroup& cfg, KDevelop::IProject* )
0098 {
0099     bool b = blockSignals( true );
0100     identifier->lineEdit()->setText(cfg.readEntry("PlasmoidIdentifier", ""));
0101     blockSignals( b );
0102 
0103     QStringList arguments = cfg.readEntry("Arguments", QStringList());
0104     int idxFormFactor = arguments.indexOf(QStringLiteral("--formfactor"))+1;
0105     if(idxFormFactor>0)
0106         formFactor->setCurrentIndex(formFactor->findText(arguments[idxFormFactor]));
0107 
0108     int idxTheme = arguments.indexOf(QStringLiteral("--theme"))+1;
0109     if(idxTheme>0)
0110         themes->setCurrentIndex(themes->findText(arguments[idxTheme]));
0111 
0112     dependencies->setDependencies( KDevelop::stringToQVariant( cfg.readEntry( "Dependencies", QString() ) ).toList());
0113 }
0114 
0115 QString PlasmoidExecutionConfig::title() const
0116 {
0117     return i18nc("@title:tab", "Configure Plasmoid Execution");
0118 }
0119 
0120 QList< KDevelop::LaunchConfigurationPageFactory* > PlasmoidLauncher::configPages() const
0121 {
0122     return QList<KDevelop::LaunchConfigurationPageFactory*>();
0123 }
0124 
0125 QString PlasmoidLauncher::description() const
0126 {
0127     return i18n("Display a plasmoid");
0128 }
0129 
0130 QString PlasmoidLauncher::id()
0131 {
0132     return QStringLiteral("PlasmoidLauncher");
0133 }
0134 
0135 QString PlasmoidLauncher::name() const
0136 {
0137     return i18n("Plasmoid Launcher");
0138 }
0139 
0140 PlasmoidLauncher::PlasmoidLauncher(ExecutePlasmoidPlugin* plugin)
0141     : m_plugin(plugin)
0142 {
0143 }
0144 
0145 KJob* PlasmoidLauncher::start(const QString& launchMode, KDevelop::ILaunchConfiguration* cfg)
0146 {
0147     Q_ASSERT(cfg);
0148     if( !cfg )
0149     {
0150         return nullptr;
0151     }
0152 
0153     if( launchMode == QLatin1String("execute") )
0154     {
0155         KJob* depsJob = dependencies(cfg);
0156         QList<KJob*> jobs;
0157         if(depsJob)
0158             jobs << depsJob;
0159         jobs << new PlasmoidExecutionJob(m_plugin, cfg);
0160 
0161         return new KDevelop::ExecuteCompositeJob( KDevelop::ICore::self()->runController(), jobs );
0162     }
0163     qCWarning(EXECUTEPLASMOID) << "Unknown launch mode " << launchMode << "for config:" << cfg->name();
0164     return nullptr;
0165 }
0166 
0167 KJob* PlasmoidLauncher::calculateDependencies(KDevelop::ILaunchConfiguration* cfg)
0168 {
0169     const QVariantList deps = KDevelop::stringToQVariant(cfg->config().readEntry("Dependencies", QString())).toList();
0170     if( !deps.isEmpty() )
0171     {
0172         KDevelop::ProjectModel* model = KDevelop::ICore::self()->projectController()->projectModel();
0173         QList<KDevelop::ProjectBaseItem*> items;
0174         for (const QVariant& dep : deps) {
0175             KDevelop::ProjectBaseItem* item = model->itemFromIndex( model->pathToIndex( dep.toStringList() ) );
0176             if( item )
0177             {
0178                 items << item;
0179             }
0180             else
0181             {
0182                 KMessageBox::error(KDevelop::ICore::self()->uiController()->activeMainWindow(),
0183                                    i18n("Could not resolve the dependency: %1", dep.toString()));
0184             }
0185         }
0186         auto* job = new KDevelop::BuilderJob;
0187         job->addItems( KDevelop::BuilderJob::Install, items );
0188         job->updateJobName();
0189         return job;
0190     }
0191     return nullptr;
0192 }
0193 
0194 KJob* PlasmoidLauncher::dependencies(KDevelop::ILaunchConfiguration* cfg)
0195 {
0196     return calculateDependencies(cfg);
0197 }
0198 
0199 
0200 QStringList PlasmoidLauncher::supportedModes() const
0201 {
0202     return QStringList() << QStringLiteral("execute");
0203 }
0204 
0205 KDevelop::LaunchConfigurationPage* PlasmoidPageFactory::createWidget(QWidget* parent)
0206 {
0207     return new PlasmoidExecutionConfig( parent );
0208 }
0209 
0210 PlasmoidPageFactory::PlasmoidPageFactory()
0211 {}
0212 
0213 PlasmoidExecutionConfigType::PlasmoidExecutionConfigType()
0214 {
0215     factoryList.append( new PlasmoidPageFactory );
0216 }
0217 
0218 PlasmoidExecutionConfigType::~PlasmoidExecutionConfigType()
0219 {
0220     qDeleteAll(factoryList);
0221     factoryList.clear();
0222 }
0223 
0224 QString PlasmoidExecutionConfigType::name() const
0225 {
0226     return i18n("Plasmoid Launcher");
0227 }
0228 
0229 QList<KDevelop::LaunchConfigurationPageFactory*> PlasmoidExecutionConfigType::configPages() const
0230 {
0231     return factoryList;
0232 }
0233 
0234 QString PlasmoidExecutionConfigType::typeId()
0235 {
0236     return QStringLiteral("PlasmoidLauncherType");
0237 }
0238 
0239 QIcon PlasmoidExecutionConfigType::icon() const
0240 {
0241     return QIcon::fromTheme(QStringLiteral("plasma"));
0242 }
0243 
0244 static bool canLaunchMetadataFile(const KDevelop::Path &path)
0245 {
0246     KConfig cfg(path.toLocalFile(), KConfig::SimpleConfig);
0247     KConfigGroup group(&cfg, "Desktop Entry");
0248     QStringList services = group.readEntry("ServiceTypes", group.readEntry("X-KDE-ServiceTypes", QStringList()));
0249     return services.contains(QStringLiteral("Plasma/Applet"));
0250 }
0251 
0252 //don't bother, nobody uses this interface
0253 bool PlasmoidExecutionConfigType::canLaunch(const QUrl& ) const
0254 {
0255     return false;
0256 }
0257 
0258 bool PlasmoidExecutionConfigType::canLaunch(KDevelop::ProjectBaseItem* item) const
0259 {
0260     KDevelop::ProjectFolderItem* folder = item->folder();
0261     if(folder && folder->hasFileOrFolder(QStringLiteral("metadata.desktop"))) {
0262         return canLaunchMetadataFile(KDevelop::Path(folder->path(), QStringLiteral("metadata.desktop")));
0263     }
0264     return false;
0265 }
0266 
0267 void PlasmoidExecutionConfigType::configureLaunchFromItem(KConfigGroup config, KDevelop::ProjectBaseItem* item) const
0268 {
0269     config.writeEntry("PlasmoidIdentifier", item->path().toUrl().toLocalFile());
0270 }
0271 
0272 void PlasmoidExecutionConfigType::configureLaunchFromCmdLineArguments(KConfigGroup /*config*/, const QStringList &/*args*/) const
0273 {}
0274 
0275 QMenu* PlasmoidExecutionConfigType::launcherSuggestions()
0276 {
0277     QList<QAction*> found;
0278     const QList<KDevelop::IProject*> projects = KDevelop::ICore::self()->projectController()->projects();
0279     for (KDevelop::IProject* p : projects) {
0280         const QSet<KDevelop::IndexedString> files = p->fileSet();
0281         for (const KDevelop::IndexedString& file : files) {
0282             KDevelop::Path path(file.str());
0283             if (path.lastPathSegment() == QLatin1String("metadata.desktop") && canLaunchMetadataFile(path)) {
0284                 path = path.parent();
0285                 QString relUrl = p->path().relativePath(path);
0286                 auto* action = new QAction(relUrl, this);
0287                 action->setProperty("url", relUrl);
0288                 action->setProperty("project", QVariant::fromValue<KDevelop::IProject*>(p));
0289                 connect(action, &QAction::triggered, this, &PlasmoidExecutionConfigType::suggestionTriggered);
0290                 found.append(action);
0291             }
0292         }
0293     }
0294 
0295     QMenu *m = nullptr;
0296     if(!found.isEmpty()) {
0297         m = new QMenu(i18nc("@title:menu", "Plasmoids"));
0298         m->addActions(found);
0299     }
0300     return m;
0301 }
0302 
0303 void PlasmoidExecutionConfigType::suggestionTriggered()
0304 {
0305     auto* action = qobject_cast<QAction*>(sender());
0306     auto* p = action->property("project").value<KDevelop::IProject*>();
0307     QString relUrl = action->property("url").toString();
0308 
0309     KDevelop::ILauncher* launcherInstance = launchers().at( 0 );
0310     QPair<QString,QString> launcher = qMakePair( launcherInstance->supportedModes().at(0), launcherInstance->id() );
0311 
0312     QString name = relUrl.mid(relUrl.lastIndexOf(QLatin1Char('/'))+1);
0313     KDevelop::ILaunchConfiguration* config = KDevelop::ICore::self()->runController()->createLaunchConfiguration(this, launcher, p, name);
0314     KConfigGroup cfg = config->config();
0315     cfg.writeEntry("PlasmoidIdentifier", relUrl);
0316     emit signalAddLaunchConfiguration(config);
0317 }
0318 
0319 #include "moc_plasmoidexecutionconfig.cpp"