From 6d4fd2e1a2b37806e5007f7e2c901172d966643a Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Mon, 8 Dec 2014 11:52:08 +0300 Subject: [PATCH] gradle tool window rework initial commit --- .../i18n/ExternalSystemBundle.properties | 17 + .../externalSystem/model/DataNode.java | 39 +- .../externalSystem/model/task/TaskData.java | 12 + .../AbstractExternalSystemLocalSettings.java | 18 + .../util/ExternalSystemApiUtil.java | 100 ++- .../view/ExternalProjectsViewState.java | 33 + .../resources/icons/taskGroup.png | Bin 0 -> 386 bytes .../action/DetachExternalProjectAction.java | 93 +-- ...tExternalSystemRunConfigurationAction.java | 56 ++ .../action/ExternalActionUtil.java | 89 --- .../action/ExternalSystemAction.java | 62 ++ .../action/ExternalSystemActionUtil.java | 179 +++++ .../action/ExternalSystemNodeAction.java | 101 +++ .../ExternalSystemRunConfigurationMenu.java | 94 +++ .../action/ExternalSystemToggleAction.java | 68 ++ .../action/ExternalSystemTreeAction.java | 63 ++ .../action/ExternalSystemViewGearAction.java | 63 ++ .../action/OpenExternalConfigAction.java | 93 +-- .../action/RefreshExternalProjectAction.java | 54 +- ...eExternalSystemRunConfigurationAction.java | 59 ++ .../ShowExternalSystemSettingsAction.java | 59 ++ .../action/ToggleAutoImportAction.java | 80 +++ .../AssignRunConfigurationShortcutAction.java | 64 ++ .../action/task/AssignShortcutAction.java | 49 ++ .../action/task/GroupTasksAction.java | 36 ++ .../task/RunExternalSystemTaskAction.java | 63 ++ .../task/ToggleAfterCompileTasksAction.java | 28 + .../task/ToggleAfterRebuildTasksAction.java | 28 + .../task/ToggleAfterSyncTaskAction.java | 28 + .../task/ToggleBeforeCompileTasksAction.java | 28 + .../task/ToggleBeforeRebuildTasksAction.java | 28 + .../task/ToggleBeforeRunTaskAction.java | 28 + .../task/ToggleTaskActivationAction.java | 112 ++++ .../model/ExternalSystemDataKeys.java | 26 +- .../ExternalSystemStartupActivity.java | 6 +- ...ctExternalSystemTaskConfigurationType.java | 48 +- .../project/ProjectStructureHelper.java | 24 +- .../manage/ExternalProjectsDataStorage.java | 233 ++++++- .../manage/ExternalProjectsManager.java | 239 +++++++ .../project/manage/ExternalProjectsState.java | 100 +++ .../manage/ExternalSystemKeymapExtension.java | 276 ++++++++ .../ExternalSystemRunManagerListener.java | 143 ++++ .../ExternalSystemShortcutsManager.java | 149 +++++ .../manage/ExternalSystemTaskActivator.java | 259 ++++++++ .../project/manage/ProjectDataManager.java | 64 +- .../manage/ProjectDataServiceImpl.java | 2 +- .../project/manage/TaskActivationState.java | 68 ++ .../task/AbstractToolWindowService.java | 9 +- .../service/task/ToolWindowModuleService.java | 5 +- .../service/task/ToolWindowTaskService.java | 9 +- ...stractExternalSystemToolWindowFactory.java | 21 +- .../ui/ExternalSystemRecentTaskListModel.java | 113 ---- .../ui/ExternalSystemRecentTasksList.java | 195 ------ .../task/ui/ExternalSystemTasksPanel.java | 204 ------ .../util/ExternalSystemUiUtil.java | 22 - .../util/ExternalSystemUtil.java | 76 ++- .../view/ExternalProjectsStructure.java | 253 ++++++++ .../view/ExternalProjectsView.java | 611 ++++++++++++++++++ .../view/ExternalSystemNode.java | 379 +++++++++++ .../view/ExternalSystemViewContributor.java | 40 ++ .../ExternalSystemViewDefaultContributor.java | 243 +++++++ .../externalSystem/view/ModuleNode.java | 98 +++ .../externalSystem/view/ProjectNode.java | 145 +++++ .../view/RunConfigurationNode.java | 132 ++++ .../view/RunConfigurationsNode.java | 94 +++ .../openapi/externalSystem/view/TaskNode.java | 81 +++ .../externalSystem/view/TasksNode.java | 110 ++++ .../src/icons/ExternalSystemIcons.java | 1 + ...ExternalSystemRecentTaskListModelTest.java | 77 --- .../ExternalSystemExtensionPoints.xml | 1 + .../src/META-INF/ExternalSystemExtensions.xml | 4 + .../src/idea/ExternalSystemActions.xml | 133 +++- .../gradle/resources/icons/offlineMode.png | Bin 0 -> 403 bytes plugins/gradle/src/META-INF/plugin.xml | 19 + plugins/gradle/src/icons/GradleIcons.java | 1 + .../gradle/action/ToggleOfflineAction.java | 37 ++ .../BaseGradleProjectResolverExtension.java | 26 +- .../builder/ExternalProjectBuilderImpl.groovy | 2 +- 78 files changed, 5698 insertions(+), 1004 deletions(-) create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewState.java create mode 100644 platform/external-system-impl/resources/icons/taskGroup.png create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/EditExternalSystemRunConfigurationAction.java delete mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalActionUtil.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemActionUtil.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemNodeAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemRunConfigurationMenu.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemToggleAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemTreeAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemViewGearAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/RemoveExternalSystemRunConfigurationAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ShowExternalSystemSettingsAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ToggleAutoImportAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignRunConfigurationShortcutAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignShortcutAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/GroupTasksAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/RunExternalSystemTaskAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterCompileTasksAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterRebuildTasksAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterSyncTaskAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeCompileTasksAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeRebuildTasksAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeRunTaskAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleTaskActivationAction.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManager.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsState.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemKeymapExtension.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemRunManagerListener.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemShortcutsManager.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/TaskActivationState.java delete mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTaskListModel.java delete mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTasksList.java delete mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemTasksPanel.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsStructure.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsView.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemNode.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemViewContributor.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemViewDefaultContributor.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ModuleNode.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ProjectNode.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/RunConfigurationNode.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/RunConfigurationsNode.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/TaskNode.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/TasksNode.java delete mode 100644 platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTaskListModelTest.java create mode 100644 plugins/gradle/resources/icons/offlineMode.png create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/action/ToggleOfflineAction.java diff --git a/platform/external-system-api/resources/i18n/ExternalSystemBundle.properties b/platform/external-system-api/resources/i18n/ExternalSystemBundle.properties index 42cdd96b2f7d..e89aa54a1238 100644 --- a/platform/external-system-api/resources/i18n/ExternalSystemBundle.properties +++ b/platform/external-system-api/resources/i18n/ExternalSystemBundle.properties @@ -32,7 +32,9 @@ error.resolve.generic=Resolve error error.resolve.already.running=Another 'refresh project' task is currently running for the project: {0} # Tool window +tool.window.title.projects=projects tool.window.title.tasks=tasks +external.system.view.nodes.run_configurations.name = Run Configurations # Action. action.refresh.all.projects.text=Refresh all {0} projects @@ -46,14 +48,29 @@ action.detach.external.project.description=Detach selected external project action.open.config.text=Open {0} config action.open.config.description=Allows to open project file of the linked {0} project at the editor +action.refresh.project.auto.text=Auto-import +action.refresh.project.auto.description=Enable/disable project auto-import + +action.open.settings.text={0} Settings +action.open.settings.description=Edit {0} settings for the current project + # Notification notification.project.refresh.fail.title={0} ''{1}'' project refresh failed notification.messages.project.sync.tab.name={0} Sync +notification.messages.task.execution.tab.name={0} Task # Tasks. tasks.recent.title=Recent tasks tasks.all.title=All tasks +external.system.keymap.group=External Build Systems +external.system.task.after.sync=After Import +external.system.task.before.compile=Before Make +external.system.task.after.compile=After Make +external.system.task.before.rebuild=Before Rebuild +external.system.task.after.rebuild=After Rebuild +external.system.task.before.run=Before Run + # Execution run.configuration.description={0} build run.configuration.tooltip.choose.registered.project=Choose one of registered {0} projects diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DataNode.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DataNode.java index 325c7cdd45b2..869731d2d90b 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DataNode.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DataNode.java @@ -53,7 +53,7 @@ public class DataNode implements Serializable { private transient T myData; private byte[] myRawData; - @Nullable private final DataNode myParent; + @Nullable private DataNode myParent; public DataNode(@NotNull Key key, @NotNull T data, @Nullable DataNode parent) { myKey = key; @@ -176,6 +176,8 @@ public class DataNode implements Serializable { }; myData = (T)oIn.readObject(); myRawData = null; + + assert myData != null; } catch (IOException e) { throw new IllegalStateException( @@ -239,18 +241,32 @@ public class DataNode implements Serializable { } private void writeObject(ObjectOutputStream out) throws IOException { + try { + myRawData = getDataBytes(); + } + catch (IOException e) { + LOG.warn("Unable to serialize the data node - " + toString()); + throw e; + } + out.defaultWriteObject(); + } + + public byte[] getDataBytes() throws IOException { + if (myRawData != null) return myRawData; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ObjectOutputStream oOut = new ObjectOutputStream(bOut); try { oOut.writeObject(myData); + final byte[] bytes = bOut.toByteArray(); + myRawData = bytes; + return bytes; } finally { oOut.close(); } - myRawData = bOut.toByteArray(); - out.defaultWriteObject(); } - + @Override public int hashCode() { int result = myChildren.hashCode(); @@ -285,4 +301,19 @@ public class DataNode implements Serializable { } return String.format("%s: %s", myKey, dataDescription); } + + public void clear(boolean removeFromGraph) { + if (removeFromGraph && myParent != null) { + for (Iterator> iterator = myParent.getChildren().iterator(); iterator.hasNext(); ) { + DataNode dataNode = iterator.next(); + if (System.identityHashCode(dataNode) == System.identityHashCode(this)) { + iterator.remove(); + break; + } + } + } + myParent = null; + myRawData = null; + myChildren.clear(); + } } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/TaskData.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/TaskData.java index d5279404c8e3..04296dc77306 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/TaskData.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/TaskData.java @@ -33,6 +33,7 @@ public class TaskData extends AbstractExternalEntityData implements ExternalConf @NotNull private final String myName; @NotNull private final String myLinkedExternalProjectPath; + @Nullable private String myGroup; @Nullable private final String myDescription; @@ -58,12 +59,22 @@ public class TaskData extends AbstractExternalEntityData implements ExternalConf return myDescription; } + @Nullable + public String getGroup() { + return myGroup; + } + + public void setGroup(@Nullable String group) { + myGroup = group; + } + @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + myName.hashCode(); result = 31 * result + myLinkedExternalProjectPath.hashCode(); result = 31 * result + (myDescription != null ? myDescription.hashCode() : 0); + result = 31 * result + (myGroup != null ? myGroup.hashCode() : 0); return result; } @@ -76,6 +87,7 @@ public class TaskData extends AbstractExternalEntityData implements ExternalConf TaskData data = (TaskData)o; if (myDescription != null ? !myDescription.equals(data.myDescription) : data.myDescription != null) return false; + if (myGroup != null ? !myGroup.equals(data.myGroup) : data.myGroup != null) return false; if (!myLinkedExternalProjectPath.equals(data.myLinkedExternalProjectPath)) return false; if (!myName.equals(data.myName)) return false; diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemLocalSettings.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemLocalSettings.java index aa6950933390..4d4245648c15 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemLocalSettings.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemLocalSettings.java @@ -24,6 +24,7 @@ import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; import com.intellij.openapi.externalSystem.service.project.PlatformFacade; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; +import com.intellij.openapi.externalSystem.view.ExternalProjectsViewState; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.util.SystemProperties; @@ -73,6 +74,10 @@ public abstract class AbstractExternalSystemLocalSettings { myExternalConfigModificationStamps = new AtomicReference>(ContainerUtilRt.newHashMap()); + private final AtomicReference myExternalProjectsViewState = new AtomicReference( + new ExternalProjectsViewState() + ); + @NotNull private final ProjectSystemId myExternalSystemId; @NotNull private final Project myProject; @NotNull private final PlatformFacade myPlatformFacade; @@ -189,6 +194,16 @@ public abstract class AbstractExternalSystemLocalSettings { myProjectBuildClasspath.set(projectsBuildClasspath); } + public ExternalProjectsViewState getExternalProjectsViewState() { + return myExternalProjectsViewState.get(); + } + + @SuppressWarnings("UnusedDeclaration") + public void setExternalProjectsViewState(ExternalProjectsViewState externalProjectsViewState) { + // Required for IJ serialization. + myExternalProjectsViewState.set(externalProjectsViewState); + } + public void fillState(@NotNull State state) { if (PRESERVE_EXPAND_STATE) { state.tasksExpandState = myExpandStates.get(); @@ -201,6 +216,7 @@ public abstract class AbstractExternalSystemLocalSettings { state.availableTasks = myAvailableTasks.get(); state.modificationStamps = myExternalConfigModificationStamps.get(); state.projectBuildClasspath = myProjectBuildClasspath.get(); + state.externalProjectsViewState = myExternalProjectsViewState.get(); } public void loadState(@NotNull State state) { @@ -209,6 +225,7 @@ public abstract class AbstractExternalSystemLocalSettings { setIfNotNull(myAvailableTasks, state.availableTasks); setIfNotNull(myExternalConfigModificationStamps, state.modificationStamps); setIfNotNull(myProjectBuildClasspath, state.projectBuildClasspath); + myExternalProjectsViewState.set(state.externalProjectsViewState); if (state.recentTasks != null) { List recentTasks = myRecentTasks.get(); if (recentTasks != state.recentTasks) { @@ -270,5 +287,6 @@ public abstract class AbstractExternalSystemLocalSettings { public Map modificationStamps = ContainerUtilRt.newHashMap(); public Map projectBuildClasspath = ContainerUtilRt.newHashMap(); + public ExternalProjectsViewState externalProjectsViewState; } } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java index 88da2ad4dee9..d14d908cf03b 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java @@ -23,15 +23,14 @@ import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.ExternalSystemAutoImportAware; import com.intellij.openapi.externalSystem.ExternalSystemManager; -import com.intellij.openapi.externalSystem.model.DataNode; -import com.intellij.openapi.externalSystem.model.ExternalSystemException; -import com.intellij.openapi.externalSystem.model.Key; -import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.*; import com.intellij.openapi.externalSystem.model.project.LibraryData; import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings; import com.intellij.openapi.externalSystem.service.ParametersEnhancer; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; +import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; +import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListener; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; @@ -46,9 +45,12 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.*; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; +import com.intellij.util.containers.Stack; import com.intellij.util.containers.TransferToEDTQueue; import com.intellij.util.lang.UrlClassLoader; +import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -361,6 +363,84 @@ public class ExternalSystemApiUtil { return result == null ? Collections.>emptyList() : result; } + public static void visit(@Nullable DataNode node, @NotNull Consumer consumer) { + if(node == null) return; + + Stack toProcess = ContainerUtil.newStack(node); + while (!toProcess.isEmpty()) { + DataNode node0 = toProcess.pop(); + consumer.consume(node0); + for (DataNode child : node0.getChildren()) { + toProcess.push(child); + } + } + } + + @NotNull + public static Collection> findAllRecursively(@Nullable final DataNode node, + @NotNull final Key key) { + if (node == null) return Collections.emptyList(); + + final Collection> nodes = findAllRecursively(node.getChildren(), new BooleanFunction>() { + @Override + public boolean fun(DataNode node) { + return node.getKey().equals(key); + } + }); + //noinspection unchecked + return new SmartList(nodes); + } + + public static Collection> findAllRecursively(@NotNull Collection> nodes) { + return findAllRecursively(nodes, null); + } + + @NotNull + public static Collection> findAllRecursively(@Nullable DataNode node, + @Nullable BooleanFunction> predicate) { + if (node == null) return Collections.emptyList(); + return findAllRecursively(node.getChildren(), predicate); + } + + public static Collection> findAllRecursively(@NotNull Collection> nodes, + @Nullable BooleanFunction> predicate) { + SmartList> result = new SmartList>(); + for (DataNode node : nodes) { + if (predicate == null || predicate.fun(node)) { + result.add(node); + } + } + for (DataNode node : nodes) { + result.addAll(findAllRecursively(node.getChildren(), predicate)); + } + return result; + } + + public static DataNode findFirstRecursively(@NotNull DataNode parentNode, + @NotNull BooleanFunction> predicate) { + Queue> queue = new LinkedList>(); + queue.add(parentNode); + return findInQueue(queue, predicate); + } + + public static DataNode findFirstRecursively(@NotNull Collection> nodes, + @NotNull BooleanFunction> predicate) { + return findInQueue(new LinkedList>(nodes), predicate); + } + + private static DataNode findInQueue(@NotNull Queue> queue, + @NotNull BooleanFunction> predicate) { + while (!queue.isEmpty()) { + DataNode node = (DataNode)queue.remove(); + if (predicate.fun(node)) { + return node; + } + //noinspection unchecked + queue.addAll(node.getChildren()); + } + return null; + } + public static void executeProjectChangeAction(@NotNull final DisposeAwareProjectChange task) { executeProjectChangeAction(false, task); } @@ -682,8 +762,20 @@ public class ExternalSystemApiUtil { return module != null && !module.isDisposed() ? module.getOptionValue(ExternalSystemConstants.LINKED_PROJECT_PATH_KEY) : null; } + @Nullable + public static String getExternalRootProjectPath(@Nullable Module module) { + return module != null && !module.isDisposed() ? module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY) : null; + } + @Nullable public static String getExternalProjectId(@Nullable Module module) { return module != null && !module.isDisposed() ? module.getOptionValue(ExternalSystemConstants.LINKED_PROJECT_ID_KEY) : null; } + + public static void subscribe(@NotNull Project project, + @NotNull ProjectSystemId systemId, + @NotNull ExternalSystemSettingsListener listener) { + MessageBusConnection connection = project.getMessageBus().connect(project); + connection.subscribe(getSettings(project, systemId).getChangesTopic(), listener); + } } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewState.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewState.java new file mode 100644 index 000000000000..6bf6d86e7e64 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewState.java @@ -0,0 +1,33 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.util.xmlb.annotations.Property; +import com.intellij.util.xmlb.annotations.Tag; +import org.jdom.Element; + +import java.io.Serializable; + +/** + * @author Vladislav.Soroka + * @since 9/26/2014 + */ +@Tag("projects_view") +public class ExternalProjectsViewState { + public boolean groupTasks = true; + @Tag("tree_state") + public Element treeState; +} diff --git a/platform/external-system-impl/resources/icons/taskGroup.png b/platform/external-system-impl/resources/icons/taskGroup.png new file mode 100644 index 0000000000000000000000000000000000000000..7604d83886e9b69e9da72a92d77daa337154ee33 GIT binary patch literal 386 zcmV-|0e$|7P)YU7{&7l$y}eHPv9Vkrl#5!tcA9SPVR2HDu~h!#hQOMD2Wtfaf?H&h)q+|CZy8E zx!Py&4Lz1d=#0398GAu?>oh>uR1TUOsyoZI z2EdDbSZ?$p$BaG6KmXuYEuKEHe6u%MSNb1W*?ANs2hcHNPj)W$wJp`2xs}FCiX5n| gT{wV_8GGEn0oZ_P^*{`mlK=n!07*qoM6N<$f({(96#xJL literal 0 HcmV?d00001 diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/DetachExternalProjectAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/DetachExternalProjectAction.java index 88f2c26a68a1..80e1e0f3a9da 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/DetachExternalProjectAction.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/DetachExternalProjectAction.java @@ -16,31 +16,28 @@ package com.intellij.openapi.externalSystem.action; import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; +import com.intellij.openapi.externalSystem.model.project.AbstractExternalEntityData; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.service.project.PlatformFacade; -import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemRecentTasksList; -import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemTasksTreeModel; -import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; -import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; -import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; -import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.externalSystem.view.ExternalSystemNode; +import com.intellij.openapi.externalSystem.view.ProjectNode; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfoRt; +import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.List; @@ -49,63 +46,71 @@ import java.util.List; * @author Denis Zhdanov * @since 6/13/13 5:42 PM */ -public class DetachExternalProjectAction extends AnAction implements DumbAware { +public class DetachExternalProjectAction extends ExternalSystemNodeAction implements DumbAware { public DetachExternalProjectAction() { + super(AbstractExternalEntityData.class); getTemplatePresentation().setText(ExternalSystemBundle.message("action.detach.external.project.text", "external")); getTemplatePresentation().setDescription(ExternalSystemBundle.message("action.detach.external.project.description")); getTemplatePresentation().setIcon(SystemInfoRt.isMac ? AllIcons.ToolbarDecorator.Mac.Remove : AllIcons.ToolbarDecorator.Remove); } @Override - public void update(AnActionEvent e) { - ExternalActionUtil.MyInfo info = ExternalActionUtil.getProcessingInfo(e.getDataContext()); - e.getPresentation().setEnabled(info.externalProject != null); + protected boolean isEnabled(AnActionEvent e) { + if (!super.isEnabled(e)) return false; + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + if (selectedNodes == null || selectedNodes.size() != 1) return false; + final Object externalData = selectedNodes.get(0).getData(); + return (externalData instanceof ProjectData || externalData instanceof ModuleData); } @Override - public void actionPerformed(AnActionEvent e) { - ExternalActionUtil.MyInfo info = ExternalActionUtil.getProcessingInfo(e.getDataContext()); - if (info.settings == null || info.localSettings == null || info.externalProject == null || info.ideProject == null - || info.externalSystemId == null) - { - return; - } - + public void perform(@NotNull final Project project, + @NotNull ProjectSystemId projectSystemId, + @NotNull AbstractExternalEntityData entityData, + @NotNull AnActionEvent e) { + e.getPresentation().setText( - ExternalSystemBundle.message("action.detach.external.project.text",info.externalSystemId.getReadableName()) + ExternalSystemBundle.message("action.detach.external.project.text", projectSystemId.getReadableName()) ); - ExternalSystemTasksTreeModel allTasksModel = ExternalSystemDataKeys.ALL_TASKS_MODEL.getData(e.getDataContext()); - if (allTasksModel != null) { - allTasksModel.pruneNodes(info.externalProject); - } - ExternalSystemRecentTasksList recentTasksList = ExternalSystemDataKeys.RECENT_TASKS_LIST.getData(e.getDataContext()); - if (recentTasksList != null) { - recentTasksList.getModel().forgetTasksFrom(info.externalProject.getPath()); - } - - info.localSettings.forgetExternalProjects(Collections.singleton(info.externalProject.getPath())); - info.settings.unlinkExternalProject(info.externalProject.getPath()); + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + final ExternalSystemNode externalSystemNode = ContainerUtil.getFirstItem(selectedNodes); + assert externalSystemNode != null; + final ProjectNode projectNode = + externalSystemNode instanceof ProjectNode ? (ProjectNode)externalSystemNode : externalSystemNode.findParent(ProjectNode.class); + assert projectNode != null; + + final ProjectData projectData = projectNode.getData(); + assert projectData != null; + ExternalSystemApiUtil.getLocalSettings(project, projectSystemId). + forgetExternalProjects(Collections.singleton(projectData.getLinkedExternalProjectPath())); + ExternalSystemApiUtil.getSettings(project, projectSystemId).unlinkExternalProject(projectData.getLinkedExternalProjectPath()); + + ExternalProjectsManager.getInstance(project).forgetExternalProjectData(projectSystemId, projectData.getLinkedExternalProjectPath()); // Process orphan modules. PlatformFacade platformFacade = ServiceManager.getService(PlatformFacade.class); - String externalSystemIdAsString = info.externalSystemId.toString(); List orphanModules = ContainerUtilRt.newArrayList(); - for (Module module : platformFacade.getModules(info.ideProject)) { - String systemId = module.getOptionValue(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY); - if (!externalSystemIdAsString.equals(systemId)) { - continue; - } - String path = module.getOptionValue(ExternalSystemConstants.LINKED_PROJECT_PATH_KEY); - if (info.externalProject.getPath().equals(path)) { + for (Module module : platformFacade.getModules(project)) { + if (!ExternalSystemApiUtil.isExternalSystemAwareModule(projectSystemId, module)) continue; + + String path = ExternalSystemApiUtil.getExternalRootProjectPath(module); + if (projectData.getLinkedExternalProjectPath().equals(path)) { orphanModules.add(module); } } if (!orphanModules.isEmpty()) { - ExternalSystemUtil.ruleOrphanModules(orphanModules, info.ideProject, info.externalSystemId); + ExternalSystemUtil.ruleOrphanModules(orphanModules, project, projectSystemId, new Consumer() { + @Override + public void consume(Boolean result) { + if (result != null && result) { + projectNode.getGroup().remove(projectNode); + } + } + }); } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/EditExternalSystemRunConfigurationAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/EditExternalSystemRunConfigurationAction.java new file mode 100644 index 000000000000..a368a1e167b3 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/EditExternalSystemRunConfigurationAction.java @@ -0,0 +1,56 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.execution.RunManager; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.impl.EditConfigurationsDialog; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import com.intellij.openapi.externalSystem.view.ExternalSystemNode; +import com.intellij.openapi.externalSystem.view.RunConfigurationNode; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 11/13/2014 + */ +public class EditExternalSystemRunConfigurationAction extends ExternalSystemAction { + + protected boolean isEnabled(AnActionEvent e) { + if (!super.isEnabled(e)) return false; + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + if (selectedNodes == null || selectedNodes.size() != 1) return false; + return selectedNodes.get(0) instanceof RunConfigurationNode; + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + Project project = getProject(e); + assert project != null; + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + if (selectedNodes == null || selectedNodes.size() != 1 || !(selectedNodes.get(0) instanceof RunConfigurationNode)) return; + + RunnerAndConfigurationSettings settings = ((RunConfigurationNode)selectedNodes.get(0)).getSettings(); + assert settings != null; + RunManager.getInstance(project).setSelectedConfiguration(settings); + EditConfigurationsDialog dialog = new EditConfigurationsDialog(project); + dialog.show(); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalActionUtil.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalActionUtil.java deleted file mode 100644 index 9543edf25943..000000000000 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalActionUtil.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2000-2013 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.openapi.externalSystem.action; - -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; -import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; -import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; -import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; -import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; -import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author Vladislav.Soroka - * @since 9/18/13 - */ -public class ExternalActionUtil { - @NotNull - public static MyInfo getProcessingInfo(@NotNull DataContext context) { - ExternalProjectPojo externalProject = ExternalSystemDataKeys.SELECTED_PROJECT.getData(context); - if (externalProject == null) { - return MyInfo.EMPTY; - } - - ProjectSystemId externalSystemId = ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.getData(context); - if (externalSystemId == null) { - return MyInfo.EMPTY; - } - - Project ideProject = CommonDataKeys.PROJECT.getData(context); - if (ideProject == null) { - return MyInfo.EMPTY; - } - - AbstractExternalSystemSettings settings = ExternalSystemApiUtil.getSettings(ideProject, externalSystemId); - ExternalProjectSettings externalProjectSettings = settings.getLinkedProjectSettings(externalProject.getPath()); - AbstractExternalSystemLocalSettings localSettings = ExternalSystemApiUtil.getLocalSettings(ideProject, externalSystemId); - - return new MyInfo(externalProjectSettings == null ? null : settings, - localSettings == null ? null : localSettings, - externalProjectSettings == null ? null : externalProject, - ideProject, - externalSystemId); - } - - public static class MyInfo { - - public static final MyInfo EMPTY = new MyInfo(null, null, null, null, null); - - @Nullable public final AbstractExternalSystemSettings settings; - @Nullable public final AbstractExternalSystemLocalSettings localSettings; - @Nullable public final ExternalProjectPojo externalProject; - @Nullable public final Project ideProject; - @Nullable public final ProjectSystemId externalSystemId; - - MyInfo(@Nullable AbstractExternalSystemSettings settings, - @Nullable AbstractExternalSystemLocalSettings localSettings, - @Nullable ExternalProjectPojo externalProject, - @Nullable Project ideProject, - @Nullable ProjectSystemId externalSystemId) - { - this.settings = settings; - this.localSettings = localSettings; - this.externalProject = externalProject; - this.ideProject = ideProject; - this.externalSystemId = externalSystemId; - } - } -} - diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemAction.java new file mode 100644 index 000000000000..2d13ff88fedc --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemAction.java @@ -0,0 +1,62 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + * @since 10/20/2014 + */ +public abstract class ExternalSystemAction extends AnAction implements DumbAware { + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + Presentation p = e.getPresentation(); + final boolean visible = isVisible(e); + p.setVisible(visible); + p.setEnabled(visible && isEnabled(e)); + } + + protected boolean isEnabled(AnActionEvent e) { + return hasProject(e) && getSystemId(e) != null; + } + + protected boolean isVisible(AnActionEvent e) { + return true; + } + + protected Project getProject(AnActionEvent e) { + return CommonDataKeys.PROJECT.getData(e.getDataContext()); + } + + protected ProjectSystemId getSystemId(AnActionEvent e) { + return ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.getData(e.getDataContext()); + } + + protected boolean hasProject(AnActionEvent e) { + return getProject(e) != null; + } +} \ No newline at end of file diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemActionUtil.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemActionUtil.java new file mode 100644 index 000000000000..268664d0994b --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemActionUtil.java @@ -0,0 +1,179 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.ide.DataManager; +import com.intellij.ide.util.ElementsChooser; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; +import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo; +import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.module.Module; +import com.intellij.ui.treeStructure.SimpleTree; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreePath; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 9/18/13 + */ +public class ExternalSystemActionUtil { + + public static void executeAction(final String actionId, final InputEvent e) { + final ActionManager actionManager = ActionManager.getInstance(); + final AnAction action = actionManager.getAction(actionId); + if (action != null) { + final Presentation presentation = new Presentation(); + final AnActionEvent event = + new AnActionEvent(e, DataManager.getInstance().getDataContext(e.getComponent()), "", presentation, actionManager, 0); + action.update(event); + if (presentation.isEnabled()) { + action.actionPerformed(event); + } + } + } + + @Nullable + public static Module getModule(DataContext context) { + final Module module = LangDataKeys.MODULE.getData(context); + return module != null ? module : LangDataKeys.MODULE_CONTEXT.getData(context); + } + + public static void setElements(ElementsChooser chooser, Collection all, Collection selected, Comparator comparator) { + List selection = chooser.getSelectedElements(); + chooser.clear(); + Collection sorted = new TreeSet(comparator); + sorted.addAll(all); + for (E element : sorted) { + chooser.addElement(element, selected.contains(element)); + } + chooser.selectElements(selection); + } + + public static void installCheckboxRenderer(final SimpleTree tree, final CheckboxHandler handler) { + final JCheckBox checkbox = new JCheckBox(); + + final JPanel panel = new JPanel(new BorderLayout()); + panel.add(checkbox, BorderLayout.WEST); + + final TreeCellRenderer baseRenderer = tree.getCellRenderer(); + tree.setCellRenderer(new TreeCellRenderer() { + public Component getTreeCellRendererComponent(final JTree tree, + final Object value, + final boolean selected, + final boolean expanded, + final boolean leaf, + final int row, + final boolean hasFocus) { + final Component baseComponent = baseRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + + final Object userObject = ((DefaultMutableTreeNode)value).getUserObject(); + if (!handler.isVisible(userObject)) { + return baseComponent; + } + + final Color foreground = selected ? UIUtil.getTreeSelectionForeground() : UIUtil.getTreeTextForeground(); + + Color background = selected ? UIUtil.getTreeSelectionBackground(hasFocus) : UIUtil.getTreeTextBackground(); + + panel.add(baseComponent, BorderLayout.CENTER); + panel.setBackground(background); + panel.setForeground(foreground); + + CheckBoxState state = handler.getState(userObject); + checkbox.setSelected(state != CheckBoxState.UNCHECKED); + checkbox.setEnabled(state != CheckBoxState.PARTIAL); + checkbox.setBackground(background); + checkbox.setForeground(foreground); + + return panel; + } + }); + + tree.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + int row = tree.getRowForLocation(e.getX(), e.getY()); + if (row >= 0) { + TreePath path = tree.getPathForRow(row); + if (!isCheckboxEnabledFor(path, handler)) return; + + Rectangle checkBounds = checkbox.getBounds(); + checkBounds.setLocation(tree.getRowBounds(row).getLocation()); + if (checkBounds.contains(e.getPoint())) { + handler.toggle(path, e); + e.consume(); + tree.setSelectionRow(row); + } + } + } + }); + + tree.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_SPACE) { + TreePath[] treePaths = tree.getSelectionPaths(); + if (treePaths != null) { + for (TreePath treePath : treePaths) { + if (!isCheckboxEnabledFor(treePath, handler)) continue; + handler.toggle(treePath, e); + } + e.consume(); + } + } + } + }); + } + + private static boolean isCheckboxEnabledFor(TreePath path, CheckboxHandler handler) { + Object userObject = ((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject(); + return handler.isVisible(userObject); + } + + public interface CheckboxHandler { + void toggle(TreePath treePath, final InputEvent e); + + boolean isVisible(Object userObject); + + CheckBoxState getState(Object userObject); + } + + public enum CheckBoxState { + CHECKED, UNCHECKED, PARTIAL + } + + @NotNull + public static ExternalTaskExecutionInfo buildTaskInfo(@NotNull TaskData task) { + ExternalSystemTaskExecutionSettings settings = new ExternalSystemTaskExecutionSettings(); + settings.setExternalProjectPath(task.getLinkedExternalProjectPath()); + settings.setTaskNames(Collections.singletonList(task.getName())); + settings.setTaskDescriptions(Collections.singletonList(task.getDescription())); + settings.setExternalSystemIdString(task.getOwner().toString()); + return new ExternalTaskExecutionInfo(settings, DefaultRunExecutor.EXECUTOR_ID); + } +} + diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemNodeAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemNodeAction.java new file mode 100644 index 000000000000..94fb31f34c10 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemNodeAction.java @@ -0,0 +1,101 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.ExternalSystemUiAware; +import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.project.ExternalConfigPathAware; +import com.intellij.openapi.externalSystem.service.settings.ExternalSystemConfigLocator; +import com.intellij.openapi.externalSystem.view.ExternalSystemNode; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 10/17/2014 + */ +public abstract class ExternalSystemNodeAction extends ExternalSystemAction { + + private final Class myExternalDataClazz; + + public ExternalSystemNodeAction(Class externalDataClazz) { + super(); + myExternalDataClazz = externalDataClazz; + } + + protected boolean isEnabled(AnActionEvent e) { + return super.isEnabled(e) && getSystemId(e) != null && getExternalData(e, myExternalDataClazz) != null; + } + + protected abstract void perform(@NotNull Project project, + @NotNull ProjectSystemId projectSystemId, + @NotNull T externalData, + @NotNull AnActionEvent e); + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + final Project project = getProject(e); + if (project == null) return; + + ProjectSystemId projectSystemId = getSystemId(e); + if (projectSystemId == null) return; + + final T data = getExternalData(e, myExternalDataClazz); + if (data == null) return; + + perform(project, projectSystemId, data, e); + } + + @Nullable + protected ExternalSystemUiAware getExternalSystemUiAware(AnActionEvent e) { + return ExternalSystemDataKeys.UI_AWARE.getData(e.getDataContext()); + } + + @SuppressWarnings("unchecked") + @Nullable + protected T getExternalData(AnActionEvent e, Class dataClass) { + ExternalSystemNode node = ContainerUtil.getFirstItem(ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext())); + return node != null && dataClass.isInstance(node.getData()) ? (T)node.getData() : null; + } + + @Nullable + protected VirtualFile getExternalConfig(@NotNull ExternalConfigPathAware data, ProjectSystemId externalSystemId) { + String path = data.getLinkedExternalProjectPath(); + LocalFileSystem fileSystem = LocalFileSystem.getInstance(); + VirtualFile externalSystemConfigPath = fileSystem.refreshAndFindFileByPath(path); + if (externalSystemConfigPath == null) { + return null; + } + + VirtualFile toOpen = externalSystemConfigPath; + for (ExternalSystemConfigLocator locator : ExternalSystemConfigLocator.EP_NAME.getExtensions()) { + if (externalSystemId.equals(locator.getTargetExternalSystemId())) { + toOpen = locator.adjust(toOpen); + if (toOpen == null) { + return null; + } + break; + } + } + return toOpen.isDirectory() ? null : toOpen; + } +} \ No newline at end of file diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemRunConfigurationMenu.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemRunConfigurationMenu.java new file mode 100644 index 000000000000..843eccece03f --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemRunConfigurationMenu.java @@ -0,0 +1,94 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.execution.*; +import com.intellij.execution.runners.ProgramRunner; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import com.intellij.openapi.externalSystem.view.ExternalSystemNode; +import com.intellij.openapi.externalSystem.view.RunConfigurationNode; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 11/20/2014 + */ +public class ExternalSystemRunConfigurationMenu extends DefaultActionGroup implements DumbAware { + @Override + public void update(AnActionEvent e) { + for (AnAction action : getChildActionsOrStubs()) { + if (action instanceof ExecuteExternalSystemRunConfigurationAction) { + remove(action); + } + } + + final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext()); + + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + if (selectedNodes == null || selectedNodes.size() != 1 || !(selectedNodes.get(0) instanceof RunConfigurationNode)) return; + + final RunnerAndConfigurationSettings settings = ((RunConfigurationNode)selectedNodes.get(0)).getSettings(); + + if (settings == null || project == null) return; + + Executor[] executors = ExecutorRegistry.getInstance().getRegisteredExecutors(); + for (int i = executors.length; --i >= 0; ) { + final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(executors[i].getId(), settings.getConfiguration()); + AnAction action = new ExecuteExternalSystemRunConfigurationAction(executors[i], runner != null, project, settings); + addAction(action, Constraints.FIRST); + } + + super.update(e); + } + + private static class ExecuteExternalSystemRunConfigurationAction extends AnAction { + private final Executor myExecutor; + private final boolean myEnabled; + private final Project myProject; + private final RunnerAndConfigurationSettings mySettings; + + public ExecuteExternalSystemRunConfigurationAction(Executor executor, + boolean enabled, + Project project, + RunnerAndConfigurationSettings settings) { + super(executor.getActionName(), null, executor.getIcon()); + myExecutor = executor; + myEnabled = enabled; + myProject = project; + mySettings = settings; + } + + @Override + public void actionPerformed(@NotNull AnActionEvent event) { + if (myEnabled) { + ProgramRunnerUtil.executeConfiguration(myProject, mySettings, myExecutor); + final RunManagerEx runManagerEx = RunManagerEx.getInstanceEx(myProject); + runManagerEx.setSelectedConfiguration(mySettings); + } + } + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + e.getPresentation().setEnabled(myEnabled); + } + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemToggleAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemToggleAction.java new file mode 100644 index 000000000000..c2ea887ecc0d --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemToggleAction.java @@ -0,0 +1,68 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; + +/** + * @author Vladislav.Soroka + * @since 10/20/2014 + */ +public abstract class ExternalSystemToggleAction extends ToggleAction implements DumbAware { + @Override + public void update(AnActionEvent e) { + super.update(e); + Presentation p = e.getPresentation(); + final boolean visible = isVisible(e); + p.setVisible(visible); + p.setEnabled(visible && isEnabled(e)); + } + + protected boolean isEnabled(AnActionEvent e) { + return hasProject(e); + } + + protected boolean isVisible(AnActionEvent e) { + return true; + } + + @Override + public final boolean isSelected(AnActionEvent e) { + if (!isEnabled(e)) return false; + return doIsSelected(e); + } + + protected abstract boolean doIsSelected(AnActionEvent e); + + protected Project getProject(AnActionEvent e) { + return CommonDataKeys.PROJECT.getData(e.getDataContext()); + } + + protected boolean hasProject(AnActionEvent e) { + return getProject(e) != null; + } + + protected ProjectSystemId getSystemId(AnActionEvent e) { + return ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.getData(e.getDataContext()); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemTreeAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemTreeAction.java new file mode 100644 index 000000000000..92bb414dbb60 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemTreeAction.java @@ -0,0 +1,63 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author Vladislav.Soroka + * @since 10/20/2014 + */ +public abstract class ExternalSystemTreeAction extends ExternalSystemAction { + @Override + protected boolean isEnabled(AnActionEvent e) { + return super.isEnabled(e) && getTree(e) != null; + } + + @Nullable + protected static JTree getTree(AnActionEvent e) { + return ExternalSystemDataKeys.PROJECTS_TREE.getData(e.getDataContext()); + } + + public static class CollapseAll extends ExternalSystemTreeAction { + public void actionPerformed(AnActionEvent e) { + JTree tree = getTree(e); + if (tree == null) return; + + int row = tree.getRowCount() - 1; + while (row >= 0) { + tree.collapseRow(row); + row--; + } + } + } + + public static class ExpandAll extends ExternalSystemTreeAction { + public void actionPerformed(AnActionEvent e) { + JTree tree = getTree(e); + if (tree == null) return; + + for (int i = 0; i < tree.getRowCount(); i++) { + tree.expandRow(i); + } + } + } +} + diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemViewGearAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemViewGearAction.java new file mode 100644 index 000000000000..a56c299f82d7 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemViewGearAction.java @@ -0,0 +1,63 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.view.ExternalProjectsView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 10/31/2014 + */ +public abstract class ExternalSystemViewGearAction extends ExternalSystemToggleAction { + + private ExternalProjectsView myView; + + @Override + protected boolean isEnabled(AnActionEvent e) { + if (!super.isEnabled(e)) return false; + return getView() != null; + } + + @Override + protected boolean doIsSelected(AnActionEvent e) { + final ExternalProjectsView view = getView(); + return view != null && isSelected(view); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + final ExternalProjectsView view = getView(); + if (view != null){ + setSelected(view, state); + } + } + + protected abstract boolean isSelected(@NotNull ExternalProjectsView view); + + protected abstract void setSelected(@NotNull ExternalProjectsView view, boolean value); + + @Nullable + protected ExternalProjectsView getView() { + return myView; + } + + public void setView(ExternalProjectsView view) { + myView = view; + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/OpenExternalConfigAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/OpenExternalConfigAction.java index acc5aa4f08b4..65b1a0d8d4f5 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/OpenExternalConfigAction.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/OpenExternalConfigAction.java @@ -1,92 +1,59 @@ package com.intellij.openapi.externalSystem.action; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.ExternalSystemUiAware; import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; -import com.intellij.openapi.externalSystem.service.settings.ExternalSystemConfigLocator; +import com.intellij.openapi.externalSystem.model.project.ExternalConfigPathAware; +import com.intellij.openapi.externalSystem.model.project.ExternalEntityData; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; -import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.OpenFileDescriptor; -import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** - * @author Denis Zhdanov - * @since 7/16/13 2:19 PM + * @author Vladislav.Soroka + * @since 10/17/2014 */ -public class OpenExternalConfigAction extends AnAction implements DumbAware { +public class OpenExternalConfigAction extends ExternalSystemNodeAction { public OpenExternalConfigAction() { + super(ExternalConfigPathAware.class); getTemplatePresentation().setText(ExternalSystemBundle.message("action.open.config.text", "external")); getTemplatePresentation().setDescription(ExternalSystemBundle.message("action.open.config.description", "external")); } @Override - public void update(AnActionEvent e) { - ProjectSystemId externalSystemId = ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.getData(e.getDataContext()); - if (externalSystemId == null) { - e.getPresentation().setEnabled(false); - return; - } + protected boolean isEnabled(AnActionEvent e) { + if (!super.isEnabled(e)) return false; + final ExternalEntityData externalData = getExternalData(e, ExternalEntityData.class); + if (!(externalData instanceof ExternalConfigPathAware)) return false; + + VirtualFile config = getExternalConfig((ExternalConfigPathAware)externalData, externalData.getOwner()); + if (config == null) return false; + + ProjectSystemId externalSystemId = getSystemId(e); e.getPresentation().setText(ExternalSystemBundle.message("action.open.config.text", externalSystemId.getReadableName())); e.getPresentation().setDescription(ExternalSystemBundle.message("action.open.config.description", externalSystemId.getReadableName())); - e.getPresentation().setIcon(ExternalSystemUiUtil.getUiAware(externalSystemId).getProjectIcon()); + final ExternalSystemUiAware uiAware = getExternalSystemUiAware(e); + if (uiAware != null) { + e.getPresentation().setIcon(uiAware.getProjectIcon()); + } - VirtualFile config = getExternalConfig(e.getDataContext()); - e.getPresentation().setEnabled(config != null); + return true; } @Override - public void actionPerformed(AnActionEvent e) { - Project project = CommonDataKeys.PROJECT.getData(e.getDataContext()); - if (project == null) { - return; + protected void perform(@NotNull Project project, + @NotNull ProjectSystemId systemId, + @NotNull ExternalConfigPathAware configPathAware, + @NotNull AnActionEvent e) { + VirtualFile configFile = getExternalConfig(configPathAware, systemId); + if (configFile != null) { + OpenFileDescriptor descriptor = new OpenFileDescriptor(project, configFile); + FileEditorManager.getInstance(project).openTextEditor(descriptor, true); } - - VirtualFile configFile = getExternalConfig(e.getDataContext()); - if (configFile == null) { - return; - } - - OpenFileDescriptor descriptor = new OpenFileDescriptor(project, configFile); - FileEditorManager.getInstance(project).openTextEditor(descriptor, true); - } - - @Nullable - private static VirtualFile getExternalConfig(@NotNull DataContext context) { - ProjectSystemId externalSystemId = ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.getData(context); - if (externalSystemId == null) { - return null; - } - - ExternalProjectPojo projectPojo = ExternalSystemDataKeys.SELECTED_PROJECT.getData(context); - if (projectPojo == null) { - return null; - } - - String path = projectPojo.getPath(); - LocalFileSystem fileSystem = LocalFileSystem.getInstance(); - VirtualFile externalSystemConfigPath = fileSystem.refreshAndFindFileByPath(path); - if (externalSystemConfigPath == null) { - return null; - } - - VirtualFile toOpen = externalSystemConfigPath; - for (ExternalSystemConfigLocator locator : ExternalSystemConfigLocator.EP_NAME.getExtensions()) { - if (externalSystemId.equals(locator.getTargetExternalSystemId())) { - toOpen = locator.adjust(toOpen); - if (toOpen == null) { - return null; - } - } - } - return toOpen.isDirectory() ? null : toOpen; } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/RefreshExternalProjectAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/RefreshExternalProjectAction.java index e0e424be8887..b95465377d5a 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/RefreshExternalProjectAction.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/RefreshExternalProjectAction.java @@ -1,28 +1,33 @@ package com.intellij.openapi.externalSystem.action; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.externalSystem.model.DataNode; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.project.AbstractExternalEntityData; +import com.intellij.openapi.externalSystem.model.project.ExternalConfigPathAware; +import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; -import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; +import com.intellij.openapi.externalSystem.view.ExternalSystemNode; +import com.intellij.openapi.externalSystem.view.ProjectNode; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ex.ProjectRootManagerEx; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collections; +import java.util.List; /** * * Forces the ide to retrieve the most up-to-date info about the linked external project and updates project state if necessary @@ -31,44 +36,43 @@ import java.util.Collections; * @author Vladislav.Soroka * @since 9/18/13 */ -public class RefreshExternalProjectAction extends AnAction implements DumbAware, AnAction.TransparentUpdate { +public class RefreshExternalProjectAction extends ExternalSystemNodeAction implements DumbAware { public RefreshExternalProjectAction() { + super(AbstractExternalEntityData.class); getTemplatePresentation().setText(ExternalSystemBundle.message("action.refresh.project.text", "external")); getTemplatePresentation().setDescription(ExternalSystemBundle.message("action.refresh.project.description", "external")); } @Override - public void update(AnActionEvent e) { - ExternalActionUtil.MyInfo info = ExternalActionUtil.getProcessingInfo(e.getDataContext()); - e.getPresentation().setEnabled(info.externalProject != null); + protected boolean isEnabled(AnActionEvent e) { + if (!super.isEnabled(e)) return false; + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + if (selectedNodes == null || selectedNodes.size() != 1) return false; + final Object externalData = selectedNodes.get(0).getData(); + return (externalData instanceof ProjectData || externalData instanceof ModuleData); } @Override - public void actionPerformed(AnActionEvent e) { - ExternalActionUtil.MyInfo info = ExternalActionUtil.getProcessingInfo(e.getDataContext()); - if (info.settings == null || info.localSettings == null || info.externalProject == null || info.ideProject == null - || info.externalSystemId == null) - { - return; - } - ProjectSystemId externalSystemId = ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.getData(e.getDataContext()); - if (externalSystemId == null) { - return; - } - - final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext()); - if (project == null) { - e.getPresentation().setEnabled(false); - return; - } + public void perform(@NotNull final Project project, + @NotNull ProjectSystemId projectSystemId, + @NotNull AbstractExternalEntityData externalEntityData, + @NotNull AnActionEvent e) { + + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + final ExternalSystemNode externalSystemNode = ContainerUtil.getFirstItem(selectedNodes); + assert externalSystemNode != null; + + final ExternalConfigPathAware externalConfigPathAware = + externalSystemNode.getData() instanceof ExternalConfigPathAware ? (ExternalConfigPathAware)externalSystemNode.getData() : null; + assert externalConfigPathAware != null; // We save all documents because there is a possible case that there is an external system config file changed inside the ide. FileDocumentManager.getInstance().saveAllDocuments(); final ProjectDataManager projectDataManager = ServiceManager.getService(ProjectDataManager.class); ExternalSystemUtil.refreshProject( - project, externalSystemId, info.externalProject.getPath(), + project, projectSystemId, externalConfigPathAware.getLinkedExternalProjectPath(), new ExternalProjectRefreshCallback() { @Override public void onSuccess(@Nullable final DataNode externalProject) { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/RemoveExternalSystemRunConfigurationAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/RemoveExternalSystemRunConfigurationAction.java new file mode 100644 index 000000000000..ea535f0d90b4 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/RemoveExternalSystemRunConfigurationAction.java @@ -0,0 +1,59 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.execution.RunManager; +import com.intellij.execution.RunManagerEx; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import com.intellij.openapi.externalSystem.view.ExternalSystemNode; +import com.intellij.openapi.externalSystem.view.RunConfigurationNode; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 11/13/2014 + */ +public class RemoveExternalSystemRunConfigurationAction extends ExternalSystemAction { + + protected boolean isEnabled(AnActionEvent e) { + if (!super.isEnabled(e)) return false; + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + if (selectedNodes == null || selectedNodes.size() != 1) return false; + return selectedNodes.get(0) instanceof RunConfigurationNode; + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + Project project = getProject(e); + assert project != null; + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + if (selectedNodes == null || selectedNodes.size() != 1 || !(selectedNodes.get(0) instanceof RunConfigurationNode)) return; + + RunnerAndConfigurationSettings settings = ((RunConfigurationNode)selectedNodes.get(0)).getSettings(); + assert settings != null; + + int res = Messages.showYesNoDialog(project, "Delete \"" + settings.getName() + "\"?", "Confirmation", Messages.getQuestionIcon()); + if (res == Messages.YES) { + ((RunManagerEx)RunManager.getInstance(project)).removeConfiguration(settings); + } + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ShowExternalSystemSettingsAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ShowExternalSystemSettingsAction.java new file mode 100644 index 000000000000..bb57cdeea9ac --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ShowExternalSystemSettingsAction.java @@ -0,0 +1,59 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; +import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + * @since 10/20/2014 + */ +public class ShowExternalSystemSettingsAction extends ExternalSystemAction { + + public ShowExternalSystemSettingsAction() { + getTemplatePresentation().setText(ExternalSystemBundle.message("action.open.settings.text", "external")); + getTemplatePresentation().setDescription(ExternalSystemBundle.message("action.open.settings.description", "external")); + } + + @Override + protected boolean isEnabled(AnActionEvent e) { + if (!super.isEnabled(e)) return false; + + ProjectSystemId systemId = getSystemId(e); + if (systemId == null) return false; + + e.getPresentation().setText(ExternalSystemBundle.message("action.open.settings.text", systemId.getReadableName())); + e.getPresentation().setDescription(ExternalSystemBundle.message("action.open.settings.description", systemId.getReadableName())); + return true; + } + + @Override + public void actionPerformed(AnActionEvent e) { + final ProjectSystemId systemId = getSystemId(e); + if (systemId != null) { + showSettingsFor(getProject(e), systemId); + } + } + + protected static void showSettingsFor(Project project, @NotNull ProjectSystemId systemId) { + ShowSettingsUtil.getInstance().showSettingsDialog(project, systemId.getReadableName()); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ToggleAutoImportAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ToggleAutoImportAction.java new file mode 100644 index 000000000000..fd2da816d988 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ToggleAutoImportAction.java @@ -0,0 +1,80 @@ +/* + * 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.openapi.externalSystem.action; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; +import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; +import com.intellij.openapi.externalSystem.view.ProjectNode; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 10/20/2014 + */ +public class ToggleAutoImportAction extends ExternalSystemToggleAction { + + public ToggleAutoImportAction() { + getTemplatePresentation().setText(ExternalSystemBundle.message("action.refresh.project.auto.text")); + getTemplatePresentation().setDescription(ExternalSystemBundle.message("action.refresh.project.auto.description")); + } + + @Override + protected boolean isEnabled(AnActionEvent e) { + if (!super.isEnabled(e)) return false; + if (getSystemId(e) == null) return false; + + return ExternalSystemDataKeys.SELECTED_PROJECT_NODE.getData(e.getDataContext()) != null; + } + + @Override + protected boolean isVisible(AnActionEvent e) { + if (!super.isVisible(e)) return false; + if (getSystemId(e) == null) return false; + + return ExternalSystemDataKeys.SELECTED_PROJECT_NODE.getData(e.getDataContext()) != null; + } + + @Override + protected boolean doIsSelected(AnActionEvent e) { + final ExternalProjectSettings projectSettings = getProjectSettings(e); + + return projectSettings != null && projectSettings.isUseAutoImport(); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + final ExternalProjectSettings projectSettings = getProjectSettings(e); + if (projectSettings != null) { + if (state != projectSettings.isUseAutoImport()) { + projectSettings.setUseAutoImport(state); + ExternalSystemApiUtil.getSettings(getProject(e), getSystemId(e)).getPublisher() + .onUseAutoImportChange(state, projectSettings.getExternalProjectPath()); + } + } + } + + @Nullable + private ExternalProjectSettings getProjectSettings(AnActionEvent e) { + final ProjectNode projectNode = ExternalSystemDataKeys.SELECTED_PROJECT_NODE.getData(e.getDataContext()); + if (projectNode == null || projectNode.getData() == null) return null; + final AbstractExternalSystemSettings externalSystemSettings = ExternalSystemApiUtil.getSettings(getProject(e), getSystemId(e)); + return externalSystemSettings.getLinkedProjectSettings(projectNode.getData().getLinkedExternalProjectPath()); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignRunConfigurationShortcutAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignRunConfigurationShortcutAction.java new file mode 100644 index 000000000000..191d9afc74f9 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignRunConfigurationShortcutAction.java @@ -0,0 +1,64 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.action.ExternalSystemAction; +import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.externalSystem.view.ExternalSystemNode; +import com.intellij.openapi.externalSystem.view.RunConfigurationNode; +import com.intellij.openapi.keymap.impl.ui.EditKeymapsDialog; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +import static com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemKeymapExtension.getActionPrefix; + +/** + * @author Vladislav.Soroka + * @since 10/28/2014 + */ +public class AssignRunConfigurationShortcutAction extends ExternalSystemAction { + + protected boolean isEnabled(AnActionEvent e) { + if (!super.isEnabled(e)) return false; + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + if (selectedNodes == null || selectedNodes.size() != 1) return false; + return selectedNodes.get(0) instanceof RunConfigurationNode; + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + Project project = getProject(e); + assert project != null; + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + if (selectedNodes == null || selectedNodes.size() != 1 || !(selectedNodes.get(0) instanceof RunConfigurationNode)) return; + + RunnerAndConfigurationSettings settings = ((RunConfigurationNode)selectedNodes.get(0)).getSettings(); + assert settings != null; + + ExternalSystemRunConfiguration runConfiguration = (ExternalSystemRunConfiguration)settings.getConfiguration(); + String actionIdPrefix = getActionPrefix(project, runConfiguration.getSettings().getExternalProjectPath()); + String actionId = actionIdPrefix + settings.getName(); + if (ActionManager.getInstance().getAction(actionId) != null) { + new EditKeymapsDialog(project, actionId).show(); + } + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignShortcutAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignShortcutAction.java new file mode 100644 index 000000000000..76208ed0eb94 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/AssignShortcutAction.java @@ -0,0 +1,49 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.action.ExternalSystemNodeAction; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemShortcutsManager; +import com.intellij.openapi.keymap.impl.ui.EditKeymapsDialog; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + * @since 10/28/2014 + */ +public class AssignShortcutAction extends ExternalSystemNodeAction { + + public AssignShortcutAction() { + super(TaskData.class); + } + + @Override + protected void perform(@NotNull Project project, + @NotNull ProjectSystemId projectSystemId, + @NotNull TaskData taskData, + @NotNull AnActionEvent e) { + final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManager.getInstance(project).getShortcutsManager(); + String actionId = shortcutsManager.getActionId(taskData.getLinkedExternalProjectPath(), taskData.getName()); + if (actionId != null) { + new EditKeymapsDialog(project, actionId).show(); + } + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/GroupTasksAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/GroupTasksAction.java new file mode 100644 index 000000000000..a538267d4632 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/GroupTasksAction.java @@ -0,0 +1,36 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.openapi.externalSystem.action.ExternalSystemViewGearAction; +import com.intellij.openapi.externalSystem.view.ExternalProjectsView; +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + * @since 10/31/2014 + */ +public class GroupTasksAction extends ExternalSystemViewGearAction { + @Override + protected boolean isSelected(@NotNull ExternalProjectsView view) { + return view.getGroupTasks(); + } + + @Override + protected void setSelected(@NotNull ExternalProjectsView view, boolean value) { + view.setGroupTasks(value); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/RunExternalSystemTaskAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/RunExternalSystemTaskAction.java new file mode 100644 index 000000000000..597402a0ae83 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/RunExternalSystemTaskAction.java @@ -0,0 +1,63 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.execution.RunManagerEx; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.externalSystem.action.ExternalSystemActionUtil; +import com.intellij.openapi.externalSystem.action.ExternalSystemNodeAction; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + * @since 10/27/2014 + */ +public class RunExternalSystemTaskAction extends ExternalSystemNodeAction { + + public RunExternalSystemTaskAction() { + super(TaskData.class); + } + + @Override + protected void perform(@NotNull Project project, + @NotNull ProjectSystemId projectSystemId, + @NotNull TaskData taskData, + @NotNull AnActionEvent e) { + final ExternalTaskExecutionInfo taskExecutionInfo = ExternalSystemActionUtil.buildTaskInfo(taskData); + ExternalSystemUtil.runTask(taskExecutionInfo.getSettings(), taskExecutionInfo.getExecutorId(), project, projectSystemId); + + final DataContext dataContext = e.getDataContext(); + final ConfigurationContext context = ConfigurationContext.getFromContext(dataContext); + RunnerAndConfigurationSettings configuration = context.findExisting(); + RunManagerEx runManager = (RunManagerEx)context.getRunManager(); + if (configuration == null) { + configuration = context.getConfiguration(); + if (configuration == null) { + return; + } + runManager.setTemporaryConfiguration(configuration); + } + runManager.setSelectedConfiguration(configuration); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterCompileTasksAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterCompileTasksAction.java new file mode 100644 index 000000000000..a01a104e736b --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterCompileTasksAction.java @@ -0,0 +1,28 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; + +/** + * @author Vladislav.Soroka + * @since 10/29/2014 + */ +public class ToggleAfterCompileTasksAction extends ToggleTaskActivationAction { + protected ToggleAfterCompileTasksAction() { + super(ExternalSystemTaskActivator.Phase.AFTER_COMPILE); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterRebuildTasksAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterRebuildTasksAction.java new file mode 100644 index 000000000000..fbbd52b024f8 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterRebuildTasksAction.java @@ -0,0 +1,28 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; + +/** + * @author Vladislav.Soroka + * @since 10/29/2014 + */ +public class ToggleAfterRebuildTasksAction extends ToggleTaskActivationAction { + protected ToggleAfterRebuildTasksAction() { + super(ExternalSystemTaskActivator.Phase.AFTER_REBUILD); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterSyncTaskAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterSyncTaskAction.java new file mode 100644 index 000000000000..60fc87316712 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleAfterSyncTaskAction.java @@ -0,0 +1,28 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; + +/** + * @author Vladislav.Soroka + * @since 10/29/2014 + */ +public class ToggleAfterSyncTaskAction extends ToggleTaskActivationAction { + protected ToggleAfterSyncTaskAction() { + super(ExternalSystemTaskActivator.Phase.AFTER_SYNC); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeCompileTasksAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeCompileTasksAction.java new file mode 100644 index 000000000000..b19620a928f3 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeCompileTasksAction.java @@ -0,0 +1,28 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; + +/** + * @author Vladislav.Soroka + * @since 10/29/2014 + */ +public class ToggleBeforeCompileTasksAction extends ToggleTaskActivationAction { + protected ToggleBeforeCompileTasksAction() { + super(ExternalSystemTaskActivator.Phase.BEFORE_COMPILE); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeRebuildTasksAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeRebuildTasksAction.java new file mode 100644 index 000000000000..c0403c710396 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeRebuildTasksAction.java @@ -0,0 +1,28 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; + +/** + * @author Vladislav.Soroka + * @since 10/29/2014 + */ +public class ToggleBeforeRebuildTasksAction extends ToggleTaskActivationAction { + protected ToggleBeforeRebuildTasksAction() { + super(ExternalSystemTaskActivator.Phase.BEFORE_REBUILD); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeRunTaskAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeRunTaskAction.java new file mode 100644 index 000000000000..6bef367b1e70 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleBeforeRunTaskAction.java @@ -0,0 +1,28 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; + +/** + * @author Vladislav.Soroka + * @since 10/29/2014 + */ +public class ToggleBeforeRunTaskAction extends ToggleTaskActivationAction { + protected ToggleBeforeRunTaskAction() { + super(null); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleTaskActivationAction.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleTaskActivationAction.java new file mode 100644 index 000000000000..1ca9732fdb03 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/task/ToggleTaskActivationAction.java @@ -0,0 +1,112 @@ +/* + * 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.openapi.externalSystem.action.task; + +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.action.ExternalSystemToggleAction; +import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; +import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; +import com.intellij.openapi.externalSystem.view.ExternalSystemNode; +import com.intellij.openapi.externalSystem.view.RunConfigurationNode; +import com.intellij.openapi.externalSystem.view.TaskNode; +import com.intellij.util.SmartList; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +import static com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator.RUN_CONFIGURATION_TASK_PREFIX; + +/** + * @author Vladislav.Soroka + * @since 10/28/2014 + */ +public abstract class ToggleTaskActivationAction extends ExternalSystemToggleAction { + + private final ExternalSystemTaskActivator.Phase myPhase; + + protected ToggleTaskActivationAction(ExternalSystemTaskActivator.Phase phase) { + myPhase = phase; + } + + @Override + protected boolean isEnabled(AnActionEvent e) { + return super.isEnabled(e) && !getTasks(e).isEmpty(); + } + + @Override + protected boolean doIsSelected(AnActionEvent e) { + return hasTask(getTaskActivator(e), getTasks(e).get(0)); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + List tasks = getTasks(e); + if (state) { + addTasks(getTaskActivator(e), tasks); + } + else { + removeTasks(getTaskActivator(e), tasks); + } + } + + @NotNull + private static List getTasks(AnActionEvent e) { + final List selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext()); + if (selectedNodes == null) return Collections.emptyList(); + + List tasks = new SmartList(); + for (ExternalSystemNode node : selectedNodes) { + if (node instanceof TaskNode) { + tasks.add((TaskData)node.getData()); + } + else if (node instanceof RunConfigurationNode) { + final RunnerAndConfigurationSettings configurationSettings = ((RunConfigurationNode)node).getSettings(); + final ExternalSystemRunConfiguration runConfiguration = (ExternalSystemRunConfiguration)configurationSettings.getConfiguration(); + final ExternalSystemTaskExecutionSettings taskExecutionSettings = runConfiguration.getSettings(); + tasks.add(new TaskData(taskExecutionSettings.getExternalSystemId(), RUN_CONFIGURATION_TASK_PREFIX + configurationSettings.getName(), + taskExecutionSettings.getExternalProjectPath(), null)); + } + else { + return Collections.emptyList(); + } + } + return tasks; + } + + protected boolean hasTask(ExternalSystemTaskActivator manager, TaskData taskData) { + if (taskData == null) return false; + return manager.isTaskOfPhase(taskData, myPhase); + } + + private void addTasks(ExternalSystemTaskActivator taskActivator, List tasks) { + taskActivator.addTasks(tasks, myPhase); + } + + private void removeTasks(ExternalSystemTaskActivator taskActivator, List tasks) { + taskActivator.removeTasks(tasks, myPhase); + } + + + private ExternalSystemTaskActivator getTaskActivator(AnActionEvent e) { + return ExternalProjectsManager.getInstance(getProject(e)).getTaskActivator(); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/model/ExternalSystemDataKeys.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/model/ExternalSystemDataKeys.java index 74295376e59f..23ba428c35a3 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/model/ExternalSystemDataKeys.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/model/ExternalSystemDataKeys.java @@ -17,27 +17,29 @@ package com.intellij.openapi.externalSystem.model; import com.intellij.notification.NotificationGroup; import com.intellij.openapi.actionSystem.DataKey; -import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo; -import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; -import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemRecentTasksList; -import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemTasksTreeModel; +import com.intellij.openapi.externalSystem.ExternalSystemUiAware; +import com.intellij.openapi.externalSystem.view.ExternalProjectsView; +import com.intellij.openapi.externalSystem.view.ExternalSystemNode; +import com.intellij.openapi.externalSystem.view.ProjectNode; import com.intellij.openapi.util.Key; import org.jetbrains.annotations.NotNull; +import javax.swing.*; +import java.util.List; + /** * @author Denis Zhdanov * @since 2/7/12 11:19 AM */ public class ExternalSystemDataKeys { - @NotNull public static final DataKey EXTERNAL_SYSTEM_ID = DataKey.create("external.system.id"); - @NotNull public static final DataKey NOTIFICATION_GROUP = DataKey.create("external.system.notification"); - @NotNull public static final DataKey ALL_TASKS_MODEL = DataKey.create("external.system.all.tasks.model"); - @NotNull public static final DataKey SELECTED_TASK = DataKey.create("external.system.selected.task"); - @NotNull public static final DataKey SELECTED_PROJECT = DataKey.create("external.system.selected.project"); - - @NotNull public static final DataKey RECENT_TASKS_LIST - = DataKey.create("external.system.recent.tasks.list"); + @NotNull public static final DataKey EXTERNAL_SYSTEM_ID = DataKey.create("external.system.id"); + @NotNull public static final DataKey NOTIFICATION_GROUP = DataKey.create("external.system.notification"); + @NotNull public static final DataKey VIEW = DataKey.create("external.system.view"); + @NotNull public static final DataKey SELECTED_PROJECT_NODE = DataKey.create("external.system.selected.project.node"); + @NotNull public static final DataKey> SELECTED_NODES = DataKey.create("external.system.selected.nodes"); + @NotNull public static final DataKey UI_AWARE = DataKey.create("external.system.ui.aware"); + @NotNull public static final DataKey PROJECTS_TREE = DataKey.create("external.system.tree"); @NotNull public static final Key NEWLY_IMPORTED_PROJECT = new Key("external.system.newly.imported"); @NotNull public static final Key NEWLY_CREATED_PROJECT = new Key("external.system.newly.created"); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java index f7040a224c3f..1c9afb70f45e 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java @@ -21,6 +21,7 @@ import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.service.project.ProjectRenameAware; import com.intellij.openapi.externalSystem.service.project.autoimport.ExternalSystemAutoImporter; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; import com.intellij.openapi.externalSystem.service.ui.ExternalToolWindowManager; import com.intellij.openapi.externalSystem.service.vcs.ExternalSystemVcsRegistrar; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; @@ -45,6 +46,8 @@ public class ExternalSystemStartupActivity implements StartupActivity { @SuppressWarnings("unchecked") @Override public void run() { + ExternalProjectsManager.getInstance(project).init(); + for (ExternalSystemManager manager : ExternalSystemApiUtil.getAllManagers()) { if (manager instanceof StartupActivity) { ((StartupActivity)manager).runActivity(project); @@ -52,7 +55,8 @@ public class ExternalSystemStartupActivity implements StartupActivity { } if (project.getUserData(ExternalSystemDataKeys.NEWLY_IMPORTED_PROJECT) != Boolean.TRUE) { for (ExternalSystemManager manager : ExternalSystemManager.EP_NAME.getExtensions()) { - if (project.getUserData(ExternalSystemDataKeys.NEWLY_CREATED_PROJECT) == Boolean.TRUE) { + final boolean isNewProject = project.getUserData(ExternalSystemDataKeys.NEWLY_CREATED_PROJECT) == Boolean.TRUE; + if (isNewProject) { ExternalSystemUtil.refreshProjects( new ImportSpecBuilder(project, manager.getSystemId()) ); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java index 3eb1dd6f4420..1ce056784648 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java @@ -5,27 +5,23 @@ import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.ExternalSystemUiAware; +import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo; import com.intellij.openapi.externalSystem.service.ui.DefaultExternalSystemUiAware; -import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; -import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NotNullLazyValue; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.io.File; import java.util.Collections; import java.util.List; -import java.util.Map; /** * Basic run configuration type for external system tasks. @@ -133,35 +129,16 @@ public abstract class AbstractExternalSystemTaskConfigurationType implements Con @Nullable String externalProjectPath, @NotNull List taskNames, @Nullable String executionName) { - ExternalSystemManager manager = ExternalSystemApiUtil.getManager(externalSystemId); - assert manager != null; - AbstractExternalSystemSettings s = manager.getSettingsProvider().fun(project); - Map rootProjectPaths = ContainerUtilRt.newHashMap(); - for (ExternalProjectSettings projectSettings : s.getLinkedProjectsSettings()) { - String path = projectSettings.getExternalProjectPath(); - if(path == null) continue; - final File rootProjectPathFile = new File(path).getParentFile(); - if(rootProjectPathFile == null) continue; - rootProjectPaths.put(rootProjectPathFile.getAbsolutePath(), path); - } - + String rootProjectPath = null; if (externalProjectPath != null) { - if (!rootProjectPaths.containsKey(externalProjectPath)) { - for (File f = new File(externalProjectPath), prev = null; - f != null && !FileUtil.filesEqual(f, prev); - prev = f, f = f.getParentFile()) - { - rootProjectPath = rootProjectPaths.get(f.getAbsolutePath()); - if (rootProjectPath != null) { - break; - } - } + final ExternalProjectInfo projectInfo = ExternalSystemUtil.getExternalProjectInfo(project, externalSystemId, externalProjectPath); + if (projectInfo != null) { + rootProjectPath = projectInfo.getExternalProjectPath(); } } - + StringBuilder buffer = new StringBuilder(); - final String projectName; if (rootProjectPath == null) { projectName = null; @@ -171,24 +148,23 @@ public abstract class AbstractExternalSystemTaskConfigurationType implements Con } if (!StringUtil.isEmptyOrSpaces(projectName)) { buffer.append(projectName); - buffer.append(" "); + buffer.append(' '); } else { buffer.append(externalProjectPath); - buffer.append(" "); + buffer.append(' '); } - buffer.append("["); + buffer.append('['); if (!StringUtil.isEmpty(executionName)) { buffer.append(executionName); } else if (!taskNames.isEmpty()) { for (String taskName : taskNames) { - buffer.append(taskName).append(" "); + buffer.append(taskName).append(' '); } buffer.setLength(buffer.length() - 1); } - - buffer.append("]"); + buffer.append(']'); return buffer.toString(); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureHelper.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureHelper.java index 79b362e1e1e4..81769681771d 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureHelper.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureHelper.java @@ -1,15 +1,12 @@ package com.intellij.openapi.externalSystem.service.project; -import com.intellij.openapi.externalSystem.model.project.LibraryData; -import com.intellij.openapi.externalSystem.model.project.ModuleData; -import com.intellij.openapi.externalSystem.model.project.ModuleDependencyData; +import com.intellij.openapi.externalSystem.model.project.*; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; -import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -81,4 +78,23 @@ public class ProjectStructureHelper { } return null; } + + @Nullable + public OrderEntry findIdeModuleOrderEntry(LibraryDependencyData data, Project project) { + Module ownerIdeModule = findIdeModule(data.getOwnerModule(), project); + if (ownerIdeModule == null) return null; + + ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(ownerIdeModule); + + for (OrderEntry entry : moduleRootManager.getOrderEntries()) { + if (entry instanceof LibraryOrderEntry) { + if (((LibraryOrderEntry)entry).isModuleLevel() && data.getLevel() != LibraryLevel.MODULE) continue; + } + + if (data.getInternalName().equals(entry.getPresentableName())) { + return entry; + } + } + return null; + } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java index fb4102adc160..4b487ca55232 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsDataStorage.java @@ -15,21 +15,39 @@ */ package com.intellij.openapi.externalSystem.service.project.manage; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.components.SettingsSavingComponent; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.model.DataNode; import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; +import com.intellij.openapi.externalSystem.model.ProjectKeys; import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo; import com.intellij.openapi.externalSystem.model.internal.InternalExternalProjectInfo; +import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; +import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.module.ModuleTypeId; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.Consumer; +import com.intellij.util.Function; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.*; +import java.util.Collection; +import java.util.Iterator; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; /** * @author Vladislav.Soroka @@ -38,11 +56,14 @@ import java.util.Map; public class ExternalProjectsDataStorage implements SettingsSavingComponent { private static final Logger LOG = Logger.getInstance(ExternalProjectsDataStorage.class); + private static final String STORAGE_VERSION = ExternalProjectsDataStorage.class.getSimpleName() + ".1"; + @NotNull private final Project myProject; @NotNull - private final Map, InternalExternalProjectInfo> myExternalRootProjects = - ContainerUtil.newConcurrentMap(); + private final Map, InternalExternalProjectInfo> myExternalRootProjects = ContainerUtil.newConcurrentMap(); + + private final AtomicBoolean changed = new AtomicBoolean(); public static ExternalProjectsDataStorage getInstance(@NotNull Project project) { return ServiceManager.getService(project, ExternalProjectsDataStorage.class); @@ -52,16 +73,50 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponent { myProject = project; } - public void load() { - // TODO [Vlad] load data for the opened project + public synchronized void load() { + myExternalRootProjects.clear(); + try { + final Collection projectInfos = load(myProject); + for (InternalExternalProjectInfo projectInfo : projectInfos) { + if (validate(projectInfo)) { + myExternalRootProjects.put(Pair.create(projectInfo.getProjectSystemId(), projectInfo.getExternalProjectPath()), projectInfo); + } + } + } + catch (IOException e) { + LOG.debug(e); + } + + mergeLocalSettings(); + } + + private static boolean validate(InternalExternalProjectInfo externalProjectInfo) { + try { + final DataNode projectStructure = externalProjectInfo.getExternalProjectStructure(); + if (projectStructure == null) return false; + + ProjectDataManager.getInstance().ensureTheDataIsReadyToUse(projectStructure); + return externalProjectInfo.getExternalProjectPath().equals(projectStructure.getData().getLinkedExternalProjectPath()); + } + catch (Exception e) { + LOG.warn(e); + } + return false; } @Override - public void save() { - // TODO [Vlad] save data if changed + public synchronized void save() { + if (!changed.compareAndSet(true, false)) return; + + try { + doSave(myProject, myExternalRootProjects.values()); + } + catch (IOException e) { + LOG.debug(e); + } } - void add(@NotNull ExternalProjectInfo externalProjectInfo) { + synchronized void update(@NotNull ExternalProjectInfo externalProjectInfo) { final ProjectSystemId projectSystemId = externalProjectInfo.getProjectSystemId(); final String projectPath = externalProjectInfo.getExternalProjectPath(); DataNode externalProjectStructure = externalProjectInfo.getExternalProjectStructure(); @@ -88,10 +143,172 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponent { merged.setLastImportTimestamp(lastImportTimestamp); merged.setLastSuccessfulImportTimestamp(lastSuccessfulImportTimestamp); myExternalRootProjects.put(key, merged); + + changed.set(true); } @Nullable - ExternalProjectInfo get(@NotNull ProjectSystemId projectSystemId, @NotNull String externalProjectPath) { + synchronized ExternalProjectInfo get(@NotNull ProjectSystemId projectSystemId, @NotNull String externalProjectPath) { return myExternalRootProjects.get(Pair.create(projectSystemId, externalProjectPath)); } + + synchronized void remove(@NotNull ProjectSystemId projectSystemId, @NotNull String externalProjectPath) { + final InternalExternalProjectInfo removed = myExternalRootProjects.remove(Pair.create(projectSystemId, externalProjectPath)); + if(removed != null) { + changed.set(true); + } + } + + @NotNull + synchronized Collection list(@NotNull final ProjectSystemId projectSystemId) { + return ContainerUtil.mapNotNull(myExternalRootProjects.values(), new Function() { + @Override + public ExternalProjectInfo fun(InternalExternalProjectInfo info) { + return projectSystemId.equals(info.getProjectSystemId()) ? info : null; + } + }); + } + + private void mergeLocalSettings() { + for (ExternalSystemManager manager : ExternalSystemApiUtil.getAllManagers()) { + final ProjectSystemId systemId = manager.getSystemId(); + + AbstractExternalSystemLocalSettings settings = manager.getLocalSettingsProvider().fun(myProject); + final Map> availableProjects = settings.getAvailableProjects(); + final Map> availableTasks = settings.getAvailableTasks(); + + for (Map.Entry> entry : availableProjects.entrySet()) { + final ExternalProjectPojo projectPojo = entry.getKey(); + final String externalProjectPath = projectPojo.getPath(); + final Pair key = Pair.create(systemId, externalProjectPath); + InternalExternalProjectInfo externalProjectInfo = myExternalRootProjects.get(key); + if (externalProjectInfo == null) { + final DataNode dataNode = convert(systemId, projectPojo, entry.getValue(), availableTasks); + externalProjectInfo = new InternalExternalProjectInfo(systemId, externalProjectPath, dataNode); + myExternalRootProjects.put(key, externalProjectInfo); + + changed.set(true); + } + } + } + } + + private static DataNode convert(@NotNull ProjectSystemId systemId, + @NotNull ExternalProjectPojo rootProject, + @NotNull Collection childProjects, + @NotNull Map> availableTasks) { + ProjectData projectData = new ProjectData(systemId, rootProject.getName(), rootProject.getPath(), rootProject.getPath()); + DataNode projectDataNode = new DataNode(ProjectKeys.PROJECT, projectData, null); + + for (ExternalProjectPojo childProject : childProjects) { + String moduleConfigPath = childProject.getPath(); + ModuleData moduleData = new ModuleData(childProject.getName(), systemId, + ModuleTypeId.JAVA_MODULE, childProject.getName(), + moduleConfigPath, moduleConfigPath); + final DataNode moduleDataNode = projectDataNode.createChild(ProjectKeys.MODULE, moduleData); + + final Collection moduleTasks = availableTasks.get(moduleConfigPath); + if (moduleTasks != null) { + for (ExternalTaskPojo moduleTask : moduleTasks) { + TaskData taskData = new TaskData(systemId, moduleTask.getName(), moduleConfigPath, moduleTask.getDescription()); + moduleDataNode.createChild(ProjectKeys.TASK, taskData); + } + } + } + + return projectDataNode; + } + + private static void doSave(@NotNull Project project, @NotNull Collection externalProjects) throws IOException { + final File projectConfigurationFile = getProjectConfigurationFile(project); + if (!FileUtil.createParentDirs(projectConfigurationFile)) { + throw new IOException("Unable to save " + projectConfigurationFile); + } + + for (Iterator iterator = externalProjects.iterator(); iterator.hasNext(); ) { + InternalExternalProjectInfo externalProject = iterator.next(); + if (!validate(externalProject)) { + iterator.remove(); + continue; + } + + ExternalSystemApiUtil.visit(externalProject.getExternalProjectStructure(), new Consumer() { + @Override + public void consume(DataNode dataNode) { + try { + dataNode.getDataBytes(); + } + catch (IOException e) { + dataNode.clear(true); + } + } + }); + } + + DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(projectConfigurationFile))); + try { + out.writeUTF(STORAGE_VERSION); + out.writeInt(externalProjects.size()); + ObjectOutputStream os = new ObjectOutputStream(out); + try { + for (InternalExternalProjectInfo externalProject : externalProjects) { + os.writeObject(externalProject); + } + } + finally { + os.close(); + } + } + finally { + out.close(); + } + } + + @NotNull + private static Collection load(@NotNull Project project) throws IOException { + SmartList projects = new SmartList(); + final File configurationFile = getProjectConfigurationFile(project); + if (!configurationFile.isFile()) return projects; + + DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(configurationFile))); + + try { + final String storage_version = in.readUTF(); + if (!STORAGE_VERSION.equals(storage_version)) return projects; + final int size = in.readInt(); + + ObjectInputStream os = new ObjectInputStream(in); + try { + for (int i = 0; i < size; i++) { + //noinspection unchecked + InternalExternalProjectInfo projectDataDataNode = (InternalExternalProjectInfo)os.readObject(); + projects.add(projectDataDataNode); + } + } + catch (ClassNotFoundException e) { + IOException ioException = new IOException(); + ioException.initCause(e); + throw ioException; + } + finally { + os.close(); + } + } + finally { + in.close(); + } + return projects; + } + + private static File getProjectConfigurationFile(@NotNull Project project) { + return new File(getProjectConfigurationDir(), project.getLocationHash() + "/project.dat"); + } + + private static File getProjectConfigurationDir() { + return getExternalBuildSystemDir("Projects"); + } + + private static File getExternalBuildSystemDir(String folder) { + return new File(PathManager.getSystemPath(), "external_build_system" + "/" + folder).getAbsoluteFile(); + } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManager.java new file mode 100644 index 000000000000..b72653355055 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsManager.java @@ -0,0 +1,239 @@ +/* + * 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.openapi.externalSystem.service.project.manage; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.*; +import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.externalSystem.view.ExternalProjectsView; +import com.intellij.openapi.externalSystem.view.ExternalProjectsViewState; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.util.Function; +import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.intellij.openapi.externalSystem.model.ProjectKeys.TASK; + +/** + * @author Vladislav.Soroka + * @since 10/23/2014 + */ +@State(name = "ExternalProjectsManager", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)}) +public class ExternalProjectsManager implements PersistentStateComponent, Disposable { + + private final AtomicBoolean isInitialized = new AtomicBoolean(); + @NotNull + private ExternalProjectsState myState = new ExternalProjectsState(); + + @NotNull + private final Project myProject; + private final ExternalSystemRunManagerListener myRunManagerListener; + private final ExternalSystemTaskActivator myTaskActivator; + private final ExternalSystemShortcutsManager myShortcutsManager; + private final List myProjectsViews = new SmartList(); + + + public static ExternalProjectsManager getInstance(@NotNull Project project) { + return ServiceManager.getService(project, ExternalProjectsManager.class); + } + + public ExternalProjectsManager(@NotNull Project project) { + myProject = project; + Disposer.register(project, this); + myShortcutsManager = new ExternalSystemShortcutsManager(project); + Disposer.register(this, myShortcutsManager); + myTaskActivator = new ExternalSystemTaskActivator(project); + myRunManagerListener = new ExternalSystemRunManagerListener(this); + } + + @NotNull + public Project getProject() { + return myProject; + } + + public ExternalSystemShortcutsManager getShortcutsManager() { + return myShortcutsManager; + } + + public ExternalSystemTaskActivator getTaskActivator() { + return myTaskActivator; + } + + public void registerView(@NotNull ExternalProjectsView externalProjectsView) { + init(); + myProjectsViews.add(externalProjectsView); + externalProjectsView.loadState( + myState.getExternalSystemsState().get(externalProjectsView.getSystemId().getId()).getProjectsViewState()); + externalProjectsView.init(); + } + + @Nullable + public ExternalProjectsView getExternalProjectsView(@NotNull ProjectSystemId systemId) { + for (ExternalProjectsView projectsView : myProjectsViews) { + if(projectsView.getSystemId().equals(systemId)) return projectsView; + } + return null; + } + + public void init() { + synchronized (isInitialized) { + if (isInitialized.getAndSet(true)) return; + + // load external projects data + ExternalProjectsDataStorage.getInstance(myProject).load(); + myRunManagerListener.attach(); + + // init shortcuts manager + myShortcutsManager.init(); + for (ExternalSystemManager systemManager : ExternalSystemApiUtil.getAllManagers()) { + final Collection externalProjects = + ExternalProjectsDataStorage.getInstance(myProject).list(systemManager.getSystemId()); + for (ExternalProjectInfo externalProject : externalProjects) { + if (externalProject.getExternalProjectStructure() == null) continue; + Collection> taskData = + ExternalSystemApiUtil.findAllRecursively(externalProject.getExternalProjectStructure(), TASK); + myShortcutsManager.scheduleKeymapUpdate(taskData); + } + + if (!externalProjects.isEmpty()) { + myShortcutsManager.scheduleRunConfigurationKeymapUpdate(systemManager.getSystemId()); + } + } + // init task activation info + myTaskActivator.init(); + } + } + + public void updateExternalProjectData(ExternalProjectInfo externalProject) { + // update external projects data + ExternalProjectsDataStorage.getInstance(myProject).update(externalProject); + + // update shortcuts manager + if (externalProject.getExternalProjectStructure() != null) { + final ProjectData projectData = externalProject.getExternalProjectStructure().getData(); + + ExternalSystemUtil.scheduleExternalViewStructureUpdate(myProject, projectData.getOwner()); + + Collection> taskData = + ExternalSystemApiUtil.findAllRecursively(externalProject.getExternalProjectStructure(), TASK); + myShortcutsManager.scheduleKeymapUpdate(taskData); + myShortcutsManager.scheduleRunConfigurationKeymapUpdate(projectData.getOwner()); + } + } + + public void forgetExternalProjectData(@NotNull ProjectSystemId projectSystemId, @NotNull String linkedProjectPath) { + ExternalProjectsDataStorage.getInstance(myProject).remove(projectSystemId, linkedProjectPath); + } + + @NotNull + @Override + public ExternalProjectsState getState() { + ApplicationManager.getApplication().assertIsDispatchThread(); + for (ExternalProjectsView externalProjectsView : myProjectsViews) { + final ExternalProjectsViewState externalProjectsViewState = externalProjectsView.getState(); + final ExternalProjectsState.State state = myState.getExternalSystemsState().get(externalProjectsView.getSystemId().getId()); + assert state != null; + state.setProjectsViewState(externalProjectsViewState); + } + return myState; + } + + @NotNull + public ExternalProjectsStateProvider getStateProvider() { + return new ExternalProjectsStateProvider() { + @Override + public List getAllTasksActivation() { + List result = new SmartList(); + for (Map.Entry systemState : myState.getExternalSystemsState().entrySet()) { + ProjectSystemId systemId = new ProjectSystemId(systemState.getKey()); + for (Map.Entry activationStateEntry : systemState.getValue().getExternalSystemsTaskActivation() + .entrySet()) { + result.add(new TasksActivation(systemId, activationStateEntry.getKey(), activationStateEntry.getValue())); + } + } + + return result; + } + + @Override + public List getTasksActivation(@NotNull final ProjectSystemId systemId) { + final Set> entries = + myState.getExternalSystemsState().get(systemId.getId()).getExternalSystemsTaskActivation().entrySet(); + return ContainerUtil.map(entries, new Function, TasksActivation>() { + @Override + public TasksActivation fun(Map.Entry entry) { + return new TasksActivation(systemId, entry.getKey(), entry.getValue()); + } + }); + } + + @Override + public TaskActivationState getTasksActivation(@NotNull ProjectSystemId systemId, @NotNull String projectPath) { + return myState.getExternalSystemsState().get(systemId.getId()).getExternalSystemsTaskActivation().get(projectPath); + } + }; + } + + @Override + public void loadState(ExternalProjectsState state) { + myState = state == null ? new ExternalProjectsState() : state; + } + + @Override + public void dispose() { + myProjectsViews.clear(); + myRunManagerListener.detach(); + } + + public interface ExternalProjectsStateProvider { + class TasksActivation { + public final ProjectSystemId systemId; + public final String projectPath; + public final TaskActivationState state; + + public TasksActivation(ProjectSystemId systemId, + String projectPath, + TaskActivationState state) { + this.systemId = systemId; + this.projectPath = projectPath; + this.state = state; + } + } + + List getAllTasksActivation(); + + List getTasksActivation(@NotNull ProjectSystemId systemId); + + TaskActivationState getTasksActivation(@NotNull ProjectSystemId systemId, @NotNull String projectPath); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsState.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsState.java new file mode 100644 index 000000000000..3a0532696758 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalProjectsState.java @@ -0,0 +1,100 @@ +/* + * 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.openapi.externalSystem.service.project.manage; + +import com.intellij.openapi.externalSystem.view.ExternalProjectsViewState; +import com.intellij.util.containers.FactoryMap; +import com.intellij.util.xmlb.annotations.MapAnnotation; +import com.intellij.util.xmlb.annotations.Property; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 10/23/2014 + */ +public class ExternalProjectsState { + + + private final Map myExternalSystemsState = new NullSafeMap() { + @Nullable + @Override + protected State create(String key) { + return new State(); + } + }; + + @Property(surroundWithTag = false) + @MapAnnotation(surroundWithTag = false, surroundValueWithTag = false, surroundKeyWithTag = false, + keyAttributeName = "id", entryTagName = "system") + public Map getExternalSystemsState() { + return myExternalSystemsState; + } + + @SuppressWarnings("UnusedDeclaration") + public void setExternalSystemsState(Map externalSystemsState) { + } + + + @Tag("state") + public static class State { + private ExternalProjectsViewState projectsViewState = new ExternalProjectsViewState(); + + private final Map myExternalSystemsTaskActivation = new FactoryMap() { + @Nullable + @Override + protected TaskActivationState create(String key) { + return new TaskActivationState(); + } + + @Override + public TaskActivationState put(String key, TaskActivationState value) { + if(value == null) return null; + return super.put(key, value); + } + }; + + @Property(surroundWithTag = false) + @MapAnnotation(surroundWithTag = false, surroundValueWithTag = false, surroundKeyWithTag = false, + keyAttributeName = "path", entryTagName = "task", sortBeforeSave = false) + public Map getExternalSystemsTaskActivation() { + return myExternalSystemsTaskActivation; + } + + @SuppressWarnings("UnusedDeclaration") + public void setExternalSystemsTaskActivation(Map externalSystemsTaskActivation) { + } + + @Property(surroundWithTag = false) + public ExternalProjectsViewState getProjectsViewState() { + return projectsViewState; + } + + public void setProjectsViewState(ExternalProjectsViewState projectsViewState) { + this.projectsViewState = projectsViewState; + } + } + + public static abstract class NullSafeMap extends FactoryMap { + @Override + public V put(K key, V value) { + if(value == null) return null; + return super.put(key, value); + } + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemKeymapExtension.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemKeymapExtension.java new file mode 100644 index 000000000000..1122cb222942 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemKeymapExtension.java @@ -0,0 +1,276 @@ +/* + * 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.openapi.externalSystem.service.project.manage; + +import com.intellij.execution.ProgramRunnerUtil; +import com.intellij.execution.RunManager; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.externalSystem.ExternalSystemUiAware; +import com.intellij.openapi.externalSystem.action.ExternalSystemAction; +import com.intellij.openapi.externalSystem.action.ExternalSystemActionUtil; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ProjectKeys; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; +import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.keymap.KeymapExtension; +import com.intellij.openapi.keymap.KeymapGroup; +import com.intellij.openapi.keymap.KeymapGroupFactory; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; +import gnu.trove.THashSet; +import icons.ExternalSystemIcons; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +/** + * @author Vladislav.Soroka + * @since 10/27/2014 + */ +public class ExternalSystemKeymapExtension implements KeymapExtension { + + public KeymapGroup createGroup(Condition condition, Project project) { + KeymapGroup result = KeymapGroupFactory.getInstance().createGroup( + ExternalSystemBundle.message("external.system.keymap.group"), ExternalSystemIcons.TaskGroup); + if (project == null) return result; + + MultiMap, String> projectToActionsMapping = MultiMap.create(); + + ActionManager actionManager = ActionManager.getInstance(); + for (String eachId : actionManager.getActionIds(getActionPrefix(project, null))) { + AnAction eachAction = actionManager.getAction(eachId); + + if (!(eachAction instanceof MyExternalSystemAction)) continue; + if (condition != null && !condition.value(actionManager.getActionOrStub(eachId))) continue; + + MyExternalSystemAction taskAction = (MyExternalSystemAction)eachAction; + projectToActionsMapping.putValue(Pair.create(taskAction.getSystemId(), taskAction.getGroup()), eachId); + } + + Map keymapGroupMap = ContainerUtil.newHashMap(); + for (Pair pair : projectToActionsMapping.keySet()) { + if (!keymapGroupMap.containsKey(pair.first)) { + final Icon projectIcon = ExternalSystemUiUtil.getUiAware(pair.first).getProjectIcon(); + KeymapGroup group = KeymapGroupFactory.getInstance().createGroup(pair.first.getReadableName(), projectIcon); + result.addGroup(group); + keymapGroupMap.put(pair.first, group); + } + } + + + for (Map.Entry, Collection> each : projectToActionsMapping.entrySet()) { + String groupName = each.getKey().second; + Collection tasks = each.getValue(); + if (tasks.isEmpty()) continue; + KeymapGroup group = KeymapGroupFactory.getInstance().createGroup(groupName, ExternalSystemIcons.TaskGroup); + + final KeymapGroup systemGroup = keymapGroupMap.get(each.getKey().first); + if (systemGroup != null) { + systemGroup.addGroup(group); + } + else { + result.addGroup(group); + } + for (String actionId : tasks) { + group.addActionId(actionId); + } + } + + return result; + } + + public static void updateActions(Project project, Collection> taskData) { + clearActions(project, taskData); + createActions(project, taskData); + } + + private static void createActions(Project project, Collection> taskData) { + ActionManager manager = ActionManager.getInstance(); + for (DataNode each : taskData) { + final DataNode moduleData = ExternalSystemApiUtil.findParent(each, ProjectKeys.MODULE); + if (moduleData == null) continue; + ExternalSystemTaskAction eachAction = new ExternalSystemTaskAction(project, moduleData.getData().getInternalName(), each.getData()); + + manager.unregisterAction(eachAction.getId()); + manager.registerAction(eachAction.getId(), eachAction); + } + } + + public static void clearActions(Project project) { + ActionManager manager = ActionManager.getInstance(); + for (String each : manager.getActionIds(getActionPrefix(project, null))) { + manager.unregisterAction(each); + } + } + + public static void clearActions(Project project, Collection> taskData) { + ActionManager manager = ActionManager.getInstance(); + for (DataNode each : taskData) { + for (String eachAction : manager.getActionIds(getActionPrefix(project, each.getData().getLinkedExternalProjectPath()))) { + manager.unregisterAction(eachAction); + } + } + } + + public static String getActionPrefix(@NotNull Project project, @Nullable String path) { + return ExternalProjectsManager.getInstance(project).getShortcutsManager().getActionId(path, null); + } + + public static void updateRunConfigurationActions(Project project, ProjectSystemId systemId) { + final AbstractExternalSystemTaskConfigurationType configurationType = ExternalSystemUtil.findConfigurationType(systemId); + if (configurationType == null) return; + + Set settings = new THashSet( + RunManager.getInstance(project).getConfigurationSettingsList(configurationType)); + + ActionManager manager = ActionManager.getInstance(); + for (RunnerAndConfigurationSettings configurationSettings : settings) { + ExternalSystemRunConfigurationAction runConfigurationAction = + new ExternalSystemRunConfigurationAction(project, configurationSettings); + String id = runConfigurationAction.getId(); + manager.unregisterAction(id); + manager.registerAction(id, runConfigurationAction); + } + } + + private abstract static class MyExternalSystemAction extends ExternalSystemAction { + public abstract String getId(); + + public abstract String getGroup(); + + public abstract ProjectSystemId getSystemId(); + } + + private static class ExternalSystemTaskAction extends MyExternalSystemAction { + private final String myId; + private final String myGroup; + private final TaskData myTaskData; + + public ExternalSystemTaskAction(Project project, String group, TaskData taskData) { + myGroup = group; + myTaskData = taskData; + myId = getActionPrefix(project, taskData.getLinkedExternalProjectPath()) + taskData.getName(); + + Presentation template = getTemplatePresentation(); + template.setText(myTaskData.getName(), false); + template.setIcon(ExternalSystemIcons.Task); + } + + @Override + protected boolean isEnabled(AnActionEvent e) { + return hasProject(e); + } + + public void actionPerformed(@NotNull AnActionEvent e) { + final ExternalTaskExecutionInfo taskExecutionInfo = ExternalSystemActionUtil.buildTaskInfo(myTaskData); + ExternalSystemUtil.runTask( + taskExecutionInfo.getSettings(), taskExecutionInfo.getExecutorId(), getProject(e), myTaskData.getOwner()); + } + + public TaskData getTaskData() { + return myTaskData; + } + + public String toString() { + return myTaskData.toString(); + } + + @Override + public String getGroup() { + return myGroup; + } + + @Override + public ProjectSystemId getSystemId() { + return myTaskData.getOwner(); + } + + @Override + public String getId() { + return myId; + } + } + + private static class ExternalSystemRunConfigurationAction extends MyExternalSystemAction { + private final String myId; + private final String myGroup; + private final RunnerAndConfigurationSettings myConfigurationSettings; + private final ProjectSystemId systemId; + + public ExternalSystemRunConfigurationAction(Project project, RunnerAndConfigurationSettings configurationSettings) { + myConfigurationSettings = configurationSettings; + ExternalSystemRunConfiguration runConfiguration = (ExternalSystemRunConfiguration)configurationSettings.getConfiguration(); + systemId = runConfiguration.getSettings().getExternalSystemId(); + + ExternalSystemUiAware uiAware = ExternalSystemUiUtil.getUiAware(systemId); + myGroup = uiAware.getProjectRepresentationName(runConfiguration.getSettings().getExternalProjectPath(), null); + String actionIdPrefix = getActionPrefix(project, runConfiguration.getSettings().getExternalProjectPath()); + myId = actionIdPrefix + configurationSettings.getName(); + + Presentation template = getTemplatePresentation(); + template.setText(myConfigurationSettings.getName(), false); + template.setIcon(runConfiguration.getIcon()); + } + + @Override + protected boolean isEnabled(AnActionEvent e) { + return hasProject(e); + } + + public void actionPerformed(@NotNull AnActionEvent e) { + ProgramRunnerUtil.executeConfiguration(getProject(e), myConfigurationSettings, DefaultRunExecutor.getRunExecutorInstance()); + } + + public String toString() { + return myConfigurationSettings.toString(); + } + + @Override + public String getGroup() { + return myGroup; + } + + @Override + public ProjectSystemId getSystemId() { + return systemId; + } + + public String getId() { + return myId; + } + } +} + diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemRunManagerListener.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemRunManagerListener.java new file mode 100644 index 000000000000..3edc1aecd4b3 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemRunManagerListener.java @@ -0,0 +1,143 @@ +/* + * 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.openapi.externalSystem.service.project.manage; + +import com.intellij.execution.RunManager; +import com.intellij.execution.RunManagerAdapter; +import com.intellij.execution.RunManagerEx; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; +import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.util.Pair; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator.*; + +/** + * @author Vladislav.Soroka + * @since 11/14/2014 + */ +class ExternalSystemRunManagerListener extends RunManagerAdapter { + + private ExternalProjectsManager myManager; + private final Map> myMap; + + public ExternalSystemRunManagerListener(ExternalProjectsManager manager) { + myManager = manager; + myMap = ContainerUtil.newConcurrentMap(); + } + + @Override + public void runConfigurationAdded(@NotNull RunnerAndConfigurationSettings settings) { + add(myMap, settings); + } + + @Override + public void runConfigurationRemoved(@NotNull RunnerAndConfigurationSettings settings) { + if (settings.getConfiguration() instanceof ExternalSystemRunConfiguration) { + final Pair pair = myMap.remove(System.identityHashCode(settings)); + if (pair == null) return; + + final ExternalProjectsManager.ExternalProjectsStateProvider stateProvider = myManager.getStateProvider(); + final ExternalSystemTaskExecutionSettings taskExecutionSettings = + ((ExternalSystemRunConfiguration)settings.getConfiguration()).getSettings(); + + if(taskExecutionSettings.getExternalProjectPath() == null) return; + + final TaskActivationState activation = + stateProvider.getTasksActivation(taskExecutionSettings.getExternalSystemId(), taskExecutionSettings.getExternalProjectPath()); + + for (Phase phase : Phase.values()) { + for (Iterator iterator = activation.getTasks(phase).iterator(); iterator.hasNext(); ) { + String task = iterator.next(); + if (pair.first.equals(task)) { + iterator.remove(); + break; + } + } + } + } + } + + @Override + public void runConfigurationChanged(@NotNull RunnerAndConfigurationSettings settings) { + if (settings.getConfiguration() instanceof ExternalSystemRunConfiguration) { + final Pair pair = myMap.get(System.identityHashCode(settings)); + if (pair != null) { + final ExternalProjectsManager.ExternalProjectsStateProvider stateProvider = myManager.getStateProvider(); + final ExternalSystemTaskExecutionSettings taskExecutionSettings = + ((ExternalSystemRunConfiguration)settings.getConfiguration()).getSettings(); + + if(taskExecutionSettings.getExternalProjectPath() == null) return; + + final TaskActivationState activation = + stateProvider.getTasksActivation(taskExecutionSettings.getExternalSystemId(), taskExecutionSettings.getExternalProjectPath()); + + for (Phase phase : Phase.values()) { + final Set modifiableActivationTasks = activation.getTasks(phase); + for (String task : ContainerUtil.newTroveSet(modifiableActivationTasks)) { + if (pair.first.equals(task)) { + modifiableActivationTasks.remove(task); + final String runConfigurationActivationTaskName = getRunConfigurationActivationTaskName(settings); + modifiableActivationTasks.add(runConfigurationActivationTaskName); + myMap.put(System.identityHashCode(settings), Pair.create(runConfigurationActivationTaskName, settings)); + break; + } + } + } + } + } + } + + public void attach() { + myMap.clear(); + + for (ExternalSystemManager systemManager : ExternalSystemApiUtil.getAllManagers()) { + final AbstractExternalSystemTaskConfigurationType configurationType = + ExternalSystemUtil.findConfigurationType(systemManager.getSystemId()); + if (configurationType == null) continue; + final List configurationSettingsList = + RunManager.getInstance(myManager.getProject()).getConfigurationSettingsList(configurationType); + for (RunnerAndConfigurationSettings configurationSettings : configurationSettingsList) { + add(myMap, configurationSettings); + } + } + + ((RunManagerEx)RunManager.getInstance(myManager.getProject())).addRunManagerListener(this); + } + + public void detach() { + myMap.clear(); + ((RunManagerEx)RunManager.getInstance(myManager.getProject())).removeRunManagerListener(this); + } + + private static void add(@NotNull Map> map, + @NotNull RunnerAndConfigurationSettings settings) { + if (settings.getConfiguration() instanceof ExternalSystemRunConfiguration) { + map.put(System.identityHashCode(settings), Pair.create(getRunConfigurationActivationTaskName(settings), settings)); + } + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemShortcutsManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemShortcutsManager.java new file mode 100644 index 000000000000..911b63340a1c --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemShortcutsManager.java @@ -0,0 +1,149 @@ +/* + * 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.openapi.externalSystem.service.project.manage; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.Shortcut; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.keymap.Keymap; +import com.intellij.openapi.keymap.KeymapManager; +import com.intellij.openapi.keymap.KeymapManagerListener; +import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.keymap.ex.KeymapManagerEx; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Collection; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 10/27/2014 + */ +public class ExternalSystemShortcutsManager implements Disposable { + + private static final String ACTION_ID_PREFIX = "ExternalSystem_"; + @NotNull + private final Project myProject; + private ExternalSystemKeyMapListener myKeyMapListener; + private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); + + public ExternalSystemShortcutsManager(@NotNull Project project) { + myProject = project; + } + + public void init() { + myKeyMapListener = new ExternalSystemKeyMapListener(); + } + + public String getActionId(@Nullable String projectPath, @Nullable String taskName) { + StringBuilder result = new StringBuilder(ACTION_ID_PREFIX); + result.append(myProject.getLocationHash()); + + if (projectPath != null) { + String portablePath = FileUtil.toSystemIndependentName(projectPath); + result.append(new File(portablePath).getParentFile().getName()); + result.append(Integer.toHexString(portablePath.hashCode())); + + if (taskName != null) result.append(taskName); + } + + return result.toString(); + } + + public String getDescription(@Nullable String projectPath, @Nullable String taskName) { + String actionId = getActionId(projectPath, taskName); + if (actionId == null) return ""; + + Keymap activeKeymap = KeymapManager.getInstance().getActiveKeymap(); + Shortcut[] shortcuts = activeKeymap.getShortcuts(actionId); + if (shortcuts == null || shortcuts.length == 0) return ""; + + return KeymapUtil.getShortcutsText(shortcuts); + } + + private void fireShortcutsUpdated() { + for (Listener listener : myListeners) { + listener.shortcutsUpdated(); + } + } + + public void addListener(Listener listener) { + myListeners.add(listener); + } + + public interface Listener { + void shortcutsUpdated(); + } + + private class ExternalSystemKeyMapListener implements KeymapManagerListener, Keymap.Listener { + private Keymap myCurrentKeymap = null; + + public ExternalSystemKeyMapListener() { + KeymapManager keymapManager = KeymapManager.getInstance(); + listenTo(keymapManager.getActiveKeymap()); + keymapManager.addKeymapManagerListener(this); + } + + @Override + public void activeKeymapChanged(Keymap keymap) { + listenTo(keymap); + fireShortcutsUpdated(); + } + + private void listenTo(Keymap keymap) { + if (myCurrentKeymap != null) { + myCurrentKeymap.removeShortcutChangeListener(this); + } + myCurrentKeymap = keymap; + if (myCurrentKeymap != null) { + myCurrentKeymap.addShortcutChangeListener(this); + } + } + + @Override + public void onShortcutChanged(String actionId) { + fireShortcutsUpdated(); + } + + public void stopListen() { + listenTo(null); + KeymapManagerEx.getInstanceEx().removeKeymapManagerListener(this); + } + } + + public void scheduleKeymapUpdate(Collection> taskData) { + ExternalSystemKeymapExtension.updateActions(myProject, taskData); + } + + public void scheduleRunConfigurationKeymapUpdate(@NotNull ProjectSystemId externalSystemId) { + ExternalSystemKeymapExtension.updateRunConfigurationActions(myProject, externalSystemId); + } + + @Override + public void dispose() { + if (myKeyMapListener != null) { + myKeyMapListener.stopListen(); + } + ExternalSystemKeymapExtension.clearActions(myProject); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java new file mode 100644 index 000000000000..053517021fca --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ExternalSystemTaskActivator.java @@ -0,0 +1,259 @@ +/* + * 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.openapi.externalSystem.service.project.manage; + +import com.intellij.execution.RunManager; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileTask; +import com.intellij.openapi.compiler.CompilerManager; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager.ExternalProjectsStateProvider; +import com.intellij.openapi.externalSystem.task.TaskCallback; +import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Function; +import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.FactoryMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Vladislav.Soroka + * @since 10/28/2014 + */ +public class ExternalSystemTaskActivator { + + public static final String RUN_CONFIGURATION_TASK_PREFIX = "run: "; + @NotNull private final Project myProject; + private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); + + public ExternalSystemTaskActivator(@NotNull Project project) { + myProject = project; + } + + @NotNull + public static String getRunConfigurationActivationTaskName(@NotNull RunnerAndConfigurationSettings settings) { + return RUN_CONFIGURATION_TASK_PREFIX + settings.getName(); + } + + public void init() { + CompilerManager compilerManager = CompilerManager.getInstance(myProject); + + class MyCompileTask implements CompileTask { + private final boolean myBefore; + + MyCompileTask(boolean before) { + myBefore = before; + } + + @Override + public boolean execute(CompileContext context) { + return doExecute(myBefore, context); + } + } + + compilerManager.addBeforeTask(new MyCompileTask(true)); + compilerManager.addAfterTask(new MyCompileTask(false)); + + fireTasksChanged(); + } + + public String getDescription(ProjectSystemId systemId, String projectPath, String taskName) { + List result = new ArrayList(); + final ExternalProjectsStateProvider stateProvider = + ExternalProjectsManager.getInstance(myProject).getStateProvider(); + final TaskActivationState taskActivationState = stateProvider.getTasksActivation(systemId, projectPath); + if (taskActivationState == null) return null; + + for (Phase phase : Phase.values()) { + if (taskActivationState.getTasks(phase).contains(taskName)) { + result.add(ExternalSystemBundle.message(phase.myMessageKey)); + } + } + return StringUtil.join(result, ", "); + } + + private boolean doExecute(boolean before, CompileContext context) { + + final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider(); + + final Queue> tasksQueue = + new LinkedList>(); + + //noinspection MismatchedQueryAndUpdateOfCollection + Map> lazyConfigurationsMap = + new FactoryMap>() { + @Nullable + @Override + protected Map create(ProjectSystemId key) { + final AbstractExternalSystemTaskConfigurationType configurationType = + ExternalSystemUtil.findConfigurationType(key); + if (configurationType == null) return null; + return ContainerUtil.map2Map(RunManager.getInstance(myProject).getConfigurationSettingsList(configurationType), + new Function>() { + @Override + public Pair fun(RunnerAndConfigurationSettings configurationSettings) { + return Pair.create(configurationSettings.getName(), configurationSettings); + } + }); + } + }; + + for (final ExternalProjectsStateProvider.TasksActivation activation : stateProvider.getAllTasksActivation()) { + Set tasks = ContainerUtil.newTroveSet(activation.state.getTasks(before ? Phase.BEFORE_COMPILE : Phase.AFTER_COMPILE)); + if (context.isRebuild()) { + tasks = ContainerUtil.union(tasks, (before ? activation.state.beforeRebuildTask : activation.state.afterRebuildTask)); + } + if (tasks.isEmpty()) continue; + + for (Iterator iterator = tasks.iterator(); iterator.hasNext(); ) { + String task = iterator.next(); + if (task.length() > RUN_CONFIGURATION_TASK_PREFIX.length() && task.startsWith(RUN_CONFIGURATION_TASK_PREFIX)) { + iterator.remove(); + final String configurationName = task.substring(RUN_CONFIGURATION_TASK_PREFIX.length()); + + Map settings = lazyConfigurationsMap.get(activation.systemId); + if (settings == null) continue; + + RunnerAndConfigurationSettings configurationSettings = settings.get(configurationName); + if (configurationSettings == null) continue; + + final RunConfiguration runConfiguration = configurationSettings.getConfiguration(); + if (configurationName.equals(configurationSettings.getName()) && runConfiguration instanceof ExternalSystemRunConfiguration) { + tasksQueue.add(Pair.create(activation.systemId, ((ExternalSystemRunConfiguration)runConfiguration).getSettings())); + } + } + } + + if (tasks.isEmpty()) continue; + + ExternalSystemTaskExecutionSettings executionSettings = new ExternalSystemTaskExecutionSettings(); + executionSettings.setExternalSystemIdString(activation.systemId.toString()); + executionSettings.setExternalProjectPath(activation.projectPath); + executionSettings.getTaskNames().addAll(tasks); + tasksQueue.add(Pair.create(activation.systemId, executionSettings)); + } + + return runTasksQueue(tasksQueue); + } + + private boolean runTasksQueue(final Queue> tasksQueue) { + final Pair pair = tasksQueue.poll(); + if (pair == null) return true; + + final ProjectSystemId systemId = pair.first; + final ExternalSystemTaskExecutionSettings executionSettings = pair.getSecond(); + + final Semaphore targetDone = new Semaphore(); + targetDone.down(); + final Ref result = new Ref(false); + ExternalSystemUtil.runTask(executionSettings, DefaultRunExecutor.EXECUTOR_ID, myProject, systemId, + new TaskCallback() { + @Override + public void onSuccess() { + result.set(runTasksQueue(tasksQueue)); + targetDone.up(); + } + + @Override + public void onFailure() { + targetDone.up(); + } + }, + ProgressExecutionMode.IN_BACKGROUND_ASYNC); + targetDone.waitFor(); + return result.get(); + } + + public void addListener(Listener l) { + myListeners.add(l); + } + + public boolean isTaskOfPhase(@NotNull TaskData taskData, @NotNull Phase phase) { + final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider(); + final TaskActivationState taskActivationState = + stateProvider.getTasksActivation(taskData.getOwner(), taskData.getLinkedExternalProjectPath()); + if (taskActivationState == null) return false; + + return taskActivationState.getTasks(phase).contains(taskData.getName()); + } + + public void addTasks(List tasks, Phase phase) { + if (tasks.isEmpty()) return; + + final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider(); + for (TaskData task : tasks) { + final TaskActivationState taskActivationState = stateProvider.getTasksActivation(task.getOwner(), + task.getLinkedExternalProjectPath()); + taskActivationState.getTasks(phase).add(task.getName()); + } + + fireTasksChanged(); + } + + public void removeTasks(List tasks, Phase phase) { + if (tasks.isEmpty()) return; + + final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider(); + + for (TaskData task : tasks) { + final TaskActivationState taskActivationState = stateProvider.getTasksActivation(task.getOwner(), + task.getLinkedExternalProjectPath()); + taskActivationState.getTasks(phase).remove(task.getName()); + } + + fireTasksChanged(); + } + + public void fireTasksChanged() { + for (Listener each : myListeners) { + each.tasksActivationChanged(); + } + } + + public enum Phase { + AFTER_SYNC("external.system.task.after.sync"), + BEFORE_COMPILE("external.system.task.before.compile"), + AFTER_COMPILE("external.system.task.after.compile"), + BEFORE_REBUILD("external.system.task.before.rebuild"), + AFTER_REBUILD("external.system.task.after.rebuild"); + + public final String myMessageKey; + + Phase(String messageKey) { + myMessageKey = messageKey; + } + } + + public interface Listener { + void tasksActivationChanged(); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java index 7f638bbaa5a1..b8c2a4f963ea 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataManager.java @@ -24,6 +24,8 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NotNullLazyValue; +import com.intellij.util.Consumer; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.Stack; @@ -72,11 +74,6 @@ public class ProjectDataManager { }; } - @Nullable - public List> getDataServices(Key key) { - return myServices.getValue().get(key); - } - @Nullable public ProjectDataService getDataService(Key key) { final List> dataServices = myServices.getValue().get(key); @@ -86,7 +83,7 @@ public class ProjectDataManager { @SuppressWarnings("unchecked") public void importData(@NotNull Collection> nodes, @NotNull Project project, boolean synchronous) { - if(project.isDisposed()) return; + if (project.isDisposed()) return; Map, List>> grouped = ExternalSystemApiUtil.group(nodes); for (Map.Entry, List>> entry : grouped.entrySet()) { @@ -101,9 +98,9 @@ public class ProjectDataManager { @SuppressWarnings("unchecked") public void importData(@NotNull Key key, @NotNull Collection> nodes, @NotNull Project project, boolean synchronous) { - if(project.isDisposed()) return; + if (project.isDisposed()) return; - ensureTheDataIsReadyToUse(nodes); + ensureTheDataIsReadyToUse((Collection)nodes); List> services = myServices.getValue().get(key); if (services == null) { LOG.warn(String.format( @@ -124,22 +121,33 @@ public class ProjectDataManager { importData(children, project, synchronous); } - @SuppressWarnings("unchecked") - private void ensureTheDataIsReadyToUse(@NotNull Collection> nodes) { - Map, List>> servicesByKey = myServices.getValue(); - Stack> toProcess = ContainerUtil.newStack(nodes); - while (!toProcess.isEmpty()) { - DataNode node = toProcess.pop(); - List> services = servicesByKey.get(node.getKey()); - if (services != null) { - for (ProjectDataService service : services) { - node.prepareData(service.getClass().getClassLoader()); + public void ensureTheDataIsReadyToUse(DataNode dataNode) { + final Map, List>> servicesByKey = myServices.getValue(); + ExternalSystemApiUtil.visit(dataNode, new Consumer() { + @Override + public void consume(DataNode dataNode) { + List> services = servicesByKey.get(dataNode.getKey()); + if (services != null) { + try { + dataNode.prepareData(ContainerUtil.map2Array(services, ClassLoader.class, new Function, ClassLoader>() { + @Override + public ClassLoader fun(ProjectDataService service) { + return service.getClass().getClassLoader(); + } + })); + } + catch (Exception e) { + LOG.debug(e); + dataNode.clear(true); + } } } + }); + } - for (DataNode dataNode : node.getChildren()) { - toProcess.push((DataNode)dataNode); - } + private void ensureTheDataIsReadyToUse(@NotNull Collection> nodes) { + for (DataNode node : nodes) { + ensureTheDataIsReadyToUse(node); } } @@ -152,13 +160,21 @@ public class ProjectDataManager { } public void updateExternalProjectData(@NotNull Project project, @NotNull ExternalProjectInfo externalProjectInfo) { - if(!project.isDisposed()) { - ExternalProjectsDataStorage.getInstance(project).add(externalProjectInfo); + if (!project.isDisposed()) { + ExternalProjectsManager.getInstance(project).updateExternalProjectData(externalProjectInfo); } } @Nullable - public ExternalProjectInfo getExternalProjectData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId, @NotNull String externalProjectPath) { + public ExternalProjectInfo getExternalProjectData(@NotNull Project project, + @NotNull ProjectSystemId projectSystemId, + @NotNull String externalProjectPath) { return !project.isDisposed() ? ExternalProjectsDataStorage.getInstance(project).get(projectSystemId, externalProjectPath) : null; } + + @NotNull + public Collection getExternalProjectsData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId) { + return !project.isDisposed() ? + ExternalProjectsDataStorage.getInstance(project).list(projectSystemId) : ContainerUtil.emptyList(); + } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataServiceImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataServiceImpl.java index 34c18a9b3194..43b19c2cabb4 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataServiceImpl.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ProjectDataServiceImpl.java @@ -47,7 +47,7 @@ public class ProjectDataServiceImpl implements ProjectDataService node = toImport.iterator().next(); ProjectData projectData = node.getData(); - + if (!ExternalSystemApiUtil.isNewProjectConstruction() && !ExternalSystemUtil.isOneToOneMapping(project, node)) { return; } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/TaskActivationState.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/TaskActivationState.java new file mode 100644 index 000000000000..2099e404e748 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/TaskActivationState.java @@ -0,0 +1,68 @@ +/* + * 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.openapi.externalSystem.service.project.manage; + +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; +import java.util.TreeSet; + +/** +* @author Vladislav.Soroka +* @since 10/30/2014 +*/ +@Tag("activation") +public class TaskActivationState { + @Tag("after_sync") + @AbstractCollection(surroundWithTag = false, elementTag = "task", elementValueAttribute = "name") + public Set afterSyncTasks = new TreeSet(); + + @Tag("before_compile") + @AbstractCollection(surroundWithTag = false, elementTag = "task", elementValueAttribute = "name") + public Set beforeCompileTasks = new TreeSet(); + + @Tag("after_compile") + @AbstractCollection(surroundWithTag = false, elementTag = "task", elementValueAttribute = "name") + public Set afterCompileTasks = new TreeSet(); + + @Tag("after_rebuild") + @AbstractCollection(surroundWithTag = false, elementTag = "task", elementValueAttribute = "name") + public Set afterRebuildTask = new TreeSet(); + + @Tag("before_rebuild") + @AbstractCollection(surroundWithTag = false, elementTag = "task", elementValueAttribute = "name") + public Set beforeRebuildTask = new TreeSet(); + + @NotNull + public Set getTasks(@NotNull ExternalSystemTaskActivator.Phase phase) { + switch (phase) { + case AFTER_COMPILE: + return afterCompileTasks; + case AFTER_SYNC: + return afterSyncTasks; + case BEFORE_COMPILE: + return beforeCompileTasks; + case AFTER_REBUILD: + return afterRebuildTask; + case BEFORE_REBUILD: + return beforeRebuildTask; + default: + throw new RuntimeException(); + } + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/AbstractToolWindowService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/AbstractToolWindowService.java index b0714303b9f5..40b043651f6c 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/AbstractToolWindowService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/AbstractToolWindowService.java @@ -42,18 +42,13 @@ public abstract class AbstractToolWindowService im ExternalSystemApiUtil.executeOnEdt(false, new Runnable() { @Override public void run() { - ExternalSystemTasksTreeModel model = ExternalSystemUtil.getToolWindowElement(ExternalSystemTasksTreeModel.class, - project, - ExternalSystemDataKeys.ALL_TASKS_MODEL, - toImport.iterator().next().getData().getOwner()); - processData(toImport, project, model); + processData(toImport, project); } }); } protected abstract void processData(@NotNull Collection> nodes, - @NotNull Project project, - @Nullable ExternalSystemTasksTreeModel model); + @NotNull Project project); @Override public void removeData(@NotNull Collection toRemove, @NotNull Project project, boolean synchronous) { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ToolWindowModuleService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ToolWindowModuleService.java index 16ee28307629..0e1a06efce21 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ToolWindowModuleService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ToolWindowModuleService.java @@ -23,7 +23,6 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; -import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemTasksTreeModel; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; @@ -32,7 +31,6 @@ import com.intellij.openapi.project.Project; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.*; @@ -62,8 +60,7 @@ public class ToolWindowModuleService extends AbstractToolWindowService> nodes, - @NotNull Project project, - @Nullable final ExternalSystemTasksTreeModel model) + @NotNull Project project) { if (nodes.isEmpty()) { return; diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ToolWindowTaskService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ToolWindowTaskService.java index a9a665740946..6467d7ed95b4 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ToolWindowTaskService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ToolWindowTaskService.java @@ -24,11 +24,9 @@ import com.intellij.openapi.externalSystem.model.project.ExternalConfigPathAware import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo; import com.intellij.openapi.externalSystem.model.task.TaskData; -import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemTasksTreeModel; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; -import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; import com.intellij.openapi.externalSystem.util.Order; import com.intellij.openapi.project.Project; import com.intellij.util.Function; @@ -74,8 +72,7 @@ public class ToolWindowTaskService extends AbstractToolWindowService { @Override protected void processData(@NotNull Collection> nodes, - @NotNull Project project, - @Nullable final ExternalSystemTasksTreeModel model) + @NotNull Project project) { if (nodes.isEmpty()) { return; @@ -94,9 +91,5 @@ public class ToolWindowTaskService extends AbstractToolWindowService { Map> availableTasks = ContainerUtilRt.newHashMap(settings.getAvailableTasks()); availableTasks.putAll(data); settings.setAvailableTasks(availableTasks); - - if (model != null) { - ExternalSystemUiUtil.apply(settings, model); - } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/AbstractExternalSystemToolWindowFactory.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/AbstractExternalSystemToolWindowFactory.java index a5bf2827ef26..d6ec2d53159e 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/AbstractExternalSystemToolWindowFactory.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/AbstractExternalSystemToolWindowFactory.java @@ -15,45 +15,38 @@ */ package com.intellij.openapi.externalSystem.service.task.ui; -import com.intellij.notification.NotificationGroup; -import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; +import com.intellij.openapi.externalSystem.view.ExternalProjectsView; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowFactory; +import com.intellij.openapi.wm.ex.ToolWindowEx; import com.intellij.ui.content.ContentManager; import com.intellij.ui.content.impl.ContentImpl; import org.jetbrains.annotations.NotNull; -import java.util.Locale; - /** * @author Denis Zhdanov * @since 5/13/13 4:15 PM */ public abstract class AbstractExternalSystemToolWindowFactory implements ToolWindowFactory, DumbAware { - @NotNull private final ProjectSystemId myExternalSystemId; - @NotNull private final NotificationGroup myNotificationGroup; + @NotNull private final ProjectSystemId myExternalSystemId; protected AbstractExternalSystemToolWindowFactory(@NotNull ProjectSystemId id) { myExternalSystemId = id; - myNotificationGroup = NotificationGroup.toolWindowGroup("notification.group.id." + id.toString().toLowerCase(Locale.ENGLISH), - myExternalSystemId.getReadableName()); } @Override public void createToolWindowContent(@NotNull final Project project, @NotNull final ToolWindow toolWindow) { toolWindow.setTitle(myExternalSystemId.getReadableName()); ContentManager contentManager = toolWindow.getContentManager(); - String tasksTitle = ExternalSystemBundle.message("tool.window.title.tasks"); - ExternalSystemManager manager = ExternalSystemApiUtil.getManager(myExternalSystemId); - assert manager != null; - ExternalSystemTasksPanel panel = new ExternalSystemTasksPanel(project, myExternalSystemId, myNotificationGroup); - ContentImpl tasksContent = new ContentImpl(panel, tasksTitle, true); + final ExternalProjectsView projectsView = new ExternalProjectsView(project, (ToolWindowEx)toolWindow, myExternalSystemId); + ExternalProjectsManager.getInstance(project).registerView(projectsView); + ContentImpl tasksContent = new ContentImpl(projectsView, ExternalSystemBundle.message("tool.window.title.projects"), true); contentManager.addContent(tasksContent); } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTaskListModel.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTaskListModel.java deleted file mode 100644 index 16ba6048fc16..000000000000 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTaskListModel.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2000-2013 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.openapi.externalSystem.service.task.ui; - -import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo; -import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; -import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; -import com.intellij.openapi.project.Project; -import com.intellij.util.containers.ContainerUtilRt; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.util.List; - -/** - * @author Denis Zhdanov - * @since 6/7/13 3:28 PM - */ -public class ExternalSystemRecentTaskListModel extends DefaultListModel { - - @NotNull private final ProjectSystemId myExternalSystemId; - @NotNull private final Project myProject; - - public ExternalSystemRecentTaskListModel(@NotNull ProjectSystemId externalSystemId, @NotNull Project project) { - myExternalSystemId = externalSystemId; - myProject = project; - ensureSize(ExternalSystemConstants.RECENT_TASKS_NUMBER); - } - - @SuppressWarnings("unchecked") - public void setTasks(@NotNull List tasks) { - clear(); - List tasksToUse = ContainerUtilRt.newArrayList(tasks); - for (ExternalTaskExecutionInfo task : tasksToUse) { - addElement(task); - } - } - - @SuppressWarnings("unchecked") - public void setFirst(@NotNull ExternalTaskExecutionInfo task) { - insertElementAt(task, 0); - for (int i = 1; i < size(); i++) { - if (task.equals(getElementAt(i))) { - remove(i); - break; - } - } - ensureSize(ExternalSystemConstants.RECENT_TASKS_NUMBER); - } - - @NotNull - public List getTasks() { - List result = ContainerUtilRt.newArrayList(); - for (int i = 0; i < size(); i++) { - Object e = getElementAt(i); - if (e instanceof ExternalTaskExecutionInfo) { - result.add((ExternalTaskExecutionInfo)e); - } - } - return result; - } - - @SuppressWarnings("unchecked") - public void ensureSize(int elementsNumber) { - int toAdd = elementsNumber - size(); - if (toAdd == 0) { - return; - } - if(toAdd < 0) { - removeRange(elementsNumber, size() - 1); - } - while (--toAdd >= 0) { - addElement(new MyEmptyDescriptor()); - } - } - - /** - * Asks current model to remove all 'recent task info' entries which point to tasks from external project with the given path. - * - * @param externalProjectPath target external project's path - */ - public void forgetTasksFrom(@NotNull String externalProjectPath) { - for (int i = size() - 1; i >= 0; i--) { - Object e = getElementAt(i); - if (e instanceof ExternalTaskExecutionInfo) { - String path = ((ExternalTaskExecutionInfo)e).getSettings().getExternalProjectPath(); - if (externalProjectPath.equals(path) - || externalProjectPath.equals(ExternalSystemApiUtil.getRootProjectPath(path, myExternalSystemId, myProject))) - { - removeElementAt(i); - } - } - } - ensureSize(ExternalSystemConstants.RECENT_TASKS_NUMBER); - } - - static class MyEmptyDescriptor { - } -} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTasksList.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTasksList.java deleted file mode 100644 index 4ef7b851d573..000000000000 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTasksList.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2000-2013 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.openapi.externalSystem.service.task.ui; - -import com.intellij.execution.Executor; -import com.intellij.execution.ExecutorRegistry; -import com.intellij.execution.RunManager; -import com.intellij.execution.configurations.ConfigurationType; -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.openapi.externalSystem.ExternalSystemManager; -import com.intellij.openapi.externalSystem.ExternalSystemUiAware; -import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo; -import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType; -import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; -import com.intellij.openapi.externalSystem.service.ui.DefaultExternalSystemUiAware; -import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; -import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; -import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.components.JBList; -import com.intellij.util.Producer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; -import java.util.List; - -/** - * @author Denis Zhdanov - * @since 6/7/13 2:40 PM - */ -public class ExternalSystemRecentTasksList extends JBList implements Producer { - - @NotNull private static final JLabel EMPTY_RENDERER = new JLabel(" "); - - public ExternalSystemRecentTasksList(@NotNull ExternalSystemRecentTaskListModel model, - @NotNull final ProjectSystemId externalSystemId, - @NotNull final Project project) - { - super(model); - setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - ExternalSystemManager manager = ExternalSystemApiUtil.getManager(externalSystemId); - Icon icon = null; - if (manager instanceof ExternalSystemUiAware) { - icon = ((ExternalSystemUiAware)manager).getTaskIcon(); - } - if (icon == null) { - icon = DefaultExternalSystemUiAware.INSTANCE.getTaskIcon(); - } - setCellRenderer(new MyRenderer(project, icon, ExternalSystemUtil.findConfigurationType(externalSystemId))); - setVisibleRowCount(ExternalSystemConstants.RECENT_TASKS_NUMBER); - - registerKeyboardAction(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ExternalTaskExecutionInfo task = produce(); - if (task == null) { - return; - } - ExternalSystemUtil.runTask(task.getSettings(), task.getExecutorId(), project, externalSystemId); - } - }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); - - addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() < 2) { - return; - } - - ExternalTaskExecutionInfo task = produce(); - if (task == null) { - return; - } - - ExternalSystemUtil.runTask(task.getSettings(), task.getExecutorId(), project, externalSystemId); - } - }); - } - - @Override - public ExternalSystemRecentTaskListModel getModel() { - return (ExternalSystemRecentTaskListModel)super.getModel(); - } - - public void setFirst(@NotNull ExternalTaskExecutionInfo task) { - ExternalTaskExecutionInfo selected = produce(); - ExternalSystemRecentTaskListModel model = getModel(); - model.setFirst(task); - clearSelection(); - if (selected == null) { - return; - } - for (int i = 0; i < model.size(); i++) { - //noinspection SuspiciousMethodCalls - if (selected.equals(model.getElementAt(i))) { - addSelectionInterval(i, i); - return; - } - } - } - - @Nullable - @Override - public ExternalTaskExecutionInfo produce() { - int[] indices = getSelectedIndices(); - if (indices == null || indices.length != 1) { - return null; - } - Object e = getModel().getElementAt(indices[0]); - return e instanceof ExternalTaskExecutionInfo ? (ExternalTaskExecutionInfo)e : null; - } - - private static class MyRenderer extends DefaultListCellRenderer { - - @NotNull private final Icon myGenericTaskIcon; - @NotNull private final Project myProject; - @Nullable private ConfigurationType myConfigurationType; - - MyRenderer(@NotNull Project project, @NotNull Icon genericTaskIcon, @Nullable ConfigurationType configurationType) { - myProject = project; - myGenericTaskIcon = genericTaskIcon; - myConfigurationType = configurationType; - } - - @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - Component renderer = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - if (value instanceof ExternalSystemRecentTaskListModel.MyEmptyDescriptor) { - return EMPTY_RENDERER; - } - else if (value instanceof ExternalTaskExecutionInfo) { - ExternalTaskExecutionInfo taskInfo = (ExternalTaskExecutionInfo)value; - String text = null; - if (myConfigurationType != null) { - List configurations = RunManager.getInstance(myProject).getConfigurationsList(myConfigurationType); - for (RunConfiguration configuration : configurations) { - if (!(configuration instanceof ExternalSystemRunConfiguration)) { - continue; - } - ExternalSystemRunConfiguration c = (ExternalSystemRunConfiguration)configuration; - if (c.getSettings().equals(taskInfo.getSettings())) { - text = c.getName(); - } - } - } - if (StringUtil.isEmpty(text)) { - text = AbstractExternalSystemTaskConfigurationType.generateName(myProject, taskInfo.getSettings()); - } - - setText(text); - Icon icon = null; - String executorId = taskInfo.getExecutorId(); - if (!StringUtil.isEmpty(executorId)) { - Executor executor = ExecutorRegistry.getInstance().getExecutorById(executorId); - if (executor != null) { - icon = executor.getIcon(); - } - } - - if (icon == null) { - icon = myGenericTaskIcon; - } - setIcon(icon); - } - - return renderer; - } - - @Override - public void setIcon(Icon icon) { - if (icon != null) { - // Don't allow to reset icon. - super.setIcon(icon); - } - } - } -} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemTasksPanel.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemTasksPanel.java deleted file mode 100644 index 2530fc98f8c4..000000000000 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemTasksPanel.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2000-2013 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.openapi.externalSystem.service.task.ui; - -import com.intellij.execution.Location; -import com.intellij.execution.executors.DefaultRunExecutor; -import com.intellij.ide.ui.customization.CustomizationUtil; -import com.intellij.notification.NotificationGroup; -import com.intellij.openapi.actionSystem.ActionGroup; -import com.intellij.openapi.actionSystem.ActionManager; -import com.intellij.openapi.actionSystem.ActionToolbar; -import com.intellij.openapi.actionSystem.DataProvider; -import com.intellij.openapi.externalSystem.ExternalSystemManager; -import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; -import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo; -import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; -import com.intellij.openapi.externalSystem.service.execution.ExternalSystemTaskLocation; -import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; -import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; -import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; -import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; -import com.intellij.openapi.fileTypes.PlainTextFileType; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.SimpleToolWindowPanel; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileFactory; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.components.JBScrollPane; -import com.intellij.util.Producer; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -import static com.intellij.openapi.externalSystem.util.ExternalSystemConstants.*; - -/** - * @author Denis Zhdanov - * @since 5/12/13 10:18 PM - */ -public class ExternalSystemTasksPanel extends SimpleToolWindowPanel implements DataProvider { - - @NotNull private final ExternalSystemRecentTasksList myRecentTasksList; - @NotNull private final ExternalSystemTasksTreeModel myAllTasksModel; - @NotNull private final ExternalSystemTasksTree myAllTasksTree; - @NotNull private final ProjectSystemId myExternalSystemId; - @NotNull private final NotificationGroup myNotificationGroup; - @NotNull private final Project myProject; - - @Nullable private Producer mySelectedTaskProvider; - - public ExternalSystemTasksPanel(@NotNull Project project, - @NotNull ProjectSystemId externalSystemId, - @NotNull NotificationGroup notificationGroup) - { - super(true); - myExternalSystemId = externalSystemId; - myNotificationGroup = notificationGroup; - myProject = project; - - ExternalSystemManager manager = ExternalSystemApiUtil.getManager(externalSystemId); - assert manager != null; - AbstractExternalSystemLocalSettings settings = manager.getLocalSettingsProvider().fun(project); - - ExternalSystemRecentTaskListModel recentTasksModel = new ExternalSystemRecentTaskListModel(externalSystemId, project); - recentTasksModel.setTasks(settings.getRecentTasks()); - myRecentTasksList = new ExternalSystemRecentTasksList(recentTasksModel, externalSystemId, project) { - @Override - protected void processMouseEvent(MouseEvent e) { - if (e.getClickCount() > 0) { - mySelectedTaskProvider = myRecentTasksList; - myAllTasksTree.getSelectionModel().clearSelection(); - } - super.processMouseEvent(e); - } - }; - - myAllTasksModel = new ExternalSystemTasksTreeModel(externalSystemId); - myAllTasksTree = new ExternalSystemTasksTree(myAllTasksModel, settings.getExpandStates(), project, externalSystemId) { - @Override - protected void processMouseEvent(MouseEvent e) { - if (e.getClickCount() > 0) { - mySelectedTaskProvider = myAllTasksTree; - myRecentTasksList.getSelectionModel().clearSelection(); - } - super.processMouseEvent(e); - } - }; - final String actionIdToUseForDoubleClick = DefaultRunExecutor.getRunExecutorInstance().getContextActionId(); - myAllTasksTree.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() >= 2 && !e.isPopupTrigger()) { - ExternalSystemUiUtil.executeAction(actionIdToUseForDoubleClick, e); - } - } - }); - ExternalSystemUiUtil.apply(settings, myAllTasksModel); - CustomizationUtil.installPopupHandler(myAllTasksTree, TREE_ACTIONS_GROUP_ID, TREE_CONTEXT_MENU_PLACE); - - ActionManager actionManager = ActionManager.getInstance(); - ActionGroup group = (ActionGroup)actionManager.getAction(TOOL_WINDOW_TOOLBAR_ACTIONS_GROUP_ID); - ActionToolbar toolbar = actionManager.createActionToolbar(TOOL_WINDOW_PLACE, group, true); - toolbar.setTargetComponent(this); - setToolbar(toolbar.getComponent()); - - JPanel content = new JPanel(new GridBagLayout()); - content.setOpaque(true); - content.setBackground(UIUtil.getListBackground()); - JComponent recentTasksWithTitle = wrap(myRecentTasksList, ExternalSystemBundle.message("tasks.recent.title")); - content.add(recentTasksWithTitle, ExternalSystemUiUtil.getFillLineConstraints(0)); - JBScrollPane scrollPane = new JBScrollPane(myAllTasksTree); - scrollPane.setBorder(null); - JComponent allTasksWithTitle = wrap(scrollPane, ExternalSystemBundle.message("tasks.all.title")); - content.add(allTasksWithTitle, ExternalSystemUiUtil.getFillLineConstraints(0).weighty(1).fillCell()); - setContent(content); - } - - private static JComponent wrap(@NotNull JComponent content, @NotNull String title) { - JPanel result = new JPanel(new BorderLayout()); - result.setOpaque(false); - result.setBorder(IdeBorderFactory.createTitledBorder(title, false)); - result.add(content, BorderLayout.CENTER); - return result; - } - - @Nullable - @Override - public Object getData(@NonNls String dataId) { - if (ExternalSystemDataKeys.RECENT_TASKS_LIST.is(dataId)) { - return myRecentTasksList; - } - else if (ExternalSystemDataKeys.ALL_TASKS_MODEL.is(dataId)) { - return myAllTasksModel; - } - else if (ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.is(dataId)) { - return myExternalSystemId; - } - else if (ExternalSystemDataKeys.NOTIFICATION_GROUP.is(dataId)) { - return myNotificationGroup; - } - else if (ExternalSystemDataKeys.SELECTED_TASK.is(dataId)) { - return mySelectedTaskProvider == null ? null : mySelectedTaskProvider.produce(); - } - else if (ExternalSystemDataKeys.SELECTED_PROJECT.is(dataId)) { - if (mySelectedTaskProvider != myAllTasksTree) { - return null; - } - else { - Object component = myAllTasksTree.getLastSelectedPathComponent(); - if (component instanceof ExternalSystemNode) { - Object element = ((ExternalSystemNode)component).getDescriptor().getElement(); - return element instanceof ExternalProjectPojo ? element : null; - } - } - } - else if (Location.DATA_KEY.is(dataId)) { - Location location = buildLocation(); - return location == null ? super.getData(dataId) : location; - } - return null; - } - - @Nullable - private Location buildLocation() { - if (mySelectedTaskProvider == null) { - return null; - } - ExternalTaskExecutionInfo task = mySelectedTaskProvider.produce(); - if (task == null) { - return null; - } - - String projectPath = task.getSettings().getExternalProjectPath(); - String name = myExternalSystemId.getReadableName() + projectPath + StringUtil.join(task.getSettings().getTaskNames(), " "); - // We create a dummy text file instead of re-using external system file in order to avoid clashing with other configuration producers. - // For example gradle files are enhanced groovy scripts but we don't want to run them via regular IJ groovy script runners. - // Gradle tooling api should be used for running gradle tasks instead. IJ execution sub-system operates on Location objects - // which encapsulate PsiElement and groovy runners are automatically applied if that PsiElement IS-A GroovyFile. - PsiFile file = PsiFileFactory.getInstance(myProject).createFileFromText(name, PlainTextFileType.INSTANCE, "nichts"); - - return new ExternalSystemTaskLocation(myProject, file, task); - } -} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUiUtil.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUiUtil.java index d987be2e9fe4..3a4cf7146e2d 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUiUtil.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUiUtil.java @@ -105,28 +105,6 @@ public class ExternalSystemUiUtil { component.add(Box.createVerticalGlue(), new GridBag().weightx(1).weighty(1).fillCell().coverLine()); } - /** - * Applies data from the given settings object to the given model. - * - * @param settings target settings to use - * @param model UI model to be synced with the given settings - */ - public static void apply(@NotNull final AbstractExternalSystemLocalSettings settings, @NotNull final ExternalSystemTasksTreeModel model) { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - Map> projects = settings.getAvailableProjects(); - for (Map.Entry> entry : projects.entrySet()) { - model.ensureSubProjectsStructure(entry.getKey(), entry.getValue()); - } - Map> tasks = settings.getAvailableTasks(); - for (Map.Entry> entry : tasks.entrySet()) { - model.ensureTasks(entry.getKey(), entry.getValue()); - } - } - }); - } - public static void showUi(@NotNull Object o, boolean show) { for (Class clazz = o.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) { for (Field field : clazz.getDeclaredFields()) { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java index 62bf8a5dcad7..8f7384efd814 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/util/ExternalSystemUtil.java @@ -39,7 +39,6 @@ import com.intellij.openapi.externalSystem.importing.ImportSpec; import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder; import com.intellij.openapi.externalSystem.model.*; import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; -import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo; import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; @@ -55,14 +54,14 @@ import com.intellij.openapi.externalSystem.service.notification.NotificationSour import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; import com.intellij.openapi.externalSystem.service.project.PlatformFacade; import com.intellij.openapi.externalSystem.service.project.ProjectStructureHelper; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; import com.intellij.openapi.externalSystem.service.project.manage.ModuleDataService; import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; import com.intellij.openapi.externalSystem.service.settings.ExternalSystemConfigLocator; -import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemRecentTasksList; -import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; import com.intellij.openapi.externalSystem.task.TaskCallback; +import com.intellij.openapi.externalSystem.view.ExternalProjectsView; import com.intellij.openapi.module.Module; import com.intellij.openapi.progress.PerformInBackgroundOption; import com.intellij.openapi.progress.ProgressIndicator; @@ -142,7 +141,6 @@ public class ExternalSystemUtil { } } - @SuppressWarnings("unchecked") @Nullable public static T getToolWindowElement(@NotNull Class clazz, @NotNull Project project, @@ -170,6 +168,7 @@ public class ExternalSystemUtil { if (component instanceof DataProvider) { final Object data = ((DataProvider)component).getData(key.getName()); if (data != null && clazz.isInstance(data)) { + //noinspection unchecked return (T)data; } } @@ -300,6 +299,13 @@ public class ExternalSystemUtil { return timeStamp; } + public static void ruleOrphanModules(@NotNull final List orphanModules, + @NotNull final Project project, + @NotNull final ProjectSystemId externalSystemId) { + //noinspection unchecked + ruleOrphanModules(orphanModules, project, externalSystemId, Consumer.EMPTY_CONSUMER); + } + /** * There is a possible case that an external module has been un-linked from ide project. There are two ways to process * ide modules which correspond to that external project: @@ -317,7 +323,8 @@ public class ExternalSystemUtil { */ public static void ruleOrphanModules(@NotNull final List orphanModules, @NotNull final Project project, - @NotNull final ProjectSystemId externalSystemId) + @NotNull final ProjectSystemId externalSystemId, + @NotNull final Consumer result) { UIUtil.invokeLaterIfNeeded(new Runnable() { @Override @@ -356,6 +363,7 @@ public class ExternalSystemUtil { } }; boolean ok = dialog.showAndGet(); + result.consume(ok); if (!ok) { return; } @@ -700,6 +708,16 @@ public class ExternalSystemUtil { ProgramRunner runner = RunnerRegistry.getInstance().findRunnerById(runnerId); if (runner == null) return null; + RunnerAndConfigurationSettings settings = createExternalSystemRunnerAndConfigurationSettings(taskSettings, project, externalSystemId); + if (settings == null) return null; + + return Pair.create(runner, new ExecutionEnvironment(executor, runner, settings, project)); + } + + @Nullable + public static RunnerAndConfigurationSettings createExternalSystemRunnerAndConfigurationSettings(@NotNull ExternalSystemTaskExecutionSettings taskSettings, + @NotNull Project project, + @NotNull ProjectSystemId externalSystemId) { AbstractExternalSystemTaskConfigurationType configurationType = findConfigurationType(externalSystemId); if (configurationType == null) return null; @@ -713,7 +731,7 @@ public class ExternalSystemUtil { runConfiguration.getSettings().setScriptParameters(taskSettings.getScriptParameters()); runConfiguration.getSettings().setExecutionName(taskSettings.getExecutionName()); - return Pair.create(runner, new ExecutionEnvironment(executor, runner, settings, project)); + return settings; } @Nullable @@ -729,32 +747,6 @@ public class ExternalSystemUtil { return null; } - /** - * Is expected to be called when given task info is about to be executed. - *

- * Basically, this method updates recent tasks list at the corresponding external system tool window and - * persists new recent tasks state. - * - * @param taskInfo task which is about to be executed - * @param project target project - */ - public static void updateRecentTasks(@NotNull ExternalTaskExecutionInfo taskInfo, @NotNull Project project) { - ProjectSystemId externalSystemId = taskInfo.getSettings().getExternalSystemId(); - ExternalSystemRecentTasksList recentTasksList = getToolWindowElement(ExternalSystemRecentTasksList.class, - project, - ExternalSystemDataKeys.RECENT_TASKS_LIST, - externalSystemId); - if (recentTasksList == null) { - return; - } - recentTasksList.setFirst(taskInfo); - - ExternalSystemManager manager = ExternalSystemApiUtil.getManager(externalSystemId); - assert manager != null; - AbstractExternalSystemLocalSettings settings = manager.getLocalSettingsProvider().fun(project); - settings.setRecentTasks(recentTasksList.getModel().getTasks()); - } - @Nullable public static String getRunnerId(@NotNull String executorId) { return RUNNER_IDS.get(executorId); @@ -904,6 +896,26 @@ public class ExternalSystemUtil { return file[0]; } + public static void scheduleExternalViewStructureUpdate(final Project project, final ProjectSystemId systemId) { + ExternalProjectsView externalProjectsView = ExternalProjectsManager.getInstance(project).getExternalProjectsView(systemId); + if (externalProjectsView != null) { + externalProjectsView.scheduleStructureUpdate(); + } + } + + @Nullable + public static ExternalProjectInfo getExternalProjectInfo(@NotNull final Project project, + @NotNull final ProjectSystemId projectSystemId, + @NotNull final String externalProjectPath) { + final ExternalProjectSettings linkedProjectSettings = + ExternalSystemApiUtil.getSettings(project, projectSystemId).getLinkedProjectSettings(externalProjectPath); + if (linkedProjectSettings == null) return null; + + return ProjectDataManager.getInstance().getExternalProjectData( + project, projectSystemId, linkedProjectSettings.getExternalProjectPath()); + } + + private interface TaskUnderProgress { void execute(@NotNull ProgressIndicator indicator); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsStructure.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsStructure.java new file mode 100644 index 000000000000..0eb2d5e81614 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsStructure.java @@ -0,0 +1,253 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.ui.treeStructure.SimpleNode; +import com.intellij.ui.treeStructure.SimpleTree; +import com.intellij.ui.treeStructure.SimpleTreeBuilder; +import com.intellij.ui.treeStructure.SimpleTreeStructure; +import com.intellij.util.Consumer; +import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashMap; +import org.jetbrains.annotations.NotNull; + +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 9/22/2014 + */ +public class ExternalProjectsStructure extends SimpleTreeStructure { + private final Project myProject; + private final ExternalProjectsView myExternalProjectsView; + private final SimpleTreeBuilder myTreeBuilder; + private final RootNode myRoot; + + private final Map myNodeMapping = new THashMap(); + + public ExternalProjectsStructure(Project project, ExternalProjectsView externalProjectsView, SimpleTree tree) { + myProject = project; + myExternalProjectsView = externalProjectsView; + + configureTree(tree); + + myTreeBuilder = new SimpleTreeBuilder(tree, (DefaultTreeModel)tree.getModel(), this, null); + Disposer.register(myProject, myTreeBuilder); + + myRoot = new RootNode(); + myTreeBuilder.initRoot(); + myTreeBuilder.expand(myRoot, null); + } + + public Project getProject() { + return myProject; + } + + void updateFrom(SimpleNode node) { + myTreeBuilder.addSubtreeToUpdateByElement(node); + } + + void updateUpTo(SimpleNode node) { + SimpleNode each = node; + while (each != null) { + updateFrom(each); + each = each.getParent(); + } + } + + @Override + public Object getRootElement() { + return myRoot; + } + + private static void configureTree(final SimpleTree tree) { + tree.setRootVisible(false); + tree.setShowsRootHandles(true); + } + + public void updateProjects(Collection> toImport) { + for (DataNode each : toImport) { + final ProjectData projectData = each.getData(); + ExternalSystemNode projectNode = findNodeFor(projectData.getLinkedExternalProjectPath()); + + if (projectNode instanceof ProjectNode) { + doMergeChildrenChanges(projectNode, each, new ProjectNode(myExternalProjectsView, each)); + } + else { + ExternalSystemNode node = myNodeMapping.remove(projectData.getLinkedExternalProjectPath()); + if (node != null) { + SimpleNode parent = node.getParent(); + if (parent instanceof ExternalSystemNode) { + ((ExternalSystemNode)parent).remove(projectNode); + } + } + + projectNode = new ProjectNode(myExternalProjectsView, each); + myNodeMapping.put(projectData.getLinkedExternalProjectPath(), projectNode); + } + if (toImport.size() == 0) { + myTreeBuilder.expand(projectNode, null); + } + doUpdateProject((ProjectNode)projectNode); + } + } + + private void doMergeChildrenChanges(ExternalSystemNode currentNode, DataNode newDataNode, ExternalSystemNode newNode) { + final ExternalSystemNode[] cached = currentNode.getCached(); + if (cached != null) { + Map oldDataMap = ContainerUtil.newLinkedHashMap(); + for (ExternalSystemNode node : cached) { + Object key = node.getData() != null ? node.getData() : node.getName(); + oldDataMap.put(key, node); + } + + Map newDataMap = ContainerUtil.newLinkedHashMap(); + Map unchangedNewDataMap = ContainerUtil.newLinkedHashMap(); + for (ExternalSystemNode node : newNode.getChildren()) { + Object key = node.getData() != null ? node.getData() : node.getName(); + if (oldDataMap.remove(key) == null) { + newDataMap.put(key, node); + } + else { + unchangedNewDataMap.put(key, node); + } + } + + currentNode.removeAll(oldDataMap.values()); + + for (ExternalSystemNode node : currentNode.getChildren()) { + Object key = node.getData() != null ? node.getData() : node.getName(); + final ExternalSystemNode unchangedNewNode = unchangedNewDataMap.get(key); + if (unchangedNewNode != null) { + doMergeChildrenChanges(node, unchangedNewNode.myDataNode, unchangedNewNode); + } + } + + updateFrom(currentNode); + currentNode.addAll(newDataMap.values()); + } + //noinspection unchecked + currentNode.setDataNode(newDataNode); + } + + private void doUpdateProject(ProjectNode node) { + ExternalSystemNode newParentNode = myRoot; + node.updateProject(); + reconnectNode(node, newParentNode); + } + + private static void reconnectNode(ProjectNode node, ExternalSystemNode newParentNode) { + ExternalSystemNode oldParentNode = node.getGroup(); + if (oldParentNode == null || !oldParentNode.equals(newParentNode)) { + if (oldParentNode != null) { + oldParentNode.remove(node); + } + newParentNode.add(node); + } + } + + @SuppressWarnings("SuspiciousMethodCalls") + private ExternalSystemNode findNodeFor(String projectPath) { + return myNodeMapping.get(projectPath); + } + + public void updateNodes(@NotNull Class nodeClass) { + for (T node : getNodes(nodeClass)) { + updateFrom(node); + } + } + + public void visitNodes(@NotNull Class nodeClass, @NotNull Consumer consumer) { + for (T node : getNodes(nodeClass)) { + consumer.consume(node); + } + } + + public class RootNode extends ExternalSystemNode { + public RootNode() { + super(myExternalProjectsView, null, null); + } + + @Override + public boolean isVisible() { + return true; + } + } + + public enum ErrorLevel { + NONE, ERROR + } + + enum DisplayKind { + ALWAYS, NEVER, NORMAL + } + + @NotNull + public List getNodes(@NotNull Class nodeClass) { + return doGetNodes(nodeClass, myRoot.getChildren(), new SmartList()); + } + + @NotNull + private static List doGetNodes(@NotNull Class nodeClass, + SimpleNode[] nodes, + @NotNull List result) { + if (nodes == null) return result; + + for (SimpleNode node : nodes) { + if (nodeClass.isInstance(node)) { + //noinspection unchecked + result.add((T)node); + } + doGetNodes(nodeClass, node.getChildren(), result); + } + return result; + } + + @NotNull + public List getSelectedNodes(SimpleTree tree, Class nodeClass) { + final List filtered = new ArrayList(); + for (SimpleNode node : getSelectedNodes(tree)) { + if ((nodeClass != null) && (!nodeClass.isInstance(node))) { + filtered.clear(); + break; + } + //noinspection unchecked + filtered.add((T)node); + } + return filtered; + } + + private static List getSelectedNodes(SimpleTree tree) { + List nodes = new ArrayList(); + TreePath[] treePaths = tree.getSelectionPaths(); + if (treePaths != null) { + for (TreePath treePath : treePaths) { + nodes.add(tree.getNodeFor(treePath)); + } + } + return nodes; + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsView.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsView.java new file mode 100644 index 000000000000..5bc77ebb52fb --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsView.java @@ -0,0 +1,611 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.execution.*; +import com.intellij.icons.AllIcons; +import com.intellij.ide.util.treeView.TreeState; +import com.intellij.lang.Language; +import com.intellij.notification.NotificationGroup; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.ExternalSystemUiAware; +import com.intellij.openapi.externalSystem.action.ExternalSystemViewGearAction; +import com.intellij.openapi.externalSystem.model.*; +import com.intellij.openapi.externalSystem.model.Key; +import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo; +import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo; +import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemTaskLocation; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemShortcutsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings; +import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListener; +import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListenerAdapter; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; +import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; +import com.intellij.openapi.fileTypes.PlainTextFileType; +import com.intellij.openapi.module.ModuleTypeId; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.SimpleToolWindowPanel; +import com.intellij.openapi.util.*; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ex.ToolWindowEx; +import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter; +import com.intellij.openapi.wm.ex.ToolWindowManagerEx; +import com.intellij.openapi.wm.impl.ToolWindowImpl; +import com.intellij.pom.Navigatable; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiFileFactory; +import com.intellij.psi.PsiManager; +import com.intellij.psi.impl.source.DummyHolderFactory; +import com.intellij.ui.PopupHandler; +import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.treeStructure.SimpleTree; +import com.intellij.util.Consumer; +import com.intellij.util.DisposeAwareRunnable; +import com.intellij.util.Function; +import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Convertor; +import com.intellij.util.containers.MultiMap; +import com.intellij.util.messages.MessageBusConnection; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.tree.TreeSelectionModel; +import java.awt.*; +import java.net.URL; +import java.util.*; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 9/19/2014 + */ +public class ExternalProjectsView extends SimpleToolWindowPanel implements DataProvider { + public static final Logger LOG = Logger.getInstance(ExternalProjectsView.class); + + @NotNull + private final Project myProject; + @NotNull + private final ExternalProjectsManager myProjectsManager; + @NotNull + private final ToolWindowEx myToolWindow; + @NotNull + private final ProjectSystemId myExternalSystemId; + @NotNull + private final ExternalSystemUiAware myUiAware; + + @Nullable + private ExternalProjectsStructure myStructure; + private SimpleTree myTree; + @NotNull + private final NotificationGroup myNotificationGroup; + + private ExternalProjectsViewState myState = new ExternalProjectsViewState(); + + public ExternalProjectsView(@NotNull Project project, @NotNull ToolWindowEx toolWindow, @NotNull ProjectSystemId externalSystemId) { + super(true, true); + myProject = project; + myToolWindow = toolWindow; + myExternalSystemId = externalSystemId; + myUiAware = ExternalSystemUiUtil.getUiAware(externalSystemId); + myProjectsManager = ExternalProjectsManager.getInstance(myProject); + + String toolWindowId = + toolWindow instanceof ToolWindowImpl ? ((ToolWindowImpl)toolWindow).getId() : myExternalSystemId.getReadableName(); + + myNotificationGroup = NotificationGroup.toolWindowGroup( + "notification.group.id." + externalSystemId.getId().toLowerCase(Locale.ENGLISH), toolWindowId); + } + + @Nullable + @Override + public Object getData(@NonNls String dataId) { + if (ExternalSystemDataKeys.VIEW.is(dataId)) return this; + + if (PlatformDataKeys.HELP_ID.is(dataId)) return "reference.toolwindows.gradle"; + if (CommonDataKeys.PROJECT.is(dataId)) return myProject; + if (CommonDataKeys.VIRTUAL_FILE.is(dataId)) return extractVirtualFile(); + if (CommonDataKeys.VIRTUAL_FILE_ARRAY.is(dataId)) return extractVirtualFiles(); + if (Location.DATA_KEY.is(dataId)) { + return extractLocation(); + } + if (CommonDataKeys.NAVIGATABLE_ARRAY.is(dataId)) return extractNavigatables(); + + if (ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.is(dataId)) return myExternalSystemId; + if (ExternalSystemDataKeys.UI_AWARE.is(dataId)) return myUiAware; + if (ExternalSystemDataKeys.SELECTED_PROJECT_NODE.is(dataId)) return getSelectedProjectNode(); + if (ExternalSystemDataKeys.SELECTED_NODES.is(dataId)) return getSelectedNodes(ExternalSystemNode.class); + if (ExternalSystemDataKeys.PROJECTS_TREE.is(dataId)) return myTree; + if (ExternalSystemDataKeys.NOTIFICATION_GROUP.is(dataId)) return myNotificationGroup; + + return super.getData(dataId); + } + + @NotNull + public Project getProject() { + return myProject; + } + + @NotNull + public ExternalSystemUiAware getUiAware() { + return myUiAware; + } + + public ExternalSystemShortcutsManager getShortcutsManager() { + return myProjectsManager.getShortcutsManager(); + } + + public ExternalSystemTaskActivator getTaskActivator() { + return myProjectsManager.getTaskActivator(); + } + + @NotNull + public ProjectSystemId getSystemId() { + return myExternalSystemId; + } + + @NotNull + public NotificationGroup getNotificationGroup() { + return myNotificationGroup; + } + + public void init() { + initTree(); + + final ToolWindowManagerEx manager = ToolWindowManagerEx.getInstanceEx(myProject); + + final ToolWindowManagerAdapter listener = new ToolWindowManagerAdapter() { + boolean wasVisible = false; + + @Override + public void stateChanged() { + if (myToolWindow.isDisposed()) return; + boolean visible = myToolWindow.isVisible(); + if (!visible || wasVisible) { + wasVisible = visible; + return; + } + scheduleStructureUpdate(); + wasVisible = true; + } + }; + manager.addToolWindowManagerListener(listener); + + Disposer.register(myProject, new Disposable() { + public void dispose() { + manager.removeToolWindowManagerListener(listener); + } + }); + + getShortcutsManager().addListener(new ExternalSystemShortcutsManager.Listener() { + @Override + public void shortcutsUpdated() { + scheduleTasksUpdate(); + + scheduleStructureRequest(new Runnable() { + public void run() { + assert myStructure != null; + myStructure.updateNodes(RunConfigurationNode.class); + } + }); + } + }); + + getTaskActivator().addListener(new ExternalSystemTaskActivator.Listener() { + @Override + public void tasksActivationChanged() { + scheduleTasksUpdate(); + + scheduleStructureRequest(new Runnable() { + public void run() { + assert myStructure != null; + myStructure.updateNodes(RunConfigurationNode.class); + } + }); + } + }); + + ((RunManagerEx)RunManager.getInstance(myProject)).addRunManagerListener(new RunManagerAdapter() { + private void changed() { + scheduleStructureRequest(new Runnable() { + public void run() { + assert myStructure != null; + myStructure.visitNodes(ModuleNode.class, new Consumer() { + @Override + public void consume(ModuleNode node) { + node.updateRunConfigurations(); + } + }); + } + }); + } + + @Override + public void runConfigurationAdded(@NotNull RunnerAndConfigurationSettings settings) { + changed(); + } + + @Override + public void runConfigurationRemoved(@NotNull RunnerAndConfigurationSettings settings) { + changed(); + } + + @Override + public void runConfigurationChanged(@NotNull RunnerAndConfigurationSettings settings) { + changed(); + } + }); + + ExternalSystemApiUtil.subscribe(myProject, myExternalSystemId, new ExternalSystemSettingsListenerAdapter(){ + @Override + public void onUseAutoImportChange(boolean currentValue, @NotNull final String linkedProjectPath) { + scheduleStructureRequest(new Runnable() { + public void run() { + assert myStructure != null; + final List projectNodes = myStructure.getNodes(ProjectNode.class); + for (ProjectNode projectNode : projectNodes) { + final ProjectData projectData = projectNode.getData(); + if(projectData != null && projectData.getLinkedExternalProjectPath().equals(linkedProjectPath)) { + projectNode.updateProject(); + break; + } + } + } + }); + } + }); + + ActionManager actionManager = ActionManager.getInstance(); + + DefaultActionGroup group = new DefaultActionGroup(); + final AnAction gearAction = actionManager.getAction("ExternalSystem.GroupTasks"); + if(gearAction instanceof ExternalSystemViewGearAction) { + ((ExternalSystemViewGearAction)gearAction).setView(this); + group.add(gearAction); + } + + myToolWindow.setAdditionalGearActions(group); + + scheduleStructureUpdate(); + } + + private void initStructure() { + myStructure = new ExternalProjectsStructure(myProject, this, myTree); + } + + private void initTree() { + myTree = new SimpleTree(); + myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); + + final ActionManager actionManager = ActionManager.getInstance(); + ActionToolbar actionToolbar = actionManager.createActionToolbar(myExternalSystemId.getReadableName() + " View Toolbar", + (DefaultActionGroup)actionManager + .getAction("ExternalSystemView.ActionsToolbar"), true); + + actionToolbar.setTargetComponent(myTree); + setToolbar(actionToolbar.getComponent()); + setContent(ScrollPaneFactory.createScrollPane(myTree)); + + myTree.addMouseListener(new PopupHandler() { + public void invokePopup(final Component comp, final int x, final int y) { + final String id = getMenuId(getSelectedNodes(ExternalSystemNode.class)); + if (id != null) { + final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(id); + if (actionGroup != null) { + actionManager.createActionPopupMenu("", actionGroup).getComponent().show(comp, x, y); + } + } + } + + @Nullable + private String getMenuId(Collection nodes) { + String id = null; + for (ExternalSystemNode node : nodes) { + String menuId = node.getMenuId(); + if (menuId == null) { + return null; + } + if (id == null) { + id = menuId; + } + else if (!id.equals(menuId)) { + return null; + } + } + return id; + } + }); + } + + public void scheduleStructureUpdate() { + scheduleStructureRequest(new Runnable() { + public void run() { + final Collection projectsData = + ProjectDataManager.getInstance().getExternalProjectsData(myProject, myExternalSystemId); + + final List> toImport = + ContainerUtil.mapNotNull(projectsData, new Function>() { + @Override + public DataNode fun(ExternalProjectInfo info) { + return info.getExternalProjectStructure(); + } + }); + + assert myStructure != null; + myStructure.updateProjects(toImport); + } + }); + } + + protected boolean isUnitTestMode() { + return ApplicationManager.getApplication().isUnitTestMode(); + } + + public static void invokeLater(Project p, Runnable r) { + invokeLater(p, ModalityState.defaultModalityState(), r); + } + + public static void invokeLater(final Project p, final ModalityState state, final Runnable r) { + if (isNoBackgroundMode()) { + r.run(); + } + else { + ApplicationManager.getApplication().invokeLater(DisposeAwareRunnable.create(r, p), state); + } + } + + public static boolean isNoBackgroundMode() { + return (ApplicationManager.getApplication().isUnitTestMode() + || ApplicationManager.getApplication().isHeadlessEnvironment()); + } + + public void updateUpTo(ExternalSystemNode node) { + if (myStructure != null) { + myStructure.updateUpTo(node); + } + } + + @Nullable + protected ExternalProjectsStructure getStructure() { + return myStructure; + } + + @NotNull + public List> createNodes(@Nullable ExternalSystemNode parent, @NotNull DataNode dataNode) { + final List> result = new SmartList>(); + final Map, List>> groups = ExternalSystemApiUtil.group(dataNode.getChildren()); + for (ExternalSystemViewContributor contributor : ExternalSystemViewContributor.EP_NAME.getExtensions()) { + List> keys = contributor.getKeys(); + + final MultiMap, DataNode> dataNodes = MultiMap.create(); + for (Key key : keys) { + final List> values = groups.get(key); + if(key != null && values != null) { + dataNodes.put(key, values); + } + } + + if (dataNodes.isEmpty()) continue; + + final List> childNodes = contributor.createNodes(this, dataNodes); + result.addAll(childNodes); + + if (parent == null) continue; + + for (ExternalSystemNode childNode : childNodes) { + childNode.setParent(parent); + } + } + + return result; + } + + @Nullable + public ExternalProjectsViewState getState() { + ApplicationManager.getApplication().assertIsDispatchThread(); + if (myStructure != null) { + try { + myState.treeState = new Element("root"); + TreeState.createOn(myTree).writeExternal(myState.treeState); + } + catch (WriteExternalException e) { + LOG.warn(e); + } + } + return myState; + } + + public void loadState(ExternalProjectsViewState state) { + myState = state; + } + + public boolean getGroupTasks() { + return myState.groupTasks; + } + + public void setGroupTasks(boolean value) { + if (myState.groupTasks != value) { + myState.groupTasks = value; + scheduleStructureRequest(new Runnable() { + public void run() { + assert myStructure != null; + final List tasksNodes = myStructure.getNodes(TasksNode.class); + for (TasksNode tasksNode : tasksNodes) { + tasksNode.cleanUpCache(); + updateUpTo(tasksNode); + } + } + }); + } + } + + private void scheduleTasksUpdate() { + scheduleStructureRequest(new Runnable() { + public void run() { + assert myStructure != null; + myStructure.updateNodes(TaskNode.class); + } + }); + } + + private void scheduleStructureRequest(final Runnable r) { + if (isUnitTestMode()) { + r.run(); + return; + } + + invokeLater(myProject, new Runnable() { + public void run() { + if (!myToolWindow.isVisible()) return; + + boolean shouldCreate = myStructure == null; + if (shouldCreate) { + initStructure(); + } + + myTree.setPaintBusy(true); + try { + r.run(); + if (shouldCreate) { + restoreTreeState(); + } + } + finally { + myTree.setPaintBusy(false); + } + } + }); + } + + private void restoreTreeState() { + if (myState.treeState != null) { + TreeState treeState = new TreeState(); + try { + treeState.readExternal(myState.treeState); + treeState.applyTo(myTree); + } + catch (InvalidDataException e) { + LOG.info(e); + } + } + } + + private List getSelectedNodes(Class aClass) { + return myStructure != null ? myStructure.getSelectedNodes(myTree, aClass) : ContainerUtil.emptyList(); + } + + private List getSelectedProjectNodes() { + return getSelectedNodes(ProjectNode.class); + } + + @Nullable + private ProjectNode getSelectedProjectNode() { + final List projectNodes = getSelectedProjectNodes(); + return projectNodes.size() == 1 ? projectNodes.get(0) : null; + } + + @Nullable + private Location extractLocation() { + final List selectedNodes = getSelectedNodes(ExternalSystemNode.class); + if (selectedNodes.isEmpty()) return null; + + List tasks = ContainerUtil.newSmartList(); + + ExternalTaskExecutionInfo taskExecutionInfo = new ExternalTaskExecutionInfo(); + + String projectPath = null; + + for (ExternalSystemNode node : selectedNodes) { + final Object data = node.getData(); + if (data instanceof TaskData) { + final TaskData taskData = (TaskData)data; + if (projectPath == null) { + projectPath = taskData.getLinkedExternalProjectPath(); + } + else if (!taskData.getLinkedExternalProjectPath().equals(projectPath)) { + return null; + } + + taskExecutionInfo.getSettings().getTaskNames().add(taskData.getName()); + taskExecutionInfo.getSettings().getTaskDescriptions().add(taskData.getDescription()); + tasks.add(taskData); + } + } + + if(tasks.isEmpty()) return null; + + taskExecutionInfo.getSettings().setExternalSystemIdString(myExternalSystemId.toString()); + taskExecutionInfo.getSettings().setExternalProjectPath(projectPath); + + String name = myExternalSystemId.getReadableName() + projectPath + StringUtil.join(taskExecutionInfo.getSettings().getTaskNames(), " "); + // We create a dummy text file instead of re-using external system file in order to avoid clashing with other configuration producers. + // For example gradle files are enhanced groovy scripts but we don't want to run them via regular IJ groovy script runners. + // Gradle tooling api should be used for running gradle tasks instead. IJ execution sub-system operates on Location objects + // which encapsulate PsiElement and groovy runners are automatically applied if that PsiElement IS-A GroovyFile. + PsiFile file = PsiFileFactory.getInstance(myProject).createFileFromText(name, PlainTextFileType.INSTANCE, ""); + return new ExternalSystemTaskLocation(myProject, file, taskExecutionInfo); + } + + private VirtualFile extractVirtualFile() { + for (ExternalSystemNode each : getSelectedNodes(ExternalSystemNode.class)) { + VirtualFile file = each.getVirtualFile(); + if (file != null && file.isValid()) return file; + } + + final ProjectNode projectNode = getSelectedProjectNode(); + if (projectNode == null) return null; + VirtualFile file = projectNode.getVirtualFile(); + if (file == null || !file.isValid()) return null; + return file; + } + + private Object extractVirtualFiles() { + final List files = new ArrayList(); + for (ExternalSystemNode each : getSelectedNodes(ExternalSystemNode.class)) { + VirtualFile file = each.getVirtualFile(); + if (file != null && file.isValid()) files.add(file); + } + return files.isEmpty() ? null : VfsUtilCore.toVirtualFileArray(files); + } + + private Object extractNavigatables() { + final List navigatables = new ArrayList(); + for (ExternalSystemNode each : getSelectedNodes(ExternalSystemNode.class)) { + Navigatable navigatable = each.getNavigatable(); + if (navigatable != null) navigatables.add(navigatable); + } + return navigatables.isEmpty() ? null : navigatables.toArray(new Navigatable[navigatables.size()]); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemNode.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemNode.java new file mode 100644 index 000000000000..dbe5e0d3154c --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemNode.java @@ -0,0 +1,379 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.ide.util.treeView.NodeDescriptor; +import com.intellij.openapi.externalSystem.ExternalSystemUiAware; +import com.intellij.openapi.externalSystem.action.ExternalSystemActionUtil; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemShortcutsManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator; +import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; +import com.intellij.openapi.externalSystem.util.Order; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.Navigatable; +import com.intellij.ui.JBColor; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.ui.treeStructure.SimpleNode; +import com.intellij.ui.treeStructure.SimpleTree; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.awt.event.InputEvent; +import java.util.*; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 10/15/2014 + */ +public abstract class ExternalSystemNode extends SimpleNode implements Comparable { + + + @NotNull public static final Comparator ORDER_AWARE_COMPARATOR = new Comparator() { + + @Override + public int compare(@NotNull ExternalSystemNode o1, @NotNull ExternalSystemNode o2) { + int order1 = getOrder(o1); + int order2 = getOrder(o2); + if (order1 == order2) return o1.compareTo(o2); + return order1 < order2 ? -1 : 1; + } + + private int getOrder(@NotNull Comparable o) { + Order annotation = o.getClass().getAnnotation(Order.class); + if (annotation != null) { + return annotation.value(); + } + return 0; + } + }; + + + protected static final ExternalSystemNode[] NO_CHILDREN = new ExternalSystemNode[0]; + + private final ExternalProjectsView myExternalProjectsView; + private final List> myChildrenList = ContainerUtil.newArrayList(); + protected DataNode myDataNode; + @Nullable + private ExternalSystemNode myParent; + private ExternalSystemNode[] myChildren; + private ExternalProjectsStructure.ErrorLevel myErrorLevel = ExternalProjectsStructure.ErrorLevel.NONE; + private ExternalProjectsStructure.ErrorLevel myTotalErrorLevel = null; + + public ExternalSystemNode(@NotNull ExternalProjectsView externalProjectsView, + @Nullable ExternalSystemNode parent) { + this(externalProjectsView, parent, null); + } + + public ExternalSystemNode(@NotNull ExternalProjectsView externalProjectsView, + @Nullable ExternalSystemNode parent, + @Nullable DataNode dataNode) { + super(externalProjectsView.getProject(), null); + myExternalProjectsView = externalProjectsView; + myDataNode = dataNode; + myParent = parent; + } + + public void setParent(@Nullable ExternalSystemNode parent) { + myParent = parent; + } + + @Nullable + public T getData() { + return myDataNode != null ? myDataNode.getData() : null; + } + + @Override + public NodeDescriptor getParentDescriptor() { + return myParent; + } + + protected ExternalProjectsView getExternalProjectsView() { + return myExternalProjectsView; + } + + protected ExternalSystemUiAware getUiAware() { + return myExternalProjectsView.getUiAware(); + } + + protected ExternalProjectsStructure getStructure() { + return myExternalProjectsView.getStructure(); + } + + protected ExternalSystemShortcutsManager getShortcutsManager() { + return myExternalProjectsView.getShortcutsManager(); + } + + protected ExternalSystemTaskActivator getTaskActivator() { + return myExternalProjectsView.getTaskActivator(); + } + + @Nullable + public T findParent(Class parentClass) { + ExternalSystemNode node = this; + while (true) { + node = node.myParent; + if (node == null || parentClass.isInstance(node)) { + //noinspection unchecked + return (T)node; + } + } + } + + @Nullable + public DataType findParentData(Class parentDataClass) { + ExternalSystemNode node = this; + while (true) { + node = node.myParent; + if (node == null) return null; + if (node.getData() != null && parentDataClass.isInstance(node.getData())) { + //noinspection unchecked + return (DataType)node.getData(); + } + } + } + + public boolean isVisible() { + return getDisplayKind() != ExternalProjectsStructure.DisplayKind.NEVER; + } + + public ExternalProjectsStructure.DisplayKind getDisplayKind() { + return ExternalProjectsStructure.DisplayKind.NORMAL; + } + + @NotNull + public final ExternalSystemNode[] getChildren() { + if (myChildren == null) { + myChildren = buildChildren(); + onChildrenBuilt(); + } + return myChildren; + } + + protected void onChildrenBuilt() { + } + + @NotNull + private ExternalSystemNode[] buildChildren() { + List newChildrenCandidates = doBuildChildren(); + if (newChildrenCandidates.isEmpty()) return NO_CHILDREN; + + addAll(newChildrenCandidates, true); + sort(myChildrenList); + List visibleNodes = new ArrayList(); + for (ExternalSystemNode each : myChildrenList) { + if (each.isVisible()) visibleNodes.add(each); + } + return visibleNodes.toArray(new ExternalSystemNode[visibleNodes.size()]); + } + + public void cleanUpCache() { + myChildren = null; + myChildrenList.clear(); + myTotalErrorLevel = null; + } + + @Nullable + protected ExternalSystemNode[] getCached() { + return myChildren; + } + + protected void sort(List list) { + Collections.sort(list, ORDER_AWARE_COMPARATOR); + } + + protected boolean addAll(Collection externalSystemNodes) { + return addAll(externalSystemNodes, false); + } + + private boolean addAll(Collection externalSystemNodes, boolean silently) { + if (externalSystemNodes.isEmpty()) return false; + + for (ExternalSystemNode externalSystemNode : externalSystemNodes) { + externalSystemNode.setParent(this); + myChildrenList.add(externalSystemNode); + } + if (!silently) { + childrenChanged(); + } + + return true; + } + + protected boolean add(ExternalSystemNode externalSystemNode) { + return addAll(ContainerUtil.list(externalSystemNode)); + } + + protected boolean removeAll(Collection externalSystemNodes) { + return removeAll(externalSystemNodes, false); + } + + private boolean removeAll(Collection externalSystemNodes, boolean silently) { + if (externalSystemNodes.isEmpty()) return false; + + for (ExternalSystemNode externalSystemNode : externalSystemNodes) { + externalSystemNode.setParent(null); + myChildrenList.remove(externalSystemNode); + } + if (!silently) { + childrenChanged(); + } + + return true; + } + + public void remove(ExternalSystemNode externalSystemNode) { + removeAll(ContainerUtil.list(externalSystemNode)); + } + + protected void childrenChanged() { + ExternalSystemNode each = this; + while (each != null) { + each.myTotalErrorLevel = null; + each = (ExternalSystemNode)each.getParent(); + } + + sort(myChildrenList); + final List> visibleNodes = ContainerUtil.filter(myChildrenList, new Condition>() { + @Override + public boolean value(ExternalSystemNode node) { + return node.isVisible(); + } + }); + myChildren = visibleNodes.toArray(new ExternalSystemNode[visibleNodes.size()]); + myExternalProjectsView.updateUpTo(this); + } + + public boolean hasChildren() { + return getChildren().length > 0; + } + + @NotNull + protected List doBuildChildren() { + if (myDataNode != null && !myDataNode.getChildren().isEmpty()) { + return getExternalProjectsView().createNodes(this, myDataNode); + } + else { + return myChildrenList; + } + } + + public void setDataNode(DataNode dataNode) { + myDataNode = dataNode; + } + + public ExternalProjectsStructure.ErrorLevel getTotalErrorLevel() { + if (myTotalErrorLevel == null) { + myTotalErrorLevel = calcTotalErrorLevel(); + } + return myTotalErrorLevel; + } + + private ExternalProjectsStructure.ErrorLevel calcTotalErrorLevel() { + ExternalProjectsStructure.ErrorLevel childrenErrorLevel = getChildrenErrorLevel(); + return childrenErrorLevel.compareTo(myErrorLevel) > 0 ? childrenErrorLevel : myErrorLevel; + } + + public ExternalProjectsStructure.ErrorLevel getChildrenErrorLevel() { + ExternalProjectsStructure.ErrorLevel result = ExternalProjectsStructure.ErrorLevel.NONE; + for (SimpleNode each : getChildren()) { + ExternalProjectsStructure.ErrorLevel eachLevel = ((ExternalSystemNode)each).getTotalErrorLevel(); + if (eachLevel.compareTo(result) > 0) result = eachLevel; + } + return result; + } + + public void setErrorLevel(ExternalProjectsStructure.ErrorLevel level) { + if (myErrorLevel == level) return; + myErrorLevel = level; + myExternalProjectsView.updateUpTo(this); + } + + @Override + protected void doUpdate() { + setNameAndTooltip(getName(), null); + } + + protected void setNameAndTooltip(String name, @Nullable String tooltip) { + setNameAndTooltip(name, tooltip, (String)null); + } + + protected void setNameAndTooltip(String name, @Nullable String tooltip, @Nullable String hint) { + setNameAndTooltip(name, tooltip, getPlainAttributes()); + if (!StringUtil.isEmptyOrSpaces(hint)) { + addColoredFragment(" (" + hint + ")", SimpleTextAttributes.GRAY_ATTRIBUTES); + } + } + + protected void setNameAndTooltip(String name, @Nullable String tooltip, SimpleTextAttributes attributes) { + clearColoredText(); + addColoredFragment(name, prepareAttributes(attributes)); + getTemplatePresentation().setTooltip(tooltip); + } + + private SimpleTextAttributes prepareAttributes(SimpleTextAttributes from) { + ExternalProjectsStructure.ErrorLevel level = getTotalErrorLevel(); + Color waveColor = level == ExternalProjectsStructure.ErrorLevel.NONE ? null : JBColor.RED; + int style = from.getStyle(); + if (waveColor != null) style |= SimpleTextAttributes.STYLE_WAVED; + return new SimpleTextAttributes(from.getBgColor(), from.getFgColor(), waveColor, style); + } + + @Nullable + @NonNls + protected String getActionId() { + return null; + } + + @Nullable + @NonNls + protected String getMenuId() { + return null; + } + + protected String message(@NotNull String key, @NotNull Object... params) { + return ExternalSystemBundle.message(key); + } + + @Nullable + public VirtualFile getVirtualFile() { + return null; + } + + @Nullable + public Navigatable getNavigatable() { + return null; + } + + @Override + public void handleDoubleClickOrEnter(SimpleTree tree, InputEvent inputEvent) { + String actionId = getActionId(); + if (actionId != null) { + ExternalSystemActionUtil.executeAction(actionId, inputEvent); + } + } + + @Override + public int compareTo(@NotNull ExternalSystemNode node) { + return StringUtil.compare(this.getName(), node.getName(), true); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemViewContributor.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemViewContributor.java new file mode 100644 index 000000000000..7fee2128429c --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemViewContributor.java @@ -0,0 +1,40 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.Key; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 10/10/2014 + */ +public abstract class ExternalSystemViewContributor { + public static final ExtensionPointName EP_NAME = + ExtensionPointName.create("com.intellij.externalSystemViewContributor"); + + @NotNull + public abstract List> getKeys(); + + @NotNull + public abstract List> createNodes( + ExternalProjectsView externalProjectsView, MultiMap, DataNode> dataNodes); +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemViewDefaultContributor.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemViewDefaultContributor.java new file mode 100644 index 000000000000..18fdfa094326 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalSystemViewDefaultContributor.java @@ -0,0 +1,243 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.projectView.PresentationData; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.Key; +import com.intellij.openapi.externalSystem.model.ProjectKeys; +import com.intellij.openapi.externalSystem.model.project.LibraryDependencyData; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.model.project.ModuleDependencyData; +import com.intellij.openapi.externalSystem.service.project.ProjectStructureHelper; +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; +import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.Order; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService; +import com.intellij.pom.Navigatable; +import com.intellij.util.SmartList; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 10/10/2014 + */ +public class ExternalSystemViewDefaultContributor extends ExternalSystemViewContributor { + + private static final Key[] KEYS = new Key[]{ + ProjectKeys.MODULE, + ProjectKeys.MODULE_DEPENDENCY, + ProjectKeys.LIBRARY_DEPENDENCY, + ProjectKeys.TASK + }; + + + @NotNull + @Override + public List> getKeys() { + return Arrays.asList(KEYS); + } + + @Override + @NotNull + public List> createNodes(final ExternalProjectsView externalProjectsView, + final MultiMap, DataNode> dataNodes) { + final List> result = new SmartList>(); + + addModuleNodes(externalProjectsView, dataNodes, result); + // add tasks + result.add(new TasksNode(externalProjectsView, dataNodes.get(ProjectKeys.TASK))); + addDependenciesNode(externalProjectsView, dataNodes, result); + + return result; + } + + private static void addDependenciesNode(@NotNull ExternalProjectsView externalProjectsView, + @NotNull MultiMap, DataNode> dataNodes, + @NotNull List> result) { + final Collection> moduleDeps = dataNodes.get(ProjectKeys.MODULE_DEPENDENCY); + final Collection> libDeps = dataNodes.get(ProjectKeys.LIBRARY_DEPENDENCY); + + if (!moduleDeps.isEmpty() || !libDeps.isEmpty()) { + final ExternalSystemNode depNode = new MyDependenciesNode(externalProjectsView); + + for (DataNode dataNode : moduleDeps) { + if (!(dataNode.getData() instanceof ModuleDependencyData)) continue; + //noinspection unchecked + depNode.add(new ModuleDependencyDataExternalSystemNode(externalProjectsView, (DataNode)dataNode)); + } + + for (DataNode dataNode : libDeps) { + if (!(dataNode.getData() instanceof LibraryDependencyData)) continue; + //noinspection unchecked + final ExternalSystemNode libraryDependencyDataExternalSystemNode = + new LibraryDependencyDataExternalSystemNode(externalProjectsView, (DataNode)dataNode); + + depNode.add(libraryDependencyDataExternalSystemNode); + libraryDependencyDataExternalSystemNode.setErrorLevel(((LibraryDependencyData)dataNode.getData()).getTarget().isUnresolved() + ? ExternalProjectsStructure.ErrorLevel.ERROR + : ExternalProjectsStructure.ErrorLevel.NONE); + } + + result.add(depNode); + } + } + + private static void addModuleNodes(@NotNull ExternalProjectsView externalProjectsView, + @NotNull MultiMap, DataNode> dataNodes, + @NotNull List> result) { + final Collection> moduleDataNodes = dataNodes.get(ProjectKeys.MODULE); + if (!moduleDataNodes.isEmpty()) { + final AbstractExternalSystemSettings systemSettings = + ExternalSystemApiUtil.getSettings(externalProjectsView.getProject(), externalProjectsView.getSystemId()); + + for (DataNode dataNode : moduleDataNodes) { + final ModuleData data = (ModuleData)dataNode.getData(); + + final ExternalProjectSettings projectSettings = systemSettings.getLinkedProjectSettings(data.getLinkedExternalProjectPath()); + final boolean isRoot = + projectSettings != null && data.getLinkedExternalProjectPath().equals(projectSettings.getExternalProjectPath()); + //noinspection unchecked + final ModuleNode moduleNode = new ModuleNode(externalProjectsView, (DataNode)dataNode, isRoot); + result.add(moduleNode); + } + } + } + + @Order(2) + private static class MyDependenciesNode extends ExternalSystemNode { + public MyDependenciesNode(ExternalProjectsView externalProjectsView) { + //noinspection unchecked + super(externalProjectsView, null, null); + } + + @Override + protected void update(PresentationData presentation) { + super.update(presentation); + presentation.setIcon(AllIcons.Nodes.PpLibFolder); + } + + @Override + public String getName() { + return "Dependencies"; + } + } + + private static class ModuleDependencyDataExternalSystemNode extends ExternalSystemNode { + + public ModuleDependencyDataExternalSystemNode(ExternalProjectsView externalProjectsView, DataNode dataNode) { + super(externalProjectsView, null, dataNode); + } + + @Override + protected void update(PresentationData presentation) { + super.update(presentation); + presentation.setIcon(getUiAware().getProjectIcon()); + + final ModuleDependencyData data = getData(); + if (data != null) { + setNameAndTooltip(getName(), null, data.getScope().getDisplayName()); + } + } + + @Override + public String getName() { + final ModuleDependencyData data = getData(); + return data != null ? data.getExternalName() : ""; + } + + @Override + public boolean isAlwaysLeaf() { + return true; + } + } + + private static class LibraryDependencyDataExternalSystemNode extends ExternalSystemNode { + + public LibraryDependencyDataExternalSystemNode(ExternalProjectsView externalProjectsView, DataNode dataNode) { + super(externalProjectsView, null, dataNode); + } + + @Override + protected void update(PresentationData presentation) { + super.update(presentation); + presentation.setIcon(AllIcons.Nodes.PpLib); + + final LibraryDependencyData data = getData(); + if (data != null) { + setNameAndTooltip(getName(), null, data.getScope().getDisplayName()); + } + } + + @Override + public String getName() { + final LibraryDependencyData data = getData(); + return data != null ? data.getExternalName() : ""; + } + + @Override + public boolean isAlwaysLeaf() { + return true; + } + + @Nullable + @Override + public Navigatable getNavigatable() { + return new Navigatable() { + @Nullable + private OrderEntry myOrderEntry; + + @Override + public void navigate(boolean requestFocus) { + if (myOrderEntry != null) { + ProjectSettingsService.getInstance(myProject).openLibraryOrSdkSettings(myOrderEntry); + } + } + + @Override + public boolean canNavigate() { + myOrderEntry = getOrderEntry(); + return myOrderEntry != null; + } + + @Override + public boolean canNavigateToSource() { + return true; + } + }; + } + + @Nullable + private OrderEntry getOrderEntry() { + final LibraryDependencyData data = getData(); + if (data == null) return null; + final Project project = getProject(); + if (project == null) return null; + return ServiceManager.getService(ProjectStructureHelper.class).findIdeModuleOrderEntry(data, project); + } + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ModuleNode.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ModuleNode.java new file mode 100644 index 000000000000..31e88e962910 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ModuleNode.java @@ -0,0 +1,98 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.util.Order; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 11/7/2014 + */ +@Order(1) +public class ModuleNode extends ExternalSystemNode { + private final boolean myIsRoot; + private final ModuleData myData; + private final RunConfigurationsNode myRunConfigurationsNode; + + public ModuleNode(ExternalProjectsView externalProjectsView, + DataNode dataNode, + boolean isRoot) { + super(externalProjectsView, null, dataNode); + myIsRoot = isRoot; + myData = dataNode.getData(); + myRunConfigurationsNode = new RunConfigurationsNode(externalProjectsView, this); + } + + @Override + protected void update(PresentationData presentation) { + super.update(presentation); + presentation.setIcon(getUiAware().getProjectIcon()); + + String hint = null; + if (myIsRoot) { + hint = "root"; + } + + setNameAndTooltip(getName(), myData.toString(), hint); + } + + @NotNull + @Override + protected List doBuildChildren() { + List> myChildNodes = ContainerUtil.newArrayList(); + //noinspection unchecked + myChildNodes.addAll((Collection>)super.doBuildChildren()); + myChildNodes.add(myRunConfigurationsNode); + return myChildNodes; + } + + @Override + public String getName() { + return myData.getId(); + } + + @Nullable + @Override + protected String getMenuId() { + return "ExternalSystemView.ProjectMenu"; + } + + @Override + public boolean isVisible() { + return true; + } + + @Override + public int compareTo(@NotNull ExternalSystemNode node) { + return myIsRoot ? -1 : (node instanceof ModuleNode && ((ModuleNode)node).myIsRoot) ? 1 : super.compareTo(node); + } + + public void updateRunConfigurations() { + myRunConfigurationsNode.updateRunConfigurations(); + childrenChanged(); + getExternalProjectsView().updateUpTo(this); + getExternalProjectsView().updateUpTo(myRunConfigurationsNode); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ProjectNode.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ProjectNode.java new file mode 100644 index 000000000000..78bd31e920a2 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ProjectNode.java @@ -0,0 +1,145 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; +import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.util.Condition; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 10/15/2014 + */ +public class ProjectNode extends ExternalSystemNode { + private String myTooltipCache; + + public ProjectNode(ExternalProjectsView externalProjectsView, DataNode projectDataNode) { + super(externalProjectsView, null, projectDataNode); + updateProject(); + } + + @Override + protected void update(PresentationData presentation) { + super.update(presentation); + presentation.setIcon(getUiAware().getProjectIcon()); + } + + public ExternalSystemNode getGroup() { + return (ExternalSystemNode)getParent(); + } + + @NotNull + @Override + protected List doBuildChildren() { + final List children = super.doBuildChildren(); + final List visibleChildren = ContainerUtil.filter(children, new Condition() { + @Override + public boolean value(ExternalSystemNode node) { + return node.isVisible(); + } + }); + //noinspection unchecked + return visibleChildren.size() == 1 ? children.get(0).doBuildChildren() : children; + } + + void updateProject() { + myTooltipCache = makeDescription(); + getStructure().updateFrom(getParent()); + } + + @Override + public String getName() { + final ProjectData projectData = getData(); + return projectData != null ? projectData.getExternalName() : "unspecified"; + } + + @Override + protected void doUpdate() { + String autoImportHint = null; + final ProjectData projectData = getData(); + if (projectData != null) { + final AbstractExternalSystemSettings externalSystemSettings = + ExternalSystemApiUtil.getSettings(getExternalProjectsView().getProject(), getData().getOwner()); + final ExternalProjectSettings projectSettings = + externalSystemSettings.getLinkedProjectSettings(projectData.getLinkedExternalProjectPath()); + if (projectSettings != null && projectSettings.isUseAutoImport()) autoImportHint = "auto-import enabled"; + } + + setNameAndTooltip(getName(), myTooltipCache, autoImportHint); + } + + @Override + protected SimpleTextAttributes getPlainAttributes() { + return super.getPlainAttributes(); + } + + private String makeDescription() { + StringBuilder desc = new StringBuilder(); + final ProjectData projectData = getData(); + desc.append("" + + "" + + "" + + "" + + ""); + + appendProblems(desc); + + desc.append("
" + + "" + + "" + + "" + + "" + + "") + .append(projectData != null ? + "" + + "" + + "" + + "" + + "
Project:").append(getName()) + .append("
Location:" + projectData.getLinkedExternalProjectPath() : "") + .append("
" + + "
"); + + return desc.toString(); + } + + private void appendProblems(StringBuilder desc) { + // TBD + } + + @Override + protected void setNameAndTooltip(String name, @Nullable String tooltip, SimpleTextAttributes attributes) { + super.setNameAndTooltip(name, tooltip, attributes); + } + + @Override + @Nullable + @NonNls + protected String getMenuId() { + return "ExternalSystemView.ProjectMenu"; + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/RunConfigurationNode.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/RunConfigurationNode.java new file mode 100644 index 000000000000..ebd55aaa358c --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/RunConfigurationNode.java @@ -0,0 +1,132 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.execution.ProgramRunnerUtil; +import com.intellij.execution.RunManager; +import com.intellij.execution.RunManagerEx; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.execution.impl.EditConfigurationsDialog; +import com.intellij.ide.projectView.PresentationData; +import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.pom.Navigatable; +import com.intellij.ui.treeStructure.SimpleTree; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.event.InputEvent; + +import static com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator.getRunConfigurationActivationTaskName; + +/** + * @author Vladislav.Soroka + * @since 11/7/2014 + */ +public class RunConfigurationNode extends ExternalSystemNode { + private final RunnerAndConfigurationSettings mySettings; + + public RunConfigurationNode(@NotNull ExternalProjectsView externalProjectsView, + RunConfigurationsNode parent, + @NotNull RunnerAndConfigurationSettings settings) { + super(externalProjectsView, parent); + mySettings = settings; + } + + @Override + protected void update(PresentationData presentation) { + super.update(presentation); + presentation.setIcon(ProgramRunnerUtil.getConfigurationIcon(mySettings, false)); + + final ExternalSystemRunConfiguration runConfiguration = (ExternalSystemRunConfiguration)mySettings.getConfiguration(); + final ExternalSystemTaskExecutionSettings taskExecutionSettings = runConfiguration.getSettings(); + final String shortcutHint = StringUtil.nullize(getShortcutsManager().getDescription( + taskExecutionSettings.getExternalProjectPath(), mySettings.getName())); + final String activatorHint = StringUtil.nullize(getTaskActivator().getDescription( + taskExecutionSettings.getExternalSystemId(), taskExecutionSettings.getExternalProjectPath(), + getRunConfigurationActivationTaskName(mySettings))); + + String hint; + if (shortcutHint == null) { + hint = activatorHint; + } + else if (activatorHint == null) { + hint = shortcutHint; + } + else { + hint = shortcutHint + ", " + activatorHint; + } + + setNameAndTooltip(getName(), StringUtil.join(taskExecutionSettings.getTaskNames(), " "), hint); + } + + public RunnerAndConfigurationSettings getSettings() { + return mySettings; + } + + @Override + public String getName() { + return mySettings.getName(); + } + + public boolean isAlwaysLeaf() { + return true; + } + + @Nullable + @Override + protected String getMenuId() { + return "ExternalSystemView.RunConfigurationMenu"; + } + + public void updateRunConfiguration() { + } + + @Override + public void handleDoubleClickOrEnter(SimpleTree tree, InputEvent inputEvent) { + final Project project = getExternalProjectsView().getProject(); + ProgramRunnerUtil.executeConfiguration(project, mySettings, DefaultRunExecutor.getRunExecutorInstance()); + final RunManagerEx runManagerEx = RunManagerEx.getInstanceEx(project); + runManagerEx.setSelectedConfiguration(mySettings); + } + + @Nullable + @Override + public Navigatable getNavigatable() { + return new Navigatable() { + + @Override + public void navigate(boolean requestFocus) { + RunManager.getInstance(myProject).setSelectedConfiguration(mySettings); + EditConfigurationsDialog dialog = new EditConfigurationsDialog(myProject); + dialog.show(); + } + + @Override + public boolean canNavigate() { + return true; + } + + @Override + public boolean canNavigateToSource() { + return false; + } + }; + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/RunConfigurationsNode.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/RunConfigurationsNode.java new file mode 100644 index 000000000000..ca826684c3d9 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/RunConfigurationsNode.java @@ -0,0 +1,94 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.execution.RunManager; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.ide.projectView.PresentationData; +import com.intellij.openapi.externalSystem.model.project.ModuleData; +import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.externalSystem.util.Order; +import com.intellij.util.PathUtil; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; +import icons.ExternalSystemIcons; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * @author Vladislav.Soroka + * @since 11/7/2014 + */ +@Order(3) +public class RunConfigurationsNode extends ExternalSystemNode { + + private final ModuleData myModuleData; + + public RunConfigurationsNode(@NotNull ExternalProjectsView externalProjectsView, ModuleNode parent) { + super(externalProjectsView, parent, null); + myModuleData = parent.getData(); + } + + @Override + protected void update(PresentationData presentation) { + super.update(presentation); + presentation.setIcon(ExternalSystemIcons.TaskGroup); + } + + @Override + public String getName() { + return message("external.system.view.nodes.run_configurations.name"); + } + + @Override + public boolean isVisible() { + return hasChildren() && super.isVisible(); + } + + @NotNull + @Override + protected List doBuildChildren() { + List runConfigurationNodes = ContainerUtil.newArrayList(); + final AbstractExternalSystemTaskConfigurationType configurationType = ExternalSystemUtil.findConfigurationType(myModuleData.getOwner()); + if (configurationType == null) return Collections.emptyList(); + + Set settings = new THashSet( + RunManager.getInstance(myProject).getConfigurationSettingsList(configurationType)); + + + String directory = PathUtil.getCanonicalPath(myModuleData.getLinkedExternalProjectPath()); + + for (RunnerAndConfigurationSettings cfg : settings) { + ExternalSystemRunConfiguration externalSystemRunConfiguration = (ExternalSystemRunConfiguration)cfg.getConfiguration(); + + if (directory.equals(PathUtil.getCanonicalPath(externalSystemRunConfiguration.getSettings().getExternalProjectPath()))) { + runConfigurationNodes.add(new RunConfigurationNode(getExternalProjectsView(), this, cfg)); + } + } + + return runConfigurationNodes; + } + + public void updateRunConfigurations() { + cleanUpCache(); + getExternalProjectsView().updateUpTo(this); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/TaskNode.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/TaskNode.java new file mode 100644 index 000000000000..8175c2f6334b --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/TaskNode.java @@ -0,0 +1,81 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 10/28/2014 + */ +public class TaskNode extends ExternalSystemNode { + private TaskData myTaskData; + + public TaskNode(@NotNull ExternalProjectsView externalProjectsView, @NotNull DataNode dataNode) { + super(externalProjectsView, null, dataNode); + myTaskData = dataNode.getData(); + } + + @Override + protected void update(PresentationData presentation) { + super.update(presentation); + presentation.setIcon(getUiAware().getTaskIcon()); + + final String shortcutHint = StringUtil.nullize(getShortcutsManager().getDescription(myTaskData.getLinkedExternalProjectPath(), myTaskData.getName())); + final String activatorHint = StringUtil.nullize(getTaskActivator().getDescription( + myTaskData.getOwner(), myTaskData.getLinkedExternalProjectPath(), myTaskData.getName())); + + String hint; + if (shortcutHint == null) { + hint = activatorHint; + } + else if (activatorHint == null) { + hint = shortcutHint; + } + else { + hint = shortcutHint + ", " + activatorHint; + } + + setNameAndTooltip(getName(), myTaskData.getDescription(), hint); + } + + @Override + public String getName() { + return myTaskData.getName(); + } + + @Nullable + @Override + protected String getMenuId() { + return "ExternalSystemView.TaskMenu"; + } + + @Nullable + @Override + protected String getActionId() { + return "ExternalSystem.RunTask"; + } + + @Override + public boolean isAlwaysLeaf() { + return true; + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/TasksNode.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/TasksNode.java new file mode 100644 index 000000000000..ad4f1e1e611f --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/TasksNode.java @@ -0,0 +1,110 @@ +/* + * 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.openapi.externalSystem.view; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ProjectKeys; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.util.Order; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; +import icons.ExternalSystemIcons; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 11/6/2014 + */ +@Order(1) +public class TasksNode extends ExternalSystemNode { + + private final MultiMap myTasksMap = new MultiMap(); + + @SuppressWarnings("unchecked") + public TasksNode(ExternalProjectsView externalProjectsView, final Collection> dataNodes) { + super(externalProjectsView, null, null); + + if (dataNodes != null && !dataNodes.isEmpty()) { + for (DataNode dataNode : dataNodes) { + if (!(dataNode.getData() instanceof TaskData)) continue; + if (dataNode.getParent() != null && ProjectKeys.PROJECT.equals(dataNode.getParent().getKey())) break; + String group = ((TaskData)dataNode.getData()).getGroup(); + if (group == null) group = "other"; + myTasksMap.putValue(StringUtil.toLowerCase(group), new TaskNode(externalProjectsView, (DataNode)dataNode)); + } + } + } + + @Override + protected void update(PresentationData presentation) { + super.update(presentation); + presentation.setIcon(ExternalSystemIcons.TaskGroup); + } + + @Override + public String getName() { + return "Tasks"; + } + + @Override + public boolean isVisible() { + return hasChildren() && super.isVisible(); + } + + @SuppressWarnings("unchecked") + @NotNull + @Override + protected List doBuildChildren() { + final List> result = ContainerUtil.newArrayList(); + final boolean isGroup = getExternalProjectsView().getGroupTasks(); + if (isGroup) { + for (Map.Entry> collectionEntry : myTasksMap.entrySet()) { + final String group = ObjectUtils.notNull(collectionEntry.getKey(), "other"); + final ExternalSystemNode tasksGroupNode = new ExternalSystemNode(getExternalProjectsView(), null, null) { + + @Override + protected void update(PresentationData presentation) { + super.update(presentation); + presentation.setIcon(ExternalSystemIcons.TaskGroup); + } + + @Override + public String getName() { + return group; + } + + @Override + public int compareTo(@NotNull ExternalSystemNode node) { + return "other".equals(group) ? 1 : super.compareTo(node); + } + }; + tasksGroupNode.addAll(collectionEntry.getValue()); + result.add(tasksGroupNode); + } + } + else { + result.addAll(myTasksMap.values()); + } + return result; + } +} diff --git a/platform/external-system-impl/src/icons/ExternalSystemIcons.java b/platform/external-system-impl/src/icons/ExternalSystemIcons.java index 24be89247d98..38dd0388ff2b 100644 --- a/platform/external-system-impl/src/icons/ExternalSystemIcons.java +++ b/platform/external-system-impl/src/icons/ExternalSystemIcons.java @@ -29,4 +29,5 @@ public class ExternalSystemIcons { } public static final Icon Task = load("/icons/task.png"); // 16x16 + public static final Icon TaskGroup = load("/icons/taskGroup.png"); // 16x16 } diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTaskListModelTest.java b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTaskListModelTest.java deleted file mode 100644 index 9bed36f596e0..000000000000 --- a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/task/ui/ExternalSystemRecentTaskListModelTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2000-2013 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.openapi.externalSystem.service.task.ui; - -import com.intellij.openapi.command.impl.DummyProject; -import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings; -import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo; -import com.intellij.openapi.externalSystem.test.ExternalSystemTestUtil; -import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; -import com.intellij.util.containers.ContainerUtilRt; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.List; - -/** - * @author Vladislav Soroka - * @since 8/13/13 - */ -public class ExternalSystemRecentTaskListModelTest { - - private ExternalSystemRecentTaskListModel myModel; - - @Before - public void setUp() { - myModel = new ExternalSystemRecentTaskListModel(ExternalSystemTestUtil.TEST_EXTERNAL_SYSTEM_ID, DummyProject.getInstance()); - } - - @Test - public void testSetFirst() throws Exception { - List tasks = ContainerUtilRt.newArrayList(); - for (int i = 0; i <= ExternalSystemConstants.RECENT_TASKS_NUMBER; i++) { - new ExternalTaskExecutionInfo(new ExternalSystemTaskExecutionSettings(), "task" + i); - } - myModel.setTasks(tasks); - - myModel.setFirst(new ExternalTaskExecutionInfo(new ExternalSystemTaskExecutionSettings(), "newTask")); - - Assert.assertEquals(ExternalSystemConstants.RECENT_TASKS_NUMBER, myModel.getSize()); - myModel.setFirst(new ExternalTaskExecutionInfo(new ExternalSystemTaskExecutionSettings(), "task1")); - Assert.assertEquals(ExternalSystemConstants.RECENT_TASKS_NUMBER, myModel.getSize()); - } - - @Test - public void testEnsureSize() throws Exception { - List tasks = ContainerUtilRt.newArrayList(); - - // test task list widening - myModel.setTasks(tasks); - myModel.ensureSize(ExternalSystemConstants.RECENT_TASKS_NUMBER); - Assert.assertEquals("task list widening failed", ExternalSystemConstants.RECENT_TASKS_NUMBER, myModel.getSize()); - - // test task list reduction - for (int i = 0; i < ExternalSystemConstants.RECENT_TASKS_NUMBER + 1; i++) { - tasks.add(new ExternalTaskExecutionInfo(new ExternalSystemTaskExecutionSettings(), "task" + i)); - } - myModel.setTasks(tasks); - Assert.assertEquals(ExternalSystemConstants.RECENT_TASKS_NUMBER + 1, myModel.getSize()); - - myModel.ensureSize(ExternalSystemConstants.RECENT_TASKS_NUMBER); - Assert.assertEquals("task list reduction failed", ExternalSystemConstants.RECENT_TASKS_NUMBER, myModel.getSize()); - } -} diff --git a/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml b/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml index c2bb2b5bd819..ce1ce7c746fa 100644 --- a/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml @@ -11,5 +11,6 @@ interface="com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener"/> + \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml b/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml index 10bd0e8ba013..98d7413c2dce 100644 --- a/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml +++ b/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml @@ -2,6 +2,8 @@ + + @@ -20,6 +22,7 @@ + @@ -31,6 +34,7 @@ + diff --git a/platform/platform-resources/src/idea/ExternalSystemActions.xml b/platform/platform-resources/src/idea/ExternalSystemActions.xml index fdb174aa37be..b99b75929dc5 100644 --- a/platform/platform-resources/src/idea/ExternalSystemActions.xml +++ b/platform/platform-resources/src/idea/ExternalSystemActions.xml @@ -1,7 +1,6 @@ - - + @@ -16,22 +15,134 @@ + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/gradle/resources/icons/offlineMode.png b/plugins/gradle/resources/icons/offlineMode.png new file mode 100644 index 0000000000000000000000000000000000000000..3276aca09875f56142a5b9a8e1dcad659c51fc0d GIT binary patch literal 403 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKV2tu~aSW-rmHgxXe|u(CiB@4r z$<7|th98!Cc7|*}m_Dk-)Fkm_us+fP(KlF+tlRNJgUurB-0$~Mn?LOLKHK!)FZA>M z+tbcP@r8Vm>-g!|wRZEa3Wu8ZMJv4YEpr-8a|1Wq(_pzsi z>9J--@E9v7n60%^QOj%(f4z!#;^nf2t4&`H@D}7of3{Ef^zDD0@U}nYxv_gyRm?J( z1Cp)IG+bD*Lp09Q^|Y*XxXib=_j$s&FEN`RSe5s){`ouK|FXBP|2JD7wTCI=cjW@N z0@?~dvBzc&GCT|!AGjOeBt2^Y1~!AItDnm{r-UW|7Ywb_ literal 0 HcmV?d00001 diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index 4e4fea02a0c7..8302a603e38f 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -111,6 +111,7 @@ + @@ -147,10 +148,28 @@ + + + + + + + + + + + + + + + diff --git a/plugins/gradle/src/icons/GradleIcons.java b/plugins/gradle/src/icons/GradleIcons.java index 4283f7207364..19f20258d467 100644 --- a/plugins/gradle/src/icons/GradleIcons.java +++ b/plugins/gradle/src/icons/GradleIcons.java @@ -33,5 +33,6 @@ public class GradleIcons { public static final Icon GradleNavigate = load("/icons/gradleNavigate.png"); // 16x16 public static final Icon GradlePlugin = load("/icons/gradlePlugin.png"); // 16x16 public static final Icon GradleSync = load("/icons/gradleSync.png"); // 16x16 + public static final Icon OfflineMode = load("/icons/offlineMode.png"); // 16x16 public static final Icon ToolWindowGradle = load("/icons/toolWindowGradle.png"); // 13x13 } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/ToggleOfflineAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/ToggleOfflineAction.java new file mode 100644 index 000000000000..63203a251eda --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/ToggleOfflineAction.java @@ -0,0 +1,37 @@ +/* + * 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 org.jetbrains.plugins.gradle.action; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.externalSystem.action.ExternalSystemToggleAction; +import org.jetbrains.plugins.gradle.settings.GradleSettings; + +/** + * @author Vladislav.Soroka + * @since 10/20/2014 + */ +public class ToggleOfflineAction extends ExternalSystemToggleAction { + + @Override + protected boolean doIsSelected(AnActionEvent e) { + return GradleSettings.getInstance(getProject(e)).isOfflineWork(); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + GradleSettings.getInstance(getProject(e)).setOfflineWork(state); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java index 3e762741fb7a..036e61f5be13 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java @@ -330,6 +330,23 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver final Collection tasks = ContainerUtil.newArrayList(); final String moduleConfigPath = ideModule.getData().getLinkedExternalProjectPath(); + ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class); + + if (externalProject != null) { + for (ExternalTask task : externalProject.getTasks().values()) { + String taskName = task.getName(); + if (taskName.trim().isEmpty() || isIdeaTask(taskName)) { + continue; + } + TaskData taskData = new TaskData(GradleConstants.SYSTEM_ID, taskName, moduleConfigPath, task.getDescription()); + taskData.setGroup(task.getGroup()); + ideModule.createChild(ProjectKeys.TASK, taskData); + tasks.add(taskData); + } + + return tasks; + } + for (GradleTask task : gradleModule.getGradleProject().getTasks()) { String taskName = task.getName(); if (taskName == null || taskName.trim().isEmpty() || isIdeaTask(taskName)) { @@ -641,7 +658,7 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver if (unresolved) { // Gradle uses names like 'unresolved dependency - commons-collections commons-collections 3.2' for unresolved dependencies. - libraryName = binaryPath.getName().substring(UNRESOLVED_DEPENDENCY_PREFIX.length()); + libraryName = binaryPath.getPath().substring(UNRESOLVED_DEPENDENCY_PREFIX.length()); int i = libraryName.indexOf(' '); if (i >= 0) { i = CharArrayUtil.shiftForward(libraryName, i + 1, " "); @@ -669,6 +686,13 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver final String classifier = matcher.group(1); libraryName += (":" + classifier); } + else { + final String artifactId = StringUtil.trimEnd(StringUtil.trimEnd(libraryFileName, moduleVersion.getVersion()), "-"); + libraryName = String.format("%s:%s:%s", + moduleVersion.getGroup(), + artifactId, + moduleVersion.getVersion()); + } } } } diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy index 3f338ea3f585..096b1e6d8d5b 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy @@ -101,7 +101,7 @@ class ExternalProjectBuilderImpl implements ModelBuilderService { ExternalTask externalTask = new DefaultExternalTask() externalTask.name = task.name externalTask.description = task.description - externalTask.group = task.group + externalTask.group = task.group ?: "other" externalTask.QName = task.path result.put(externalTask.QName, externalTask) }