diff --git a/shell/runcontroller.cpp b/shell/runcontroller.cpp index 5e67848f84..f6031828d6 100644 --- a/shell/runcontroller.cpp +++ b/shell/runcontroller.cpp @@ -1,985 +1,986 @@ /* This file is part of KDevelop Copyright 2007-2008 Hamish Rodda Copyright 2008 Aleix Pol This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "runcontroller.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "plugincontroller.h" #include "uicontroller.h" #include "projectcontroller.h" #include "mainwindow.h" #include "launchconfiguration.h" #include "launchconfigurationdialog.h" #include #include #include #include using namespace KDevelop; QString RunController::LaunchConfigurationsGroup = "Launch"; QString RunController::LaunchConfigurationsListEntry = "Launch Configurations"; static QString CurrentLaunchConfigProjectEntry = "Current Launch Config Project"; static QString CurrentLaunchConfigNameEntry = "Current Launch Config GroupName"; static QString ConfiguredFromProjectItemEntry = "Configured from ProjectItem"; typedef QPair Target; Q_DECLARE_METATYPE(Target) //TODO: Doesn't handle add/remove of launch configs in the dialog or renaming of configs //TODO: Doesn't auto-select launch configs opened from projects class DebugMode : public ILaunchMode { public: DebugMode() {} virtual KIcon icon() const { return KIcon("tools-report-bug"); } virtual QString id() const { return "debug"; } virtual QString name() const { return i18n("Debug"); } }; class ProfileMode : public ILaunchMode { public: ProfileMode() {} virtual KIcon icon() const { return KIcon("office-chart-area"); } virtual QString id() const { return "profile"; } virtual QString name() const { return i18n("Profile"); } }; class ExecuteMode : public ILaunchMode { public: ExecuteMode() {} virtual KIcon icon() const { return KIcon("system-run"); } virtual QString id() const { return "execute"; } virtual QString name() const { return i18n("Execute"); } }; class RunController::RunControllerPrivate { public: QItemDelegate* delegate; IRunController::State state; RunController* q; QHash jobs; KAction* stopAction; KActionMenu* stopJobsMenu; KAction* profileAction; KAction* runAction; KAction* dbgAction; KSelectAction* currentTargetAction; QMap launchConfigurationTypes; QList launchConfigurations; QMap launchModes; QSignalMapper* launchChangeMapper; QSignalMapper* launchAsMapper; QMap > launchAsInfo; KDevelop::ProjectBaseItem* contextItem; DebugMode* debugMode; ExecuteMode* executeMode; ProfileMode* profileMode; bool hasLaunchConfigType( const QString& typeId ) { return launchConfigurationTypes.contains( typeId ); } void saveCurrentLaunchAction() { if (!currentTargetAction) return; if( currentTargetAction->currentAction() ) { KConfigGroup grp = Core::self()->activeSession()->config()->group( RunController::LaunchConfigurationsGroup ); LaunchConfiguration* l = static_cast( qVariantValue( currentTargetAction->currentAction()->data() ) ); grp.writeEntry( CurrentLaunchConfigProjectEntry, l->project() ? l->project()->name() : "" ); grp.writeEntry( CurrentLaunchConfigNameEntry, l->configGroupName() ); grp.sync(); } } void configureLaunches() { LaunchConfigurationDialog dlg; dlg.exec(); } QString launchActionText( LaunchConfiguration* l ) { QString label; if( l->project() ) { label = QString("%1 : %2").arg( l->project()->name()).arg(l->name()); } else { label = QString("%1" ).arg(l->name()); } return label; } void launchAs( int id ) { //kDebug() << "Launching id:" << id; QPair info = launchAsInfo[id]; //kDebug() << "fetching type and mode:" << info.first << info.second; LaunchConfigurationType* type = launchConfigurationTypeForId( info.first ); ILaunchMode* mode = q->launchModeForId( info.second ); //kDebug() << "got mode and type:" << type << type->id() << mode << mode->id(); if( type && mode ) { ILauncher* launcher = 0; foreach (ILauncher *l, type->launchers()) { //kDebug() << "avaliable launcher" << l << l->id() << l->supportedModes(); if (l->supportedModes().contains(mode->id())) { launcher = l; break; } } if (launcher) { QStringList itemPath = Core::self()->projectController()->projectModel()->pathFromIndex(contextItem->index()); ILaunchConfiguration* ilaunch = 0; foreach (LaunchConfiguration *l, launchConfigurations) { QStringList path = l->config().readEntry(ConfiguredFromProjectItemEntry, QStringList()); if (l->type() == type && path == itemPath) { kDebug() << "allready generated ilaunch" << path; ilaunch = l; break; } } if (!ilaunch) { ilaunch = q->createLaunchConfiguration( type, qMakePair( mode->id(), launcher->id() ), contextItem->project(), contextItem->text() ); LaunchConfiguration* launch = dynamic_cast( ilaunch ); type->configureLaunchFromItem( launch->config(), contextItem ); launch->config().writeEntry(ConfiguredFromProjectItemEntry, itemPath); //kDebug() << "created config, launching"; } else { //kDebug() << "reusing generated config, launching"; } q->setDefaultLaunch(ilaunch); q->execute( mode->id(), ilaunch ); } } } void updateCurrentLaunchAction() { if (!currentTargetAction) return; KConfigGroup launchGrp = Core::self()->activeSession()->config()->group( RunController::LaunchConfigurationsGroup ); QString currentLaunchProject = launchGrp.readEntry( CurrentLaunchConfigProjectEntry, "" ); QString currentLaunchName = launchGrp.readEntry( CurrentLaunchConfigNameEntry, "" ); LaunchConfiguration* l = 0; if( currentTargetAction->currentAction() ) { l = static_cast( qVariantValue( currentTargetAction->currentAction()->data() ) ); } else if( !launchConfigurations.isEmpty() ) { l = launchConfigurations.at( 0 ); } if( l && ( ( !currentLaunchProject.isEmpty() && ( !l->project() || l->project()->name() != currentLaunchProject ) ) || l->configGroupName() != currentLaunchName ) ) { foreach( QAction* a, currentTargetAction->actions() ) { LaunchConfiguration* l = static_cast( qvariant_cast( a->data() ) ); if( currentLaunchName == l->configGroupName() && ( ( currentLaunchProject.isEmpty() && !l->project() ) || ( l->project() && l->project()->name() == currentLaunchProject ) ) ) { a->setChecked( true ); break; } } } if( !currentTargetAction->currentAction() ) { kDebug() << "oops no current action, using first if list is non-empty"; if( !currentTargetAction->actions().isEmpty() ) { currentTargetAction->actions().first()->setChecked( true ); } } } void addLaunchAction( LaunchConfiguration* l ) { if (!currentTargetAction) return; KAction* action = currentTargetAction->addAction(launchActionText( l )); action->setData(qVariantFromValue(l)); } void readLaunchConfigs( KSharedConfigPtr cfg, IProject* prj ) { KConfigGroup group(cfg, RunController::LaunchConfigurationsGroup); QStringList configs = group.readEntry( RunController::LaunchConfigurationsListEntry, QStringList() ); foreach( const QString& cfg, configs ) { KConfigGroup grp = group.group( cfg ); if( launchConfigurationTypeForId( grp.readEntry( LaunchConfiguration::LaunchConfigurationTypeEntry, "" ) ) ) { q->addLaunchConfiguration( new LaunchConfiguration( grp, prj ) ); } } } LaunchConfigurationType* launchConfigurationTypeForId( const QString& id ) { QMap::iterator it = launchConfigurationTypes.find( id ); if( it != launchConfigurationTypes.end() ) { return it.value(); } else { kWarning() << "couldn't find type for id:" << id << ". Known types:" << launchConfigurationTypes.keys(); } return 0; } }; RunController::RunController(QObject *parent) : IRunController(parent) , d(new RunControllerPrivate) { setObjectName("RunController"); // TODO: need to implement compile only if needed before execute // TODO: need to implement abort all running programs when project closed d->currentTargetAction = 0; d->state = Idle; d->q = this; d->delegate = new RunDelegate(this); d->launchChangeMapper = new QSignalMapper( this ); d->launchAsMapper = 0; d->contextItem = 0; d->executeMode = 0; d->debugMode = 0; d->profileMode = 0; if(!(Core::self()->setupFlags() & Core::NoUi)) { // Note that things like registerJob() do not work without the actions, it'll simply crash. setupActions(); } } RunController::~RunController() { delete d; } void KDevelop::RunController::launchChanged( LaunchConfiguration* l ) { foreach( QAction* a, d->currentTargetAction->actions() ) { if( static_cast( qVariantValue( a->data() ) ) == l ) { a->setText( d->launchActionText( l ) ); break; } } } void RunController::cleanup() { delete d->executeMode; d->executeMode = 0; delete d->profileMode; d->profileMode = 0; delete d->debugMode; d->debugMode = 0; stopAllProcesses(); d->saveCurrentLaunchAction(); } void RunController::initialize() { d->executeMode = new ExecuteMode(); addLaunchMode( d->executeMode ); d->profileMode = new ProfileMode(); addLaunchMode( d->profileMode ); d->debugMode = new DebugMode; addLaunchMode( d->debugMode ); d->readLaunchConfigs( Core::self()->activeSession()->config(), 0 ); foreach (IProject* project, Core::self()->projectController()->projects()) { slotProjectOpened(project); } connect(Core::self()->projectController(), SIGNAL(projectOpened(KDevelop::IProject*)), this, SLOT(slotProjectOpened(KDevelop::IProject*))); connect(Core::self()->projectController(), SIGNAL(projectClosing(KDevelop::IProject*)), this, SLOT(slotProjectClosing(KDevelop::IProject*))); connect(Core::self()->projectController(), SIGNAL(projectConfigurationChanged(KDevelop::IProject*)), this, SLOT(slotRefreshProject(KDevelop::IProject*))); if( (Core::self()->setupFlags() & Core::NoUi) == 0 ) { // Only do this in GUI mode d->updateCurrentLaunchAction(); } } KJob* RunController::execute(const QString& runMode, ILaunchConfiguration* launch) { if( !launch ) { kDebug() << "execute called without launch config!"; return 0; } LaunchConfiguration *run = dynamic_cast(launch); //TODO: Port to launch framework, probably needs to be part of the launcher //if(!run.dependencies().isEmpty()) // ICore::self()->documentController()->saveAllDocuments(IDocument::Silent); //foreach(KJob* job, run.dependencies()) //{ // jobs.append(job); //} kDebug() << "mode:" << runMode; QString launcherId = run->launcherForMode( runMode ); kDebug() << "launcher id:" << launcherId; ILauncher* launcher = run->type()->launcherForId( launcherId ); if( !launcher ) { KMessageBox::error( qApp->activeWindow(), i18n("The current launch configuration does not support the '%1' mode.", runMode), ""); return 0; } KJob* launchJob = launcher->start(runMode, run); registerJob(launchJob); return launchJob; } void RunController::setupActions() { KAction *action; // TODO not multi-window friendly, FIXME KActionCollection* ac = Core::self()->uiControllerInternal()->defaultMainWindow()->actionCollection(); action = new KAction (i18n("Configure Launches..."), this); ac->addAction("configure_launches", action); action->setStatusTip(i18n("Open Launch Configuration Dialog")); action->setToolTip(i18nc("@info:tooltip", "Open Launch Configuration Dialog")); action->setWhatsThis(i18nc("@info:whatsthis", "

Opens a dialog to setup new launch configurations, or to change the existing ones.

")); connect(action, SIGNAL(triggered(bool)), SLOT(configureLaunches())); d->runAction = new KAction( KIcon("system-run"), i18n("Execute Launch"), this); d->runAction->setIconText( i18nc("Short text for 'Execute Launch' used in the toolbar", "Execute") ); d->runAction->setShortcut(Qt::SHIFT + Qt::Key_F9); d->runAction->setToolTip(i18nc("@info:tooltip", "Execute current Launch")); d->runAction->setStatusTip(i18n("Execute current Launch")); d->runAction->setWhatsThis(i18nc("@info:whatsthis", "Execute Launch

Executes the target or the program specified in currently active launch configuration.

")); ac->addAction("run_execute", d->runAction); connect(d->runAction, SIGNAL(triggered(bool)), this, SLOT(slotExecute())); d->dbgAction = new KAction( KIcon("debug-run"), i18n("Debug Launch"), this); d->dbgAction->setShortcut(Qt::Key_F9); d->dbgAction->setIconText( i18nc("Short text for 'Debug Launch' used in the toolbar", "Debug") ); d->dbgAction->setToolTip(i18nc("@info:tooltip", "Debug current Launch")); d->dbgAction->setStatusTip(i18n("Debug current Launch")); d->dbgAction->setWhatsThis(i18nc("@info:whatsthis", "Debug Launch

Executes the target or the program specified in currently active launch configuration inside a Debugger.

")); ac->addAction("run_debug", d->dbgAction); connect(d->dbgAction, SIGNAL(triggered(bool)), this, SLOT(slotDebug())); d->profileAction = new KAction( KIcon(""), i18n("Profile Launch"), this); d->profileAction->setToolTip(i18nc("@info:tooltip", "Profile current Launch")); d->profileAction->setStatusTip(i18n("Profile current Launch")); d->profileAction->setWhatsThis(i18nc("@info:whatsthis", "Profile Launch

Executes the target or the program specified in currently active launch configuration inside a Profiler.

")); ac->addAction("run_profile", d->profileAction); connect(d->profileAction, SIGNAL(triggered(bool)), this, SLOT(slotProfile())); action = d->stopAction = new KAction( KIcon("process-stop"), i18n("Stop All Jobs"), this); action->setIconText(i18nc("Short text for 'Stop All Jobs' used in the toolbar", "Stop All")); - action->setShortcut(Qt::Key_Escape); + // Ctrl+Escape would be nicer, but thats taken by the ksysguard desktop shortcut + action->setShortcut(QKeySequence("Ctrl+Shift+Escape")); action->setToolTip(i18nc("@info:tooltip", "Stop all currently running jobs")); action->setWhatsThis(i18nc("@info:whatsthis", "Stop All Jobs

Requests that all running jobs are stopped.

")); action->setEnabled(false); ac->addAction("run_stop_all", action); connect(action, SIGNAL(triggered(bool)), this, SLOT(stopAllProcesses())); action = d->stopJobsMenu = new KActionMenu( KIcon("process-stop"), i18n("Stop"), this); action->setIconText(i18nc("Short text for 'Stop' used in the toolbar", "Stop")); action->setToolTip(i18nc("@info:tooltip", "Menu allowing to stop individual jobs")); action->setWhatsThis(i18nc("@info:whatsthis", "Stop

List of Jobs that can be stopped individually.

")); action->setEnabled(false); ac->addAction("run_stop_menu", action); d->currentTargetAction = new KSelectAction( i18n("Current Launch Configuration"), this); d->currentTargetAction->setToolTip(i18nc("@info:tooltip", "Current Launch Configuration")); d->currentTargetAction->setStatusTip(i18n("Current Launch Configuration")); d->currentTargetAction->setWhatsThis(i18nc("@info:whatsthis", "

Select which launch configuration to run when run is invoked.

")); ac->addAction("run_default_target", d->currentTargetAction); } LaunchConfigurationType* RunController::launchConfigurationTypeForId( const QString& id ) { return d->launchConfigurationTypeForId( id ); } void KDevelop::RunController::slotProjectOpened(KDevelop::IProject * project) { d->readLaunchConfigs( project->projectConfiguration(), project ); d->updateCurrentLaunchAction(); } void KDevelop::RunController::slotProjectClosing(KDevelop::IProject * project) { if (!d->currentTargetAction) return; foreach (QAction* action, d->currentTargetAction->actions()) { LaunchConfiguration* l = static_cast(qvariant_cast(action->data())); if ( project == l->project() ) { l->save(); d->launchConfigurations.removeAll(l); delete l; bool wasSelected = action->isChecked(); delete action; if (wasSelected && !d->currentTargetAction->actions().isEmpty()) d->currentTargetAction->actions().first()->setChecked(true); } } } void KDevelop::RunController::slotRefreshProject(KDevelop::IProject* project) { slotProjectClosing(project); slotProjectOpened(project); } void RunController::slotDebug() { if(d->launchConfigurations.isEmpty()) { LaunchConfigurationDialog d; d.exec(); } if(!d->launchConfigurations.isEmpty()) executeDefaultLaunch( "debug" ); } void RunController::slotProfile() { if(d->launchConfigurations.isEmpty()) { LaunchConfigurationDialog d; d.exec(); } if(!d->launchConfigurations.isEmpty()) executeDefaultLaunch( "profile" ); } void RunController::slotExecute() { if(d->launchConfigurations.isEmpty()) { LaunchConfigurationDialog d; d.exec(); } if(!d->launchConfigurations.isEmpty()) executeDefaultLaunch( "execute" ); } LaunchConfiguration* KDevelop::RunController::defaultLaunch() const { QAction* projectAction = d->currentTargetAction->currentAction(); if( projectAction ) return static_cast(qvariant_cast(projectAction->data())); return 0; } void KDevelop::RunController::registerJob(KJob * job) { if (!job) return; if (!d->jobs.contains(job)) { KAction* stopJobAction = 0; if (Core::self()->setupFlags() != Core::NoUi) { stopJobAction = new KAction(job->objectName().isEmpty() ? i18n("<%1> Unnamed job", job->staticMetaObject.className()) : job->objectName(), this); stopJobAction->setData(QVariant::fromValue(static_cast(job))); d->stopJobsMenu->addAction(stopJobAction); connect (stopJobAction, SIGNAL(triggered(bool)), SLOT(slotKillJob())); job->setUiDelegate( new KDialogJobUiDelegate() ); } d->jobs.insert(job, stopJobAction); connect( job, SIGNAL(finished(KJob*)), SLOT(finished(KJob*)) ); connect( job, SIGNAL(destroyed(QObject*)), SLOT(jobDestroyed(QObject*)) ); IRunController::registerJob(job); emit jobRegistered(job); } job->start(); checkState(); } void KDevelop::RunController::unregisterJob(KJob * job) { IRunController::unregisterJob(job); Q_ASSERT(d->jobs.contains(job)); // Delete the stop job action QAction *action = d->jobs.take(job); if (action) action->deleteLater(); checkState(); emit jobUnregistered(job); } void KDevelop::RunController::checkState() { bool running = false; foreach (KJob* job, d->jobs.keys()) { if (!job->isSuspended()) { running = true; break; } } if ( ( d->state != Running ? false : true ) == running ) { d->state = running ? Running : Idle; emit runStateChanged(d->state); } if (Core::self()->setupFlags() != Core::NoUi) { d->stopAction->setEnabled(running); d->stopJobsMenu->setEnabled(running); } } void KDevelop::RunController::stopAllProcesses() { // composite jobs might remove child jobs, see also: // https://bugs.kde.org/show_bug.cgi?id=258904 // foreach already iterates over a copy foreach (KJob* job, d->jobs.keys()) { // now we check the real list whether it was deleted if (!d->jobs.contains(job)) continue; if (job->capabilities() & KJob::Killable) job->kill(KJob::EmitResult); } } void KDevelop::RunController::slotKillJob() { KAction* action = dynamic_cast(sender()); Q_ASSERT(action); KJob* job = static_cast(qvariant_cast(action->data())); if (job->capabilities() & KJob::Killable) job->kill(); } void KDevelop::RunController::finished(KJob * job) { unregisterJob(job); switch (job->error()) { case KJob::NoError: case KJob::KilledJobError: case OutputJob::FailedShownError: break; default: { ///WARNING: do *not* use a nested event loop here, it might cause /// random crashes later on, see e.g.: /// https://bugs.kde.org/show_bug.cgi?id=309811 KDialog* dialog = new KDialog; dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setWindowTitle(i18n("Process Error")); dialog->setButtons(KDialog::Close); KMessageBox::createKMessageBox(dialog, QMessageBox::Warning, job->errorString(), QStringList(), QString(), 0, KMessageBox::NoExec ); dialog->show(); } } } void RunController::jobDestroyed(QObject* job) { KJob* kjob = static_cast(job); if (d->jobs.contains(kjob)) { kWarning() << "job destroyed without emitting finished signal!"; unregisterJob(kjob); } } void KDevelop::RunController::suspended(KJob * job) { Q_UNUSED(job); checkState(); } void KDevelop::RunController::resumed(KJob * job) { Q_UNUSED(job); checkState(); } QList< KJob * > KDevelop::RunController::currentJobs() const { return d->jobs.keys(); } QList RunController::launchConfigurations() const { QList configs; foreach (LaunchConfiguration *config, launchConfigurationsInternal()) configs << config; return configs; } QList RunController::launchConfigurationsInternal() const { return d->launchConfigurations; } QList RunController::launchConfigurationTypes() const { return d->launchConfigurationTypes.values(); } void RunController::addConfigurationType( LaunchConfigurationType* type ) { if( !d->launchConfigurationTypes.contains( type->id() ) ) { d->launchConfigurationTypes.insert( type->id(), type ); } } void RunController::removeConfigurationType( LaunchConfigurationType* type ) { foreach( LaunchConfiguration* l, d->launchConfigurations ) { if( l->type() == type ) { d->launchConfigurations.removeAll( l ); delete l; } } d->launchConfigurationTypes.remove( type->id() ); } void KDevelop::RunController::addLaunchMode(KDevelop::ILaunchMode* mode) { if( !d->launchModes.contains( mode->id() ) ) { d->launchModes.insert( mode->id(), mode ); } } QList< KDevelop::ILaunchMode* > KDevelop::RunController::launchModes() const { return d->launchModes.values(); } void KDevelop::RunController::removeLaunchMode(KDevelop::ILaunchMode* mode) { d->launchModes.remove( mode->id() ); } KDevelop::ILaunchMode* KDevelop::RunController::launchModeForId(const QString& id) const { QMap::iterator it = d->launchModes.find( id ); if( it != d->launchModes.end() ) { return it.value(); } return 0; } void KDevelop::RunController::addLaunchConfiguration(KDevelop::LaunchConfiguration* l) { if( !d->launchConfigurations.contains( l ) ) { d->addLaunchAction( l ); d->launchConfigurations << l; if( !d->currentTargetAction->currentAction() ) { if( !d->currentTargetAction->actions().isEmpty() ) { d->currentTargetAction->actions().first()->setChecked( true ); } } connect( l, SIGNAL(nameChanged(LaunchConfiguration*)), SLOT(launchChanged(LaunchConfiguration*)) ); } } void KDevelop::RunController::removeLaunchConfiguration(KDevelop::LaunchConfiguration* l) { KConfigGroup launcherGroup; if( l->project() ) { launcherGroup = l->project()->projectConfiguration()->group( LaunchConfigurationsGroup ); } else { launcherGroup = Core::self()->activeSession()->config()->group( LaunchConfigurationsGroup ); } QStringList configs = launcherGroup.readEntry( RunController::LaunchConfigurationsListEntry, QStringList() ); configs.removeAll( l->configGroupName() ); launcherGroup.deleteGroup( l->configGroupName() ); launcherGroup.writeEntry( RunController::LaunchConfigurationsListEntry, configs ); launcherGroup.sync(); foreach( QAction* a, d->currentTargetAction->actions() ) { if( static_cast( qVariantValue( a->data() ) ) == l ) { bool wasSelected = a->isChecked(); d->currentTargetAction->removeAction( a ); if( wasSelected && !d->currentTargetAction->actions().isEmpty() ) { d->currentTargetAction->actions().first()->setChecked( true ); } break; } } d->launchConfigurations.removeAll( l ); delete l; } void KDevelop::RunController::executeDefaultLaunch(const QString& runMode) { if( !defaultLaunch() ) { kWarning() << "no default launch!"; return; } execute( runMode, defaultLaunch() ); } void RunController::setDefaultLaunch(ILaunchConfiguration* l) { foreach( QAction* a, d->currentTargetAction->actions() ) { if( static_cast( qVariantValue( a->data() ) ) == l ) { a->setChecked(true); break; } } } bool launcherNameExists(const QString& name) { foreach(ILaunchConfiguration* config, Core::self()->runControllerInternal()->launchConfigurations()) { if(config->name()==name) return true; } return false; } QString makeUnique(const QString& name) { if(launcherNameExists(name)) { for(int i=2; ; i++) { QString proposed = QString("%1 (%2)").arg(name).arg(i); if(!launcherNameExists(proposed)) { return proposed; } } } return name; } ILaunchConfiguration* RunController::createLaunchConfiguration ( LaunchConfigurationType* type, const QPair& launcher, IProject* project, const QString& name ) { KConfigGroup launchGroup; if( project ) { launchGroup = project->projectConfiguration()->group( RunController::LaunchConfigurationsGroup ); } else { launchGroup = Core::self()->activeSession()->config()->group( RunController::LaunchConfigurationsGroup ); } QStringList configs = launchGroup.readEntry( RunController::LaunchConfigurationsListEntry, QStringList() ); uint num = 0; QString baseName = "Launch Configuration"; while( configs.contains( QString( "%1 %2" ).arg( baseName ).arg( num ) ) ) { num++; } QString groupName = QString( "%1 %2" ).arg( baseName ).arg( num ); KConfigGroup launchConfigGroup = launchGroup.group( groupName ); QString cfgName = name; if( name.isEmpty() ) { cfgName = i18n("New %1 Launcher", type->name() ); cfgName = makeUnique(cfgName); } launchConfigGroup.writeEntry(LaunchConfiguration::LaunchConfigurationNameEntry, cfgName ); launchConfigGroup.writeEntry(LaunchConfiguration::LaunchConfigurationTypeEntry, type->id() ); launchConfigGroup.sync(); configs << groupName; launchGroup.writeEntry( RunController::LaunchConfigurationsListEntry, configs ); launchGroup.sync(); LaunchConfiguration* l = new LaunchConfiguration( launchConfigGroup, project ); l->setLauncherForMode( launcher.first, launcher.second ); Core::self()->runControllerInternal()->addLaunchConfiguration( l ); return l; } QItemDelegate * KDevelop::RunController::delegate() const { return d->delegate; } ContextMenuExtension RunController::contextMenuExtension ( Context* ctx ) { delete d->launchAsMapper; d->launchAsMapper = new QSignalMapper( this ); connect( d->launchAsMapper, SIGNAL(mapped(int)), SLOT(launchAs(int)) ); d->launchAsInfo.clear(); d->contextItem = 0; ContextMenuExtension ext; if( ctx->type() == Context::ProjectItemContext ) { KDevelop::ProjectItemContext* prjctx = dynamic_cast( ctx ); if( prjctx->items().count() == 1 ) { ProjectBaseItem* itm = prjctx->items().at( 0 ); int i = 0; foreach( ILaunchMode* mode, d->launchModes.values() ) { KActionMenu* menu = new KActionMenu( i18n("%1 As...", mode->name() ), this ); foreach( LaunchConfigurationType* type, launchConfigurationTypes() ) { bool hasLauncher = false; foreach( ILauncher* launcher, type->launchers() ) { if( launcher->supportedModes().contains( mode->id() ) ) { hasLauncher = true; } } if( hasLauncher && type->canLaunch(itm) ) { d->launchAsInfo[i] = qMakePair( type->id(), mode->id() ); KAction* act = new KAction( d->launchAsMapper ); act->setText( type->name() ); kDebug() << "Setting up mapping for:" << i << "for action" << act->text() << "in mode" << mode->name(); d->launchAsMapper->setMapping( act, i ); connect( act, SIGNAL(triggered()), d->launchAsMapper, SLOT(map()) ); menu->addAction(act); i++; } } if( menu->menu()->actions().count() > 0 ) { ext.addAction( ContextMenuExtension::RunGroup, menu); } } if( ext.actions( ContextMenuExtension::RunGroup ).count() > 0 ) { d->contextItem = itm; } } } return ext; } RunDelegate::RunDelegate( QObject* parent ) : QItemDelegate(parent), runProviderBrush( KColorScheme::View, KColorScheme::PositiveText ), errorBrush( KColorScheme::View, KColorScheme::NegativeText ) { } void RunDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { QStyleOptionViewItem opt = option; QVariant status = index.data(Qt::UserRole+1); // if( status.isValid() && status.canConvert() ) // { // IRunProvider::OutputTypes type = status.value(); // if( type == IRunProvider::RunProvider ) // { // opt.palette.setBrush( QPalette::Text, runProviderBrush.brush( option.palette ) ); // } else if( type == IRunProvider::StandardError ) // { // opt.palette.setBrush( QPalette::Text, errorBrush.brush( option.palette ) ); // } // } QItemDelegate::paint(painter, opt, index); } #include "runcontroller.moc"