| /* |
| * Copyright 2000-2009 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.actions; |
| |
| import com.intellij.execution.Location; |
| import com.intellij.execution.PsiLocation; |
| import com.intellij.execution.RunManager; |
| import com.intellij.execution.RunnerAndConfigurationSettings; |
| import com.intellij.execution.configurations.ConfigurationType; |
| import com.intellij.execution.configurations.ConfigurationTypeUtil; |
| import com.intellij.execution.configurations.RunConfiguration; |
| import com.intellij.execution.junit.RuntimeConfigurationProducer; |
| import com.intellij.ide.DataManager; |
| import com.intellij.openapi.actionSystem.CommonDataKeys; |
| import com.intellij.openapi.actionSystem.DataContext; |
| import com.intellij.openapi.actionSystem.LangDataKeys; |
| import com.intellij.openapi.actionSystem.PlatformDataKeys; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.editor.Editor; |
| import com.intellij.openapi.extensions.Extensions; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.Key; |
| import com.intellij.openapi.util.Ref; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.psi.PsiDocumentManager; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.psi.PsiManager; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.awt.*; |
| import java.util.List; |
| |
| /** |
| * Context for creating run configurations from a location in the source code. |
| * |
| * @see RunConfigurationProducer |
| */ |
| public class ConfigurationContext { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.execution.actions.ConfigurationContext"); |
| private final Location<PsiElement> myLocation; |
| private RunnerAndConfigurationSettings myConfiguration; |
| private Ref<RunnerAndConfigurationSettings> myExistingConfiguration; |
| private final Module myModule; |
| private final RunConfiguration myRuntimeConfiguration; |
| private final Component myContextComponent; |
| |
| public static Key<ConfigurationContext> SHARED_CONTEXT = Key.create("SHARED_CONTEXT"); |
| private List<RuntimeConfigurationProducer> myPreferredProducers; |
| private List<ConfigurationFromContext> myConfigurationsFromContext; |
| |
| public static ConfigurationContext getFromContext(DataContext dataContext) { |
| final ConfigurationContext context = new ConfigurationContext(dataContext); |
| final DataManager dataManager = DataManager.getInstance(); |
| ConfigurationContext sharedContext = dataManager.loadFromDataContext(dataContext, SHARED_CONTEXT); |
| if (sharedContext == null || |
| sharedContext.getLocation() == null || |
| context.getLocation() == null || |
| !Comparing.equal(sharedContext.getLocation().getPsiElement(), context.getLocation().getPsiElement())) { |
| sharedContext = context; |
| dataManager.saveInDataContext(dataContext, SHARED_CONTEXT, sharedContext); |
| } |
| return sharedContext; |
| } |
| |
| private ConfigurationContext(final DataContext dataContext) { |
| myRuntimeConfiguration = RunConfiguration.DATA_KEY.getData(dataContext); |
| myContextComponent = PlatformDataKeys.CONTEXT_COMPONENT.getData(dataContext); |
| myModule = LangDataKeys.MODULE.getData(dataContext); |
| @SuppressWarnings({"unchecked"}) |
| final Location<PsiElement> location = (Location<PsiElement>)Location.DATA_KEY.getData(dataContext); |
| if (location != null) { |
| myLocation = location; |
| return; |
| } |
| final Project project = CommonDataKeys.PROJECT.getData(dataContext); |
| if (project == null) { |
| myLocation = null; |
| return; |
| } |
| final PsiElement element = getSelectedPsiElement(dataContext, project); |
| if (element == null) { |
| myLocation = null; |
| return; |
| } |
| myLocation = new PsiLocation<PsiElement>(project, myModule, element); |
| } |
| |
| /** |
| * Returns the configuration created from this context. |
| * |
| * @return the configuration, or null if none of the producers were able to create a configuration from this context. |
| */ |
| @Nullable |
| public RunnerAndConfigurationSettings getConfiguration() { |
| if (myConfiguration == null) createConfiguration(); |
| return myConfiguration; |
| } |
| |
| private void createConfiguration() { |
| LOG.assertTrue(myConfiguration == null); |
| final Location location = getLocation(); |
| myConfiguration = location != null ? |
| PreferredProducerFind.createConfiguration(location, this) : |
| null; |
| } |
| |
| public void setConfiguration(RunnerAndConfigurationSettings configuration) { |
| myConfiguration = configuration; |
| } |
| |
| @Deprecated |
| @Nullable |
| public RunnerAndConfigurationSettings updateConfiguration(final RuntimeConfigurationProducer producer) { |
| myConfiguration = producer.getConfiguration(); |
| return myConfiguration; |
| } |
| |
| /** |
| * Returns the source code location for this context. |
| * |
| * @return the source code location, or null if no source code fragment is currently selected. |
| */ |
| @Nullable |
| public Location getLocation() { |
| return myLocation; |
| } |
| |
| /** |
| * Returns the PSI element at caret for this context. |
| * |
| * @return the PSI element, or null if no source code fragment is currently selected. |
| */ |
| @Nullable |
| public PsiElement getPsiLocation() { |
| return myLocation != null ? myLocation.getPsiElement() : null; |
| } |
| |
| /** |
| * Finds an existing run configuration matching the context. |
| * |
| * @return an existing configuration, or null if none was found. |
| */ |
| @Nullable |
| public RunnerAndConfigurationSettings findExisting() { |
| if (myExistingConfiguration != null) return myExistingConfiguration.get(); |
| myExistingConfiguration = new Ref<RunnerAndConfigurationSettings>(); |
| if (myLocation == null) { |
| return null; |
| } |
| |
| final PsiElement psiElement = myLocation.getPsiElement(); |
| if (!psiElement.isValid()) { |
| return null; |
| } |
| |
| final List<RuntimeConfigurationProducer> producers = findPreferredProducers(); |
| if (myRuntimeConfiguration != null) { |
| if (producers != null) { |
| for (RuntimeConfigurationProducer producer : producers) { |
| final RunnerAndConfigurationSettings configuration = producer.findExistingConfiguration(myLocation, this); |
| if (configuration != null && configuration.getConfiguration() == myRuntimeConfiguration) { |
| myExistingConfiguration.set(configuration); |
| } |
| } |
| } |
| for (RunConfigurationProducer producer : Extensions.getExtensions(RunConfigurationProducer.EP_NAME)) { |
| RunnerAndConfigurationSettings configuration = producer.findExistingConfiguration(this); |
| if (configuration != null && configuration.getConfiguration() == myRuntimeConfiguration) { |
| myExistingConfiguration.set(configuration); |
| } |
| } |
| } |
| if (producers != null) { |
| for (RuntimeConfigurationProducer producer : producers) { |
| final RunnerAndConfigurationSettings configuration = producer.findExistingConfiguration(myLocation, this); |
| if (configuration != null) { |
| myExistingConfiguration.set(configuration); |
| } |
| } |
| } |
| for (RunConfigurationProducer producer : Extensions.getExtensions(RunConfigurationProducer.EP_NAME)) { |
| RunnerAndConfigurationSettings configuration = producer.findExistingConfiguration(this); |
| if (configuration != null) { |
| myExistingConfiguration.set(configuration); |
| } |
| } |
| return myExistingConfiguration.get(); |
| } |
| |
| @Nullable |
| private static PsiElement getSelectedPsiElement(final DataContext dataContext, final Project project) { |
| PsiElement element = null; |
| final Editor editor = CommonDataKeys.EDITOR.getData(dataContext); |
| if (editor != null){ |
| final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); |
| if (psiFile != null) { |
| final int offset = editor.getCaretModel().getOffset(); |
| element = psiFile.findElementAt(offset); |
| if (element == null && offset > 0 && offset == psiFile.getTextLength()) { |
| element = psiFile.findElementAt(offset-1); |
| } |
| } |
| } |
| if (element == null) { |
| final PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext); |
| element = elements != null && elements.length > 0 ? elements[0] : null; |
| } |
| if (element == null) { |
| final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext); |
| if (files != null && files.length > 0) { |
| element = PsiManager.getInstance(project).findFile(files[0]); |
| } |
| } |
| return element; |
| } |
| |
| public RunManager getRunManager() { |
| return RunManager.getInstance(getProject()); |
| } |
| |
| public Project getProject() { |
| return myLocation.getProject(); |
| } |
| |
| public Module getModule() { |
| return myModule; |
| } |
| |
| public DataContext getDataContext() { |
| return DataManager.getInstance().getDataContext(myContextComponent); |
| } |
| |
| /** |
| * Returns original {@link RunConfiguration} from this context. |
| * For example, it could be some test framework runtime configuration that had been launched |
| * and that had brought a result test tree on which a right-click action was performed. |
| * |
| * @param type {@link ConfigurationType} instance to filter original runtime configuration by its type |
| * @return {@link RunConfiguration} instance, it could be null |
| */ |
| @Nullable |
| public RunConfiguration getOriginalConfiguration(@Nullable ConfigurationType type) { |
| if (type == null) { |
| return myRuntimeConfiguration; |
| } |
| if (myRuntimeConfiguration != null |
| && ConfigurationTypeUtil.equals(myRuntimeConfiguration.getType(), type)) { |
| return myRuntimeConfiguration; |
| } |
| return null; |
| } |
| |
| @Deprecated |
| @Nullable |
| public List<RuntimeConfigurationProducer> findPreferredProducers() { |
| if (myPreferredProducers == null) { |
| myPreferredProducers = PreferredProducerFind.findPreferredProducers(myLocation, this, true); |
| } |
| return myPreferredProducers; |
| } |
| |
| public List<ConfigurationFromContext> getConfigurationsFromContext() { |
| if (myConfigurationsFromContext == null) { |
| myConfigurationsFromContext = PreferredProducerFind.getConfigurationsFromContext(myLocation, this, true); |
| } |
| return myConfigurationsFromContext; |
| } |
| } |