File indexing completed on 2024-04-28 04:38:39
0001 /* 0002 SPDX-FileCopyrightText: 2009 Andreas Pakulat <apaku@gmx.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "nativeappjob.h" 0008 0009 #include <QAbstractButton> 0010 #include <QFileInfo> 0011 #include <QMessageBox> 0012 #include <QPointer> 0013 #include <QCheckBox> 0014 0015 #include <KConfigGroup> 0016 #include <KLocalizedString> 0017 #include <KShell> 0018 #include <KSharedConfig> 0019 0020 #include <interfaces/ilaunchconfiguration.h> 0021 #include <interfaces/iruncontroller.h> 0022 #include <outputview/outputmodel.h> 0023 #include <util/environmentprofilelist.h> 0024 0025 #include <interfaces/icore.h> 0026 #include <interfaces/iplugincontroller.h> 0027 #include <project/projectmodel.h> 0028 0029 #include "executeplugin.h" 0030 #include "debug.h" 0031 0032 using namespace KDevelop; 0033 0034 NativeAppJob::NativeAppJob(QObject* parent, KDevelop::ILaunchConfiguration* cfg) 0035 : KDevelop::OutputExecuteJob( parent ) 0036 , m_name(cfg->name()) 0037 { 0038 { 0039 auto cfgGroup = cfg->config(); 0040 if (cfgGroup.readEntry(ExecutePlugin::isExecutableEntry, false)) { 0041 m_name = cfgGroup.readEntry(ExecutePlugin::executableEntry, cfg->name()).section(QLatin1Char('/'), -1); 0042 } 0043 if (!cfgGroup.readEntry<bool>(ExecutePlugin::configuredByCTest, false)) { 0044 m_killBeforeExecutingAgain = cfgGroup.readEntry<int>(ExecutePlugin::killBeforeExecutingAgain, askIfRunning); 0045 } 0046 } 0047 setCapabilities(Killable); 0048 0049 auto* iface = KDevelop::ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IExecutePlugin"), QStringLiteral("kdevexecute"))->extension<IExecutePlugin>(); 0050 Q_ASSERT(iface); 0051 0052 const KDevelop::EnvironmentProfileList environmentProfiles(KSharedConfig::openConfig()); 0053 QString envProfileName = iface->environmentProfileName(cfg); 0054 0055 QString err; 0056 QUrl executable = iface->executable( cfg, err ); 0057 0058 if( !err.isEmpty() ) 0059 { 0060 setError( -1 ); 0061 setErrorText( err ); 0062 return; 0063 } 0064 0065 if (envProfileName.isEmpty()) { 0066 qCWarning(PLUGIN_EXECUTE) << "Launch Configuration:" << cfg->name() << i18n("No environment profile specified, looks like a broken " 0067 "configuration, please check run configuration '%1'. " 0068 "Using default environment profile.", cfg->name() ); 0069 envProfileName = environmentProfiles.defaultProfileName(); 0070 } 0071 setEnvironmentProfile(envProfileName); 0072 0073 QStringList arguments = iface->arguments( cfg, err ); 0074 if( !err.isEmpty() ) 0075 { 0076 setError( -2 ); 0077 setErrorText( err ); 0078 } 0079 0080 if( error() != 0 ) 0081 { 0082 qCWarning(PLUGIN_EXECUTE) << "Launch Configuration:" << cfg->name() << "oops, problem" << errorText(); 0083 return; 0084 } 0085 0086 setStandardToolView(KDevelop::IOutputView::RunView); 0087 setBehaviours(KDevelop::IOutputView::AllowUserClose | KDevelop::IOutputView::AutoScroll); 0088 setFilteringStrategy(OutputModel::NativeAppErrorFilter); 0089 setProperties(DisplayStdout | DisplayStderr); 0090 0091 // Now setup the process parameters 0092 0093 QUrl wc = iface->workingDirectory( cfg ); 0094 if( !wc.isValid() || wc.isEmpty() ) { 0095 wc = QUrl::fromLocalFile( QFileInfo( executable.toLocalFile() ).absolutePath() ); 0096 } 0097 setWorkingDirectory( wc ); 0098 0099 qCDebug(PLUGIN_EXECUTE) << "setting app:" << executable << arguments; 0100 0101 if (iface->useTerminal(cfg)) { 0102 QString terminalCommand = iface->terminal(cfg); 0103 terminalCommand.replace(QLatin1String("%exe"), KShell::quoteArg( executable.toLocalFile()) ); 0104 terminalCommand.replace(QLatin1String("%workdir"), KShell::quoteArg( wc.toLocalFile()) ); 0105 QStringList args = KShell::splitArgs(terminalCommand); 0106 args.append( arguments ); 0107 *this << args; 0108 } else { 0109 *this << executable.toLocalFile(); 0110 *this << arguments; 0111 } 0112 0113 setJobName(m_name); 0114 } 0115 0116 NativeAppJob* findNativeJob(KJob* j) 0117 { 0118 auto* job = qobject_cast<NativeAppJob*>(j); 0119 if (!job) { 0120 const QList<NativeAppJob*> jobs = j->findChildren<NativeAppJob*>(); 0121 if (!jobs.isEmpty()) 0122 job = jobs.first(); 0123 } 0124 return job; 0125 } 0126 0127 void NativeAppJob::start() 0128 { 0129 QVector<QPointer<NativeAppJob> > currentJobs; 0130 // collect running instances of the same type 0131 const auto& allCurrentJobs = ICore::self()->runController()->currentJobs(); 0132 for (auto j : allCurrentJobs) { 0133 NativeAppJob* njob = findNativeJob(j); 0134 if (njob && njob != this && njob->m_name == m_name) 0135 currentJobs << njob; 0136 } 0137 0138 if (!currentJobs.isEmpty()) { 0139 int oldJobAction = m_killBeforeExecutingAgain; 0140 if (oldJobAction == askIfRunning) { 0141 QMessageBox msgBox(QMessageBox::Question, 0142 i18nc("@title:window", "Job Already Running"), 0143 i18n("'%1' is already being executed.", m_name), 0144 startAnother | killAllInstances | QMessageBox::Cancel /* aka askIfRunning */); 0145 msgBox.button(killAllInstances)->setText(i18nc("@action:button", "Kill All Instances")); 0146 msgBox.button(startAnother)->setText(i18nc("@action:button", "Start Another")); 0147 msgBox.setDefaultButton(QMessageBox::Cancel); 0148 0149 QCheckBox* remember = new QCheckBox(i18nc("@option:check", "Remember choice")); 0150 msgBox.setCheckBox(remember); 0151 0152 oldJobAction = msgBox.exec(); 0153 if (remember->isChecked() && oldJobAction != QMessageBox::Cancel) { 0154 Q_EMIT killBeforeExecutingAgainChanged(oldJobAction); 0155 } 0156 } 0157 0158 switch (oldJobAction) { 0159 case startAnother: 0160 break; 0161 case killAllInstances: 0162 for (auto & job : currentJobs) { 0163 if (job) 0164 job->kill(); 0165 } 0166 break; 0167 default: // cancel starting a new job 0168 kill(); 0169 return; 0170 } 0171 } 0172 0173 OutputExecuteJob::start(); 0174 } 0175 0176 #include "moc_nativeappjob.cpp"