blob: 44af49d36cddfe1454cf451fae4bcbf6e6a4cc12 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution;
import com.intellij.execution.actions.RunContextAction;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.*;
import com.intellij.openapi.util.Trinity;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class ExecutorRegistryImpl extends ExecutorRegistry {
private static final Logger LOG = Logger.getInstance(ExecutorRegistryImpl.class);
@NonNls public static final String RUNNERS_GROUP = "RunnerActions";
@NonNls public static final String RUN_CONTEXT_GROUP = "RunContextGroup";
private List<Executor> myExecutors = new ArrayList<Executor>();
private ActionManager myActionManager;
private final Map<String, Executor> myId2Executor = new HashMap<String, Executor>();
private final Set<String> myContextActionIdSet = new HashSet<String>();
private final Map<String, AnAction> myId2Action = new HashMap<String, AnAction>();
private final Map<String, AnAction> myContextActionId2Action = new HashMap<String, AnAction>();
// [Project, ExecutorId, RunnerId]
private final Set<Trinity<Project, String, String>> myInProgress = Collections.synchronizedSet(new java.util.HashSet<Trinity<Project, String, String>>());
public ExecutorRegistryImpl(ActionManager actionManager) {
myActionManager = actionManager;
}
synchronized void initExecutor(@NotNull final Executor executor) {
if (myId2Executor.get(executor.getId()) != null) {
LOG.error("Executor with id: \"" + executor.getId() + "\" was already registered!");
}
if (myContextActionIdSet.contains(executor.getContextActionId())) {
LOG.error("Executor with context action id: \"" + executor.getContextActionId() + "\" was already registered!");
}
myExecutors.add(executor);
myId2Executor.put(executor.getId(), executor);
myContextActionIdSet.add(executor.getContextActionId());
registerAction(executor.getId(), new ExecutorAction(executor), RUNNERS_GROUP, myId2Action);
registerAction(executor.getContextActionId(), new RunContextAction(executor), RUN_CONTEXT_GROUP, myContextActionId2Action);
}
private void registerAction(@NotNull final String actionId, @NotNull final AnAction anAction, @NotNull final String groupId, @NotNull final Map<String, AnAction> map) {
AnAction action = myActionManager.getAction(actionId);
if (action == null) {
myActionManager.registerAction(actionId, anAction);
map.put(actionId, anAction);
action = anAction;
}
((DefaultActionGroup)myActionManager.getAction(groupId)).add(action);
}
synchronized void deinitExecutor(@NotNull final Executor executor) {
myExecutors.remove(executor);
myId2Executor.remove(executor.getId());
myContextActionIdSet.remove(executor.getContextActionId());
unregisterAction(executor.getId(), RUNNERS_GROUP, myId2Action);
unregisterAction(executor.getContextActionId(), RUN_CONTEXT_GROUP, myContextActionId2Action);
}
private void unregisterAction(@NotNull final String actionId, @NotNull final String groupId, @NotNull final Map<String, AnAction> map) {
final DefaultActionGroup group = (DefaultActionGroup)myActionManager.getAction(groupId);
if (group != null) {
group.remove(myActionManager.getAction(actionId));
final AnAction action = map.get(actionId);
if (action != null) {
myActionManager.unregisterAction(actionId);
map.remove(actionId);
}
}
}
@Override
@NotNull
public synchronized Executor[] getRegisteredExecutors() {
return myExecutors.toArray(new Executor[myExecutors.size()]);
}
@Override
public Executor getExecutorById(final String executorId) {
return myId2Executor.get(executorId);
}
@Override
@NonNls
@NotNull
public String getComponentName() {
return "ExecutorRegistyImpl";
}
@Override
public void initComponent() {
ProjectManager.getInstance().addProjectManagerListener(new ProjectManagerAdapter() {
@Override
public void projectOpened(final Project project) {
final MessageBusConnection connect = project.getMessageBus().connect(project);
connect.subscribe(ExecutionManager.EXECUTION_TOPIC, new ExecutionAdapter(){
@Override
public void processStartScheduled(String executorId, ExecutionEnvironment environment) {
myInProgress.add(createExecutionId(executorId, environment));
}
@Override
public void processNotStarted(String executorId, @NotNull ExecutionEnvironment environment) {
myInProgress.remove(createExecutionId(executorId, environment));
}
@Override
public void processStarted(String executorId, @NotNull ExecutionEnvironment environment, @NotNull ProcessHandler handler) {
myInProgress.remove(createExecutionId(executorId, environment));
}
});
}
@Override
public void projectClosed(final Project project) {
// perform cleanup
synchronized (myInProgress) {
for (Iterator<Trinity<Project, String, String>> it = myInProgress.iterator(); it.hasNext(); ) {
final Trinity<Project, String, String> trinity = it.next();
if (project.equals(trinity.first)) {
it.remove();
}
}
}
}
});
final Executor[] executors = Extensions.getExtensions(Executor.EXECUTOR_EXTENSION_NAME);
for (Executor executor : executors) {
initExecutor(executor);
}
}
@NotNull
private static Trinity<Project, String, String> createExecutionId(String executorId, @NotNull ExecutionEnvironment environment) {
return Trinity.create(environment.getProject(), executorId, environment.getRunner().getRunnerId());
}
@Override
public boolean isStarting(Project project, final String executorId, final String runnerId) {
return myInProgress.contains(Trinity.create(project, executorId, runnerId));
}
@Override
public boolean isStarting(@NotNull ExecutionEnvironment environment) {
return isStarting(environment.getProject(), environment.getExecutor().getId(), environment.getRunner().getRunnerId());
}
@Override
public synchronized void disposeComponent() {
if (!myExecutors.isEmpty()) {
for (Executor executor : new ArrayList<Executor>(myExecutors)) {
deinitExecutor(executor);
}
}
myExecutors = null;
myActionManager = null;
}
private class ExecutorAction extends AnAction implements DumbAware {
private final Executor myExecutor;
private ExecutorAction(@NotNull final Executor executor) {
super(executor.getStartActionText(), executor.getDescription(), executor.getIcon());
myExecutor = executor;
}
@Override
public void update(final AnActionEvent e) {
final Presentation presentation = e.getPresentation();
final Project project = e.getProject();
if (project == null || !project.isInitialized() || project.isDisposed() || DumbService.getInstance(project).isDumb()) {
presentation.setEnabled(false);
return;
}
final RunnerAndConfigurationSettings selectedConfiguration = getConfiguration(project);
boolean enabled = false;
String text;
final String textWithMnemonic = getTemplatePresentation().getTextWithMnemonic();
if (selectedConfiguration != null) {
final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(myExecutor.getId(), selectedConfiguration.getConfiguration());
ExecutionTarget target = ExecutionTargetManager.getActiveTarget(project);
enabled = ExecutionTargetManager.canRun(selectedConfiguration, target)
&& runner != null && !isStarting(project, myExecutor.getId(), runner.getRunnerId());
if (enabled) {
presentation.setDescription(myExecutor.getDescription());
}
text = myExecutor.getStartActionText(selectedConfiguration.getName());
}
else {
text = textWithMnemonic;
}
presentation.setEnabled(enabled);
presentation.setText(text);
}
@Nullable
private RunnerAndConfigurationSettings getConfiguration(@NotNull final Project project) {
return RunManagerEx.getInstanceEx(project).getSelectedConfiguration();
}
@Override
public void actionPerformed(final AnActionEvent e) {
final Project project = e.getProject();
if (project == null || project.isDisposed()) {
return;
}
RunnerAndConfigurationSettings configuration = getConfiguration(project);
ExecutionEnvironmentBuilder builder = configuration == null ? null : ExecutionEnvironmentBuilder.createOrNull(myExecutor, configuration);
if (builder == null) {
return;
}
ExecutionManager.getInstance(project).restartRunProfile(builder.activeTarget().dataContext(e.getDataContext()).build());
}
}
}