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 index 8580c93e7587..2a86372b6c57 100644 --- 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 @@ -61,7 +61,7 @@ public class AssignRunConfigurationShortcutAction extends ExternalSystemAction { String actionId = actionIdPrefix + settings.getName(); AnAction action = ActionManager.getInstance().getAction(actionId); if (action == null) { - ExternalSystemKeymapExtension.registerAction(project, settings); + ExternalSystemKeymapExtension.getOrRegisterAction(project, settings); } 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 index 1dc2ebf1de01..0008a6016657 100644 --- 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 @@ -74,7 +74,7 @@ public class AssignShortcutAction extends ExternalSystemNodeAction { group = projectData != null ? projectData.getInternalName() : null; } if (group != null) { - ExternalSystemKeymapExtension.registerAction(project, group, taskData); + ExternalSystemKeymapExtension.getOrRegisterAction(project, group, taskData); } } new EditKeymapsDialog(project, actionId).show(); 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 index 885de988d60e..7c04330fa250 100644 --- 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 @@ -19,10 +19,15 @@ import com.intellij.execution.ProgramRunnerUtil; import com.intellij.execution.RunManager; import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; 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.application.ApplicationManager; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.ExternalSystemUiAware; import com.intellij.openapi.externalSystem.action.ExternalSystemAction; import com.intellij.openapi.externalSystem.action.ExternalSystemActionUtil; @@ -34,6 +39,7 @@ 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.service.ui.SelectExternalTaskDialog; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemBundle; import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; @@ -41,9 +47,14 @@ 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.keymap.impl.ui.Group; +import com.intellij.openapi.keymap.impl.ui.Hyperlink; +import com.intellij.openapi.keymap.impl.ui.KeymapListener; +import com.intellij.openapi.keymap.impl.ui.KeymapPanel; +import com.intellij.openapi.options.ex.Settings; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.SystemInfoRt; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import gnu.trove.THashSet; @@ -52,6 +63,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.event.MouseEvent; import java.util.Collection; import java.util.Map; import java.util.Set; @@ -62,12 +74,22 @@ import java.util.Set; */ public class ExternalSystemKeymapExtension implements KeymapExtension { - public KeymapGroup createGroup(Condition condition, Project project) { + public interface ActionsProvider { + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.externalSystemKeymapProvider"); + + KeymapGroup createGroup(Condition condition, final Project project); + } + + + public KeymapGroup createGroup(Condition condition, final 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(); + MultiMap projectToActionsMapping = MultiMap.create(); + for (ExternalSystemManager manager : ExternalSystemApiUtil.getAllManagers()) { + projectToActionsMapping.putValues(manager.getSystemId(), ContainerUtil.emptyList()); + } ActionManager actionManager = ActionManager.getInstance(); if (actionManager != null) { @@ -78,36 +100,58 @@ public class ExternalSystemKeymapExtension implements KeymapExtension { if (condition != null && !condition.value(actionManager.getActionOrStub(eachId))) continue; MyExternalSystemAction taskAction = (MyExternalSystemAction)eachAction; - projectToActionsMapping.putValue(Pair.create(taskAction.getSystemId(), taskAction.getGroup()), eachId); + projectToActionsMapping.putValue(taskAction.getSystemId(), 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); + for (ProjectSystemId systemId : projectToActionsMapping.keySet()) { + if (!keymapGroupMap.containsKey(systemId)) { + final Icon projectIcon = ExternalSystemUiUtil.getUiAware(systemId).getProjectIcon(); + KeymapGroup group = KeymapGroupFactory.getInstance().createGroup(systemId.getReadableName(), projectIcon); result.addGroup(group); - keymapGroupMap.put(pair.first, group); + keymapGroupMap.put(systemId, group); } } - - for (Map.Entry, Collection> each : projectToActionsMapping.entrySet()) { - String groupName = each.getKey().second; + for (Map.Entry> each : projectToActionsMapping.entrySet()) { 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); - } + final ProjectSystemId systemId = each.getKey(); + final KeymapGroup systemGroup = keymapGroupMap.get(systemId); for (String actionId : tasks) { - group.addActionId(actionId); + systemGroup.addActionId(actionId); + } + if (systemGroup instanceof Group) { + Icon icon = SystemInfoRt.isMac ? AllIcons.ToolbarDecorator.Mac.Add : AllIcons.ToolbarDecorator.Add; + ((Group)systemGroup).addHyperlink(new Hyperlink(icon, "Choose a task to assign a shortcut") { + @Override + public void onClick(MouseEvent e) { + SelectExternalTaskDialog dialog = new SelectExternalTaskDialog(systemId, project); + if (dialog.showAndGet() && dialog.getResult() != null) { + TaskData taskData = dialog.getResult().second; + String ownerModuleName = dialog.getResult().first; + ExternalSystemTaskAction externalSystemAction = + (ExternalSystemTaskAction)getOrRegisterAction(project, ownerModuleName, taskData); + + ApplicationManager.getApplication().getMessageBus().syncPublisher(KeymapListener.CHANGE_TOPIC).processCurrentKeymapChanged(); + + Settings allSettings = Settings.KEY.getData(DataManager.getInstance().getDataContext(e.getComponent())); + KeymapPanel keymapPanel = allSettings != null ? allSettings.find(KeymapPanel.class) : null; + if (keymapPanel != null) { + // clear actions filter + keymapPanel.showOption(""); + keymapPanel.selectAction(externalSystemAction.myId); + } + } + } + }); + } + } + + for (ActionsProvider extension : ActionsProvider.EP_NAME.getExtensions()) { + KeymapGroup group = extension.createGroup(condition, project); + if (group != null) { + result.addGroup(group); } } @@ -119,9 +163,14 @@ public class ExternalSystemKeymapExtension implements KeymapExtension { createActions(project, taskData); } - public static ExternalSystemAction registerAction(Project project, String group, TaskData taskData) { + public static ExternalSystemAction getOrRegisterAction(Project project, String group, TaskData taskData) { ExternalSystemTaskAction action = new ExternalSystemTaskAction(project, group, taskData); ActionManager manager = ActionManager.getInstance(); + AnAction anAction = manager.getAction(action.getId()); + if (anAction instanceof ExternalSystemTaskAction && action.equals(anAction)) { + return (ExternalSystemAction)anAction; + } + manager.unregisterAction(action.getId()); manager.registerAction(action.getId(), action); return action; } @@ -197,7 +246,7 @@ public class ExternalSystemKeymapExtension implements KeymapExtension { } } - public static ExternalSystemAction registerAction(Project project, RunnerAndConfigurationSettings configurationSettings) { + public static ExternalSystemAction getOrRegisterAction(Project project, RunnerAndConfigurationSettings configurationSettings) { ActionManager manager = ActionManager.getInstance(); ExternalSystemRunConfigurationAction runConfigurationAction = new ExternalSystemRunConfigurationAction(project, configurationSettings); @@ -263,6 +312,27 @@ public class ExternalSystemKeymapExtension implements KeymapExtension { public String getId() { return myId; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ExternalSystemTaskAction)) return false; + + ExternalSystemTaskAction action = (ExternalSystemTaskAction)o; + + if (myId != null ? !myId.equals(action.myId) : action.myId != null) return false; + if (myGroup != null ? !myGroup.equals(action.myGroup) : action.myGroup != null) return false; + if (!myTaskData.equals(action.myTaskData)) return false; + return true; + } + + @Override + public int hashCode() { + int result = myId != null ? myId.hashCode() : 0; + result = 31 * result + (myGroup != null ? myGroup.hashCode() : 0); + result = 31 * result + myTaskData.hashCode(); + return result; + } } private static class ExternalSystemRunConfigurationAction extends MyExternalSystemAction { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalSystemNodeDialog.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalSystemNodeDialog.java index 40cd82518a95..6866e4a3a72e 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalSystemNodeDialog.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalSystemNodeDialog.java @@ -34,6 +34,7 @@ import com.intellij.ui.treeStructure.SimpleTree; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -49,30 +50,49 @@ import java.util.List; */ public class SelectExternalSystemNodeDialog extends DialogWrapper { - private final @NotNull ProjectSystemId mySystemId; + @NotNull private final SimpleTree myTree; + @Nullable private final NodeSelector mySelector; + @Nullable + protected Boolean groupTasks; + @Nullable + protected Boolean useTasksNode; public SelectExternalSystemNodeDialog(@NotNull ProjectSystemId systemId, - Project project, - String title, - final Class nodeClass, - NodeSelector selector) { + @NotNull Project project, + @NotNull String title, + Class nodeClass, + @Nullable NodeSelector selector) { + //noinspection unchecked + this(systemId, project, title, new Class[]{nodeClass}, selector); + } + + public SelectExternalSystemNodeDialog(@NotNull ProjectSystemId systemId, + @NotNull Project project, + @NotNull String title, + final Class[] nodeClasses, + @Nullable NodeSelector selector) { super(project, false); - mySystemId = systemId; mySelector = selector; setTitle(title); myTree = new SimpleTree(); myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); - final ExternalProjectsView projectsView = ExternalProjectsManager.getInstance(project).getExternalProjectsView(mySystemId); + final ExternalProjectsView projectsView = ExternalProjectsManager.getInstance(project).getExternalProjectsView(systemId); if(projectsView != null) { final ExternalProjectsStructure treeStructure = new ExternalProjectsStructure(project, myTree) { @SuppressWarnings("unchecked") @Override protected Class[] getVisibleNodesClasses() { - return new Class[]{nodeClass}; + return nodeClasses; + } + + @Override + public Object getRootElement() { + Object rootElement = super.getRootElement(); + return customizeProjectsTreeRoot(rootElement); } }; treeStructure.init(new ExternalProjectsViewAdapter(projectsView) { @@ -87,6 +107,16 @@ public class SelectExternalSystemNodeDialog extends DialogWrapper { treeStructure.updateUpTo(node); } + @Override + public boolean getGroupTasks() { + return groupTasks != null ? groupTasks : super.getGroupTasks(); + } + + @Override + public boolean useTasksNode() { + return useTasksNode != null ? useTasksNode : super.useTasksNode(); + } + @Override public void handleDoubleClickOrEnter(@NotNull ExternalSystemNode node, @Nullable String actionId, InputEvent inputEvent) { SelectExternalSystemNodeDialog.this.handleDoubleClickOrEnter(node, actionId, inputEvent); @@ -94,7 +124,7 @@ public class SelectExternalSystemNodeDialog extends DialogWrapper { }); final Collection projectsData = - ProjectDataManager.getInstance().getExternalProjectsData(project, mySystemId); + ProjectDataManager.getInstance().getExternalProjectsData(project, systemId); final List> dataNodes = ContainerUtil.mapNotNull(projectsData, new Function>() { @@ -104,23 +134,30 @@ public class SelectExternalSystemNodeDialog extends DialogWrapper { } }); treeStructure.updateProjects(dataNodes); + TreeUtil.expandAll(myTree); - final SimpleNode[] selection = new SimpleNode[]{null}; - treeStructure.accept(new SimpleNodeVisitor() { - public boolean accept(SimpleNode each) { - if (!mySelector.shouldSelect(each)) return false; - selection[0] = each; - return true; + if (mySelector != null) { + final SimpleNode[] selection = new SimpleNode[]{null}; + treeStructure.accept(new SimpleNodeVisitor() { + public boolean accept(SimpleNode each) { + if (!mySelector.shouldSelect(each)) return false; + selection[0] = each; + return true; + } + }); + if (selection[0] != null) { + treeStructure.select(selection[0]); } - }); - if (selection[0] != null) { - treeStructure.select(selection[0]); } } init(); } + protected Object customizeProjectsTreeRoot(Object rootElement) { + return rootElement; + } + @Nullable @Override public JComponent getPreferredFocusedComponent() { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalTaskDialog.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalTaskDialog.java new file mode 100644 index 000000000000..d26e67375388 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/SelectExternalTaskDialog.java @@ -0,0 +1,90 @@ +/* + * Copyright 2000-2015 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.ui; + +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.view.ExternalSystemNode; +import com.intellij.openapi.externalSystem.view.ModuleNode; +import com.intellij.openapi.externalSystem.view.ProjectNode; +import com.intellij.openapi.externalSystem.view.TaskNode; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.ui.treeStructure.NullNode; +import com.intellij.ui.treeStructure.SimpleNode; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.event.InputEvent; + +/** + * @author Vladislav.Soroka + * @since 4/15/2015 + */ +public class SelectExternalTaskDialog extends SelectExternalSystemNodeDialog { + + private static final Class[] NODE_CLASSES = ContainerUtil.ar( + ProjectNode.class, + ModuleNode.class, + TaskNode.class + ); + private Pair myResult; + + public SelectExternalTaskDialog(@NotNull ProjectSystemId systemId, Project project) { + super(systemId, project, String.format("Choose %s Task", systemId.getReadableName()), NODE_CLASSES, null); + groupTasks = Boolean.FALSE; + useTasksNode = Boolean.FALSE; + init(); + } + + @Override + protected void doOKAction() { + SimpleNode node = getSelectedNode(); + if (node instanceof NullNode) node = null; + + myResult = node instanceof TaskNode ? Pair.create(((TaskNode)node).getModuleOwnerName(), ((TaskNode)node).getData()) : null; + super.doOKAction(); + } + + @Override + public void doCancelAction() { + super.doCancelAction(); + myResult = null; + } + + @Override + protected void handleDoubleClickOrEnter(@NotNull ExternalSystemNode node, @Nullable String actionId, InputEvent inputEvent) { + if (node instanceof ProjectNode) { + doOKAction(); + } + } + + public Pair getResult() { + return myResult; + } + + @Override + protected Object customizeProjectsTreeRoot(Object rootElement) { + if (rootElement instanceof ExternalSystemNode && ((ExternalSystemNode)rootElement).getChildCount() == 1) { + ExternalSystemNode node = ((ExternalSystemNode)rootElement).getChildren()[0]; + return (node instanceof ProjectNode) && ((ProjectNode)node).isSingleModuleProject() ? rootElement : node; + } + else { + return rootElement; + } + } +} 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 index 984478ab879b..dffe13f520cd 100644 --- 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 @@ -132,7 +132,7 @@ public class ExternalProjectsStructure extends SimpleTreeStructure { projectNode = new ProjectNode(myExternalProjectsView, each); myNodeMapping.put(projectPath, projectNode); } - if (toImport.size() == 0) { + if (toImport.size() == 1) { myTreeBuilder.expand(projectNode, null); } doUpdateProject((ProjectNode)projectNode); 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 index 938919d396db..33ed771be9da 100644 --- 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 @@ -51,6 +51,8 @@ public interface ExternalProjectsView { boolean getGroupTasks(); + boolean useTasksNode(); + ProjectSystemId getSystemId(); void handleDoubleClickOrEnter(@NotNull ExternalSystemNode node, @Nullable String actionId, InputEvent inputEvent); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewAdapter.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewAdapter.java index c52eaac1cc0d..44fe1b4babcb 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewAdapter.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewAdapter.java @@ -87,6 +87,11 @@ public class ExternalProjectsViewAdapter implements ExternalProjectsView { return delegate.getGroupTasks(); } + @Override + public boolean useTasksNode() { + return delegate.useTasksNode(); + } + @Override public ProjectSystemId getSystemId() { return delegate.getSystemId(); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java index 521938d30ff1..d9e317656d9c 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/view/ExternalProjectsViewImpl.java @@ -479,6 +479,11 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D return myState.groupTasks; } + @Override + public boolean useTasksNode() { + return true; + } + public void setGroupTasks(boolean value) { if (myState.groupTasks != value) { myState.groupTasks = value; 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 index 5351a2a50170..9ffbf27494c1 100644 --- 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 @@ -93,6 +93,11 @@ public abstract class ExternalSystemNode extends SimpleNode implements Compar myParent = parent; } + public boolean isAutoExpandNode() { + SimpleNode parent = getParent(); + return parent != null && parent.getChildCount() == 1; + } + public void setParent(@Nullable ExternalSystemNode parent) { myParent = parent; } 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 index 18fdfa094326..2632078e9972 100644 --- 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 @@ -34,12 +34,14 @@ 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.ContainerUtil; 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.Collections; import java.util.List; /** @@ -70,7 +72,13 @@ public class ExternalSystemViewDefaultContributor extends ExternalSystemViewCont addModuleNodes(externalProjectsView, dataNodes, result); // add tasks - result.add(new TasksNode(externalProjectsView, dataNodes.get(ProjectKeys.TASK))); + TasksNode tasksNode = new TasksNode(externalProjectsView, dataNodes.get(ProjectKeys.TASK)); + if(externalProjectsView.useTasksNode()) { + result.add(tasksNode); + } else { + ContainerUtil.addAll(result, tasksNode.getChildren()); + } + addDependenciesNode(externalProjectsView, dataNodes, result); return result; 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 index 8ec528d3f132..e8c8bcf12caf 100644 --- 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 @@ -37,6 +37,7 @@ import java.util.List; */ public class ProjectNode extends ExternalSystemNode { private String myTooltipCache; + private boolean singleModuleProject = false; public ProjectNode(ExternalProjectsView externalProjectsView, DataNode projectDataNode) { super(externalProjectsView, null, projectDataNode); @@ -64,14 +65,21 @@ public class ProjectNode extends ExternalSystemNode { } }); if (visibleChildren.size() == 1 && visibleChildren.get(0).getName().equals(getName())) { + singleModuleProject = true; //noinspection unchecked return visibleChildren.get(0).doBuildChildren(); } else { + singleModuleProject = false; return visibleChildren; } } + public boolean isSingleModuleProject() { + getChildren(); + return singleModuleProject; + } + void updateProject() { myTooltipCache = makeDescription(); getStructure().updateFrom(getParent()); 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 index bcf14d205e9e..11665d4f16a1 100644 --- 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 @@ -17,21 +17,35 @@ 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.Named; import com.intellij.openapi.externalSystem.model.task.TaskData; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static com.intellij.openapi.externalSystem.model.ProjectKeys.MODULE; +import static com.intellij.openapi.externalSystem.model.ProjectKeys.PROJECT; + /** * @author Vladislav.Soroka * @since 10/28/2014 */ public class TaskNode extends ExternalSystemNode { private TaskData myTaskData; + private String moduleOwnerName; public TaskNode(@NotNull ExternalProjectsView externalProjectsView, @NotNull DataNode dataNode) { super(externalProjectsView, null, dataNode); myTaskData = dataNode.getData(); + + DataNode parent = ExternalSystemApiUtil.findParent(dataNode, MODULE); + if (parent == null) { + parent = ExternalSystemApiUtil.findParent(dataNode, PROJECT); + } + if(parent != null && parent.getData() instanceof Named) { + moduleOwnerName = ((Named)parent.getData()).getInternalName(); + } } @Override @@ -68,6 +82,10 @@ public class TaskNode extends ExternalSystemNode { return myTaskData.getName(); } + public String getModuleOwnerName() { + return moduleOwnerName; + } + @Nullable @Override protected String getMenuId() { diff --git a/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml b/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml index 447d800c24a2..27ad18be8fe3 100644 --- a/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml @@ -7,6 +7,8 @@ interface="com.intellij.openapi.externalSystem.service.settings.ExternalSystemConfigLocator"/> + + diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsStructure.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsStructure.java index c779129a6093..c21c2a33f91c 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsStructure.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsStructure.java @@ -1005,6 +1005,10 @@ public class MavenProjectsStructure extends SimpleTreeStructure { setUniformIcon(MavenIcons.Phase); } + public MavenProject getMavenProject() { + return myMavenProject; + } + public String getProjectPath() { return myMavenProject.getPath(); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/SelectFromMavenProjectsDialog.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/SelectFromMavenProjectsDialog.java index 6296a20cdeee..effa7dfe60c5 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/SelectFromMavenProjectsDialog.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/SelectFromMavenProjectsDialog.java @@ -31,30 +31,35 @@ import javax.swing.*; import javax.swing.tree.TreeSelectionModel; public class SelectFromMavenProjectsDialog extends DialogWrapper { - private final Project myProject; private final SimpleTree myTree; private final NodeSelector mySelector; + public SelectFromMavenProjectsDialog(Project project, + String title, + final Class nodeClass) { + this(project, title, nodeClass, null); + } + public SelectFromMavenProjectsDialog(Project project, String title, final Class nodeClass, - NodeSelector selector) { + @Nullable NodeSelector selector) { super(project, false); - myProject = project; mySelector = selector; setTitle(title); myTree = new SimpleTree(); myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); - MavenProjectsStructure treeStructure = new MavenProjectsStructure(myProject, - MavenProjectsManager.getInstance(myProject), - MavenTasksManager.getInstance(myProject), - MavenShortcutsManager.getInstance(myProject), - MavenProjectsNavigator.getInstance(myProject), + MavenProjectsStructure treeStructure = new MavenProjectsStructure(project, + MavenProjectsManager.getInstance(project), + MavenTasksManager.getInstance(project), + MavenShortcutsManager.getInstance(project), + MavenProjectsNavigator.getInstance(project), myTree) { @Override protected Class[] getVisibleNodesClasses() { + //noinspection unchecked return new Class[]{nodeClass}; } @@ -70,16 +75,18 @@ public class SelectFromMavenProjectsDialog extends DialogWrapper { }; treeStructure.update(); - final SimpleNode[] selection = new SimpleNode[]{null}; - treeStructure.accept(new SimpleNodeVisitor() { - public boolean accept(SimpleNode each) { - if (!mySelector.shouldSelect(each)) return false; - selection[0] = each; - return true; + if (mySelector != null) { + final SimpleNode[] selection = new SimpleNode[]{null}; + treeStructure.accept(new SimpleNodeVisitor() { + public boolean accept(SimpleNode each) { + if (!mySelector.shouldSelect(each)) return false; + selection[0] = each; + return true; + } + }); + if (selection[0] != null) { + treeStructure.select(selection[0]); } - }); - if (selection[0] != null) { - treeStructure.select(selection[0]); } init(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/SelectMavenGoalDialog.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/SelectMavenGoalDialog.java new file mode 100644 index 000000000000..82a3ab9ebfc3 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/SelectMavenGoalDialog.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.maven.navigator; + +import com.intellij.openapi.project.Project; +import com.intellij.ui.treeStructure.NullNode; +import com.intellij.ui.treeStructure.SimpleNode; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +public class SelectMavenGoalDialog extends SelectFromMavenProjectsDialog { + private MavenProjectsStructure.GoalNode myResult; + + public SelectMavenGoalDialog(Project project) { + super(project, "Choose Maven Goal", MavenProjectsStructure.GoalNode.class); + init(); + } + + @NotNull + @Override + protected Action[] createActions() { + return new Action[]{getOKAction(), getCancelAction()}; + } + + @Override + protected void doOKAction() { + SimpleNode node = getSelectedNode(); + if (node instanceof NullNode) node = null; + + myResult = node instanceof MavenProjectsStructure.GoalNode ? ((MavenProjectsStructure.GoalNode)node) : null; + super.doOKAction(); + } + + @Override + public void doCancelAction() { + super.doCancelAction(); + myResult = null; + } + + public MavenProjectsStructure.GoalNode getResult() { + return myResult; + } +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenKeymapExtension.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenKeymapExtension.java index 5e8c36aa14e5..8aab5102533e 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenKeymapExtension.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenKeymapExtension.java @@ -15,13 +15,22 @@ */ package org.jetbrains.idea.maven.tasks; +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.keymap.KeymapExtension; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemKeymapExtension; import com.intellij.openapi.keymap.KeymapGroup; import com.intellij.openapi.keymap.KeymapGroupFactory; +import com.intellij.openapi.keymap.impl.ui.Group; +import com.intellij.openapi.keymap.impl.ui.Hyperlink; +import com.intellij.openapi.keymap.impl.ui.KeymapListener; +import com.intellij.openapi.keymap.impl.ui.KeymapPanel; +import com.intellij.openapi.options.ex.Settings; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.SystemInfoRt; import icons.MavenIcons; import org.jetbrains.annotations.TestOnly; import org.jetbrains.idea.maven.execution.MavenRunConfigurationType; @@ -29,6 +38,8 @@ import org.jetbrains.idea.maven.execution.MavenRunnerParameters; import org.jetbrains.idea.maven.model.MavenConstants; import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.model.MavenPlugin; +import org.jetbrains.idea.maven.navigator.MavenProjectsStructure; +import org.jetbrains.idea.maven.navigator.SelectMavenGoalDialog; import org.jetbrains.idea.maven.project.MavenProject; import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.utils.MavenArtifactUtil; @@ -36,13 +47,17 @@ import org.jetbrains.idea.maven.utils.MavenPluginInfo; import org.jetbrains.idea.maven.utils.actions.MavenAction; import org.jetbrains.idea.maven.utils.actions.MavenActionUtil; +import javax.swing.*; +import java.awt.event.MouseEvent; import java.io.File; import java.util.*; -public class MavenKeymapExtension implements KeymapExtension { - public KeymapGroup createGroup(Condition condition, Project project) { +public class MavenKeymapExtension implements ExternalSystemKeymapExtension.ActionsProvider { + + @Override + public KeymapGroup createGroup(Condition condition, final Project project) { KeymapGroup result = KeymapGroupFactory.getInstance().createGroup(TasksBundle.message("maven.tasks.action.group.name"), - MavenIcons.PhasesClosed + MavenIcons.MavenLogo ); if (project == null) return result; @@ -83,18 +98,35 @@ public class MavenKeymapExtension implements KeymapExtension { } for (Map.Entry>> each : projectToActionsMapping.entrySet()) { - MavenProject mavenProject = each.getKey(); Set> goalsToActionIds = each.getValue(); - if (goalsToActionIds.isEmpty()) continue; - KeymapGroup group = KeymapGroupFactory.getInstance().createGroup(mavenProject.getDisplayName(), - MavenIcons.PhasesClosed - ); - result.addGroup(group); for (Pair eachGoalToActionId : goalsToActionIds) { - group.addActionId(eachGoalToActionId.getSecond()); + result.addActionId(eachGoalToActionId.getSecond()); } } + Icon icon = SystemInfoRt.isMac ? AllIcons.ToolbarDecorator.Mac.Add : AllIcons.ToolbarDecorator.Add; + ((Group)result).addHyperlink(new Hyperlink(icon, "Choose a phase/goal to assign a shortcut") { + @Override + public void onClick(MouseEvent e) { + SelectMavenGoalDialog dialog = new SelectMavenGoalDialog(project); + if (dialog.showAndGet() && dialog.getResult() != null) { + MavenProjectsStructure.GoalNode goalNode = dialog.getResult(); + String goal = goalNode.getGoal(); + String actionId = MavenShortcutsManager.getInstance(project).getActionId(goalNode.getProjectPath(), goal); + getOrRegisterAction(goalNode.getMavenProject(), actionId, goal); + + ApplicationManager.getApplication().getMessageBus().syncPublisher(KeymapListener.CHANGE_TOPIC).processCurrentKeymapChanged(); + Settings allSettings = Settings.KEY.getData(DataManager.getInstance().getDataContext(e.getComponent())); + KeymapPanel keymapPanel = allSettings != null ? allSettings.find(KeymapPanel.class) : null; + if (keymapPanel != null) { + // clear actions filter + keymapPanel.showOption(""); + keymapPanel.selectAction(actionId); + } + } + } + }); + return result; } @@ -103,9 +135,14 @@ public class MavenKeymapExtension implements KeymapExtension { createActions(project, mavenProjects); } - public static MavenAction registerAction(MavenProject mavenProject, String actionId, String goal) { + public static MavenAction getOrRegisterAction(MavenProject mavenProject, String actionId, String goal) { MavenGoalAction mavenGoalAction = new MavenGoalAction(mavenProject, goal); ActionManager manager = ActionManager.getInstance(); + AnAction anAction = manager.getAction(actionId); + if (anAction instanceof MavenGoalAction) { + return (MavenGoalAction)anAction; + } + manager.unregisterAction(actionId); manager.registerAction(actionId, mavenGoalAction); return mavenGoalAction; } @@ -186,7 +223,7 @@ public class MavenKeymapExtension implements KeymapExtension { myMavenProject = mavenProject; myGoal = goal; Presentation template = getTemplatePresentation(); - template.setText(goal, false); + template.setText(goal + " (" + mavenProject.getMavenId() + ")", false); template.setIcon(MavenIcons.Phase); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/actions/AssignShortcutAction.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/actions/AssignShortcutAction.java index 0a513781bded..d501870e1afb 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/actions/AssignShortcutAction.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/actions/AssignShortcutAction.java @@ -72,7 +72,7 @@ public class AssignShortcutAction extends MavenAction { if (actionId != null) { AnAction action = ActionManager.getInstance().getAction(actionId); if (action == null) { - MavenKeymapExtension.registerAction(project, actionId, goal); + MavenKeymapExtension.getOrRegisterAction(project, actionId, goal); } } return actionId; diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index f4f961c4c834..c65bb94f22d8 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -63,7 +63,7 @@ - + diff --git a/plugins/maven/src/main/resources/TasksBundle.properties b/plugins/maven/src/main/resources/TasksBundle.properties index b57bea5ddee9..d00bc5b29dcd 100644 --- a/plugins/maven/src/main/resources/TasksBundle.properties +++ b/plugins/maven/src/main/resources/TasksBundle.properties @@ -9,6 +9,6 @@ maven.tasks.goal.after.rebuild=After Rebuild maven.tasks.goal.before.run=Before Run maven.tasks.select.goal.title=Select Maven Goal -maven.tasks.action.group.name=Maven Goals +maven.tasks.action.group.name=Maven maven.tasks.executing=Executing Maven Goal \ No newline at end of file diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/tasks/MavenShortcutsManagerTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/tasks/MavenShortcutsManagerTest.java index abd7887379cb..faddaabd7596 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/tasks/MavenShortcutsManagerTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/tasks/MavenShortcutsManagerTest.java @@ -245,7 +245,7 @@ public class MavenShortcutsManagerTest extends MavenImportingTestCase { assert actionId != null; AnAction action = ActionManager.getInstance().getAction(actionId); if (action == null) { - MavenKeymapExtension.registerAction(mavenProject, actionId, goal); + MavenKeymapExtension.getOrRegisterAction(mavenProject, actionId, goal); } Keymap activeKeymap = KeymapManager.getInstance().getActiveKeymap(); activeKeymap.addShortcut(actionId, KeyboardShortcut.fromString(shortcut));