mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-155345 Add run/stop/edit and grouping actions for runtime dashboard tool window
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.execution.dashboard;
|
||||
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.content.Content;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -23,5 +25,14 @@ import org.jetbrains.annotations.Nullable;
|
||||
*/
|
||||
public interface DashboardNode {
|
||||
@Nullable
|
||||
Content getContent();
|
||||
default RunContentDescriptor getDescriptor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
default Content getContent() {
|
||||
return getDescriptor() == null ? null : getDescriptor().getAttachedContent();
|
||||
}
|
||||
|
||||
Project getProject();
|
||||
}
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard;
|
||||
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public interface DashboardRunConfigurationNode extends DashboardNode {
|
||||
@NotNull
|
||||
RunnerAndConfigurationSettings getConfigurationSettings();
|
||||
|
||||
boolean isTerminated();
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard;
|
||||
|
||||
import com.intellij.ide.util.treeView.AbstractTreeBuilder;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public abstract class DashboardTreeAction<T, C extends TreeContent> extends AnAction {
|
||||
protected DashboardTreeAction(String text, String description, Icon icon) {
|
||||
super(text, description, icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
Presentation presentation = e.getPresentation();
|
||||
List<T> targetNodes = getTargetNodes(e);
|
||||
|
||||
boolean visible;
|
||||
boolean enabled;
|
||||
|
||||
if (targetNodes == null) {
|
||||
visible = false;
|
||||
enabled = false;
|
||||
}
|
||||
else {
|
||||
visible = true;
|
||||
enabled = true;
|
||||
for (T targetNode : targetNodes) {
|
||||
visible &= isVisible4(targetNode);
|
||||
enabled &= visible && isEnabled4(targetNode);
|
||||
}
|
||||
}
|
||||
|
||||
presentation.setVisible(visible);
|
||||
presentation.setEnabled(enabled);
|
||||
updatePresentation(presentation, ContainerUtil.getFirstItem(targetNodes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link #collectNodes(AbstractTreeBuilder) collectNodes()} to collect nodes.
|
||||
* If each collected node could be casted to tree action node class,
|
||||
* returns a list of collected nodes casted to tree action node class, otherwise returns {@code null}.
|
||||
*
|
||||
* @param e Action event.
|
||||
* @return List of target nodes for this action.
|
||||
*/
|
||||
@Nullable
|
||||
protected List<T> getTargetNodes(AnActionEvent e) {
|
||||
C content = getTreeContent(e);
|
||||
if (content == null) {
|
||||
return null;
|
||||
}
|
||||
Set<?> selectedElements = collectNodes(content.getBuilder());
|
||||
int selectionCount = selectedElements.size();
|
||||
if (selectionCount == 0 || selectionCount > 1 && !isMultiSelectionAllowed()) {
|
||||
return null;
|
||||
}
|
||||
Class<T> targetNodeClass = getTargetNodeClass();
|
||||
List<T> result = new ArrayList<>();
|
||||
for (Object selectedElement : selectedElements) {
|
||||
if (!targetNodeClass.isInstance(selectedElement)) {
|
||||
return null;
|
||||
}
|
||||
result.add(targetNodeClass.cast(selectedElement));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns a set of selected nodes.
|
||||
* Subclasses may override this method to return modified nodes set.
|
||||
*
|
||||
* @param treeBuilder Tree builder.
|
||||
* @return Set of tree nodes for which action should be performed.
|
||||
*/
|
||||
@NotNull
|
||||
protected Set<?> collectNodes(@NotNull AbstractTreeBuilder treeBuilder) {
|
||||
return treeBuilder.getSelectedElements();
|
||||
}
|
||||
|
||||
protected abstract C getTreeContent(AnActionEvent e);
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
List<T> targetNodes = getTargetNodes(e);
|
||||
if (targetNodes == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<T> verifiedTargetNodes = ContainerUtil.filter(targetNodes, targetNode -> isVisible4(targetNode) && isEnabled4(targetNode));
|
||||
doActionPerformed(getTreeContent(e), e, verifiedTargetNodes);
|
||||
}
|
||||
|
||||
protected boolean isMultiSelectionAllowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isVisible4(T node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isEnabled4(T node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void updatePresentation(@NotNull Presentation presentation, @Nullable T node) {
|
||||
}
|
||||
|
||||
protected void doActionPerformed(@NotNull C content, AnActionEvent e, List<T> nodes) {
|
||||
for (T node : nodes) {
|
||||
doActionPerformed(content, e, node);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doActionPerformed(@NotNull C content, AnActionEvent e, T node) {
|
||||
doActionPerformed(node);
|
||||
}
|
||||
|
||||
protected void doActionPerformed(T node) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected abstract Class<T> getTargetNodeClass();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public interface Group {
|
||||
String getName();
|
||||
|
||||
Icon getIcon();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard;
|
||||
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import com.intellij.ide.util.treeView.smartTree.TreeAction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Action for grouping items in a runtime dashboard tree.
|
||||
*
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public interface GroupingRule extends TreeAction {
|
||||
/**
|
||||
* @return A list of groups which should be shown in the tree even if they do not contain any nodes.
|
||||
*/
|
||||
@NotNull
|
||||
default List<Group> getPermanentGroups() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node Node which should be grouped by this grouping rule.
|
||||
* @return A group which node belongs to or null if node could not be grouped by this rule.
|
||||
*/
|
||||
@Nullable
|
||||
Group getGroup(AbstractTreeNode<?> node);
|
||||
}
|
||||
@@ -44,10 +44,11 @@ class PanelContentUI implements ContentUI {
|
||||
manager.addContentManagerListener(new ContentManagerAdapter() {
|
||||
@Override
|
||||
public void selectionChanged(final ContentManagerEvent event) {
|
||||
if (ContentManagerEvent.ContentOperation.add != event.getOperation()) {
|
||||
return;
|
||||
if (ContentManagerEvent.ContentOperation.add == event.getOperation()) {
|
||||
showContent(event.getContent());
|
||||
} else if (ContentManagerEvent.ContentOperation.remove == event.getOperation()) {
|
||||
hideContent();
|
||||
}
|
||||
showContent(event.getContent());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -63,6 +64,12 @@ class PanelContentUI implements ContentUI {
|
||||
}
|
||||
}
|
||||
|
||||
private void hideContent() {
|
||||
myPanel.removeAll();
|
||||
myPanel.revalidate();
|
||||
myPanel.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleSelection() {
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard;
|
||||
|
||||
import com.intellij.ide.util.treeView.AbstractTreeBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public interface TreeContent {
|
||||
@NotNull
|
||||
AbstractTreeBuilder getBuilder();
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.ExecutionManager;
|
||||
import com.intellij.execution.KillableProcess;
|
||||
import com.intellij.execution.configurations.RunProfile;
|
||||
import com.intellij.execution.impl.ExecutionManagerImpl;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
import com.intellij.icons.AllIcons;
|
||||
@@ -124,7 +125,7 @@ class StopAction extends DumbAwareAction implements AnAction.TransparentUpdate {
|
||||
int todoSize = cancellableProcesses.size() + stoppableDescriptors.size();
|
||||
if (todoSize == 1) {
|
||||
if (!stoppableDescriptors.isEmpty()) {
|
||||
stopProcess(stoppableDescriptors.get(0));
|
||||
ExecutionManagerImpl.stopProcess(stoppableDescriptors.get(0));
|
||||
} else {
|
||||
cancellableProcesses.get(0).second.cancel();
|
||||
}
|
||||
@@ -182,12 +183,12 @@ class StopAction extends DumbAwareAction implements AnAction.TransparentUpdate {
|
||||
}
|
||||
}
|
||||
else {
|
||||
stopProcess(getRecentlyStartedContentDescriptor(dataContext));
|
||||
ExecutionManagerImpl.stopProcess(getRecentlyStartedContentDescriptor(dataContext));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<Pair<TaskInfo, ProgressIndicator>> getCancellableProcesses(@Nullable Project project) {
|
||||
private static List<Pair<TaskInfo, ProgressIndicator>> getCancellableProcesses(@Nullable Project project) {
|
||||
IdeFrame frame = ((WindowManagerEx)WindowManager.getInstance()).findFrameFor(project);
|
||||
StatusBarEx statusBar = frame == null ? null : (StatusBarEx)frame.getStatusBar();
|
||||
if (statusBar == null) return Collections.emptyList();
|
||||
@@ -212,7 +213,7 @@ class StopAction extends DumbAwareAction implements AnAction.TransparentUpdate {
|
||||
HandlerItem item = new HandlerItem(descriptor.getDisplayName(), descriptor.getIcon(), false) {
|
||||
@Override
|
||||
void stop() {
|
||||
stopProcess(descriptor);
|
||||
ExecutionManagerImpl.stopProcess(descriptor);
|
||||
}
|
||||
};
|
||||
items.add(item);
|
||||
@@ -235,22 +236,6 @@ class StopAction extends DumbAwareAction implements AnAction.TransparentUpdate {
|
||||
return Pair.create(items, selected);
|
||||
}
|
||||
|
||||
private static void stopProcess(@Nullable RunContentDescriptor descriptor) {
|
||||
ProcessHandler processHandler = descriptor != null ? descriptor.getProcessHandler() : null;
|
||||
if (processHandler == null) return;
|
||||
if (processHandler instanceof KillableProcess && processHandler.isProcessTerminating()) {
|
||||
((KillableProcess)processHandler).killProcess();
|
||||
return;
|
||||
}
|
||||
|
||||
if (processHandler.detachIsDefault()) {
|
||||
processHandler.detachProcess();
|
||||
}
|
||||
else {
|
||||
processHandler.destroyProcess();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static RunContentDescriptor getRecentlyStartedContentDescriptor(@NotNull DataContext dataContext) {
|
||||
final RunContentDescriptor contentDescriptor = LangDataKeys.RUN_CONTENT_DESCRIPTOR.getData(dataContext);
|
||||
|
||||
+118
-11
@@ -16,24 +16,30 @@
|
||||
package com.intellij.execution.dashboard;
|
||||
|
||||
import com.intellij.execution.*;
|
||||
import com.intellij.execution.dashboard.tree.Grouper;
|
||||
import com.intellij.execution.dashboard.tree.RuntimeDashboardTreeStructure;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.ide.CommonActionsManager;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.DefaultTreeExpander;
|
||||
import com.intellij.ide.TreeExpander;
|
||||
import com.intellij.ide.util.treeView.*;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentation;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Splitter;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.ui.OnePixelSplitter;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.ui.SideBorder;
|
||||
import com.intellij.ui.TreeSpeedSearch;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBPanelWithEmptyText;
|
||||
import com.intellij.ui.content.*;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -44,12 +50,18 @@ import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import java.awt.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
class RuntimeDashboardContent extends JPanel implements Disposable {
|
||||
public class RuntimeDashboardContent extends JPanel implements TreeContent, Disposable {
|
||||
public static final DataKey<RuntimeDashboardContent> KEY = DataKey.create("runtimeDashboardContent");
|
||||
@NonNls private static final String PLACE_TOOLBAR = "RuntimeDashboardContent#Toolbar";
|
||||
@NonNls private static final String RUNTIME_DASHBOARD_TOOLBAR = "RuntimeDashboardToolbar";
|
||||
@NonNls private static final String RUNTIME_DASHBOARD_POPUP = "RuntimeDashboardPopup";
|
||||
|
||||
private static final String MESSAGE_CARD = "message";
|
||||
private static final String CONTENT_CARD = "content";
|
||||
|
||||
@@ -62,15 +74,17 @@ class RuntimeDashboardContent extends JPanel implements Disposable {
|
||||
private AbstractTreeBuilder myBuilder;
|
||||
private AbstractTreeNode<?> myLastSelection;
|
||||
private Set<Object> myCollapsedTreeNodeValues = new HashSet<>();
|
||||
private List<Grouper> myGroupers;
|
||||
|
||||
@NotNull private final ContentManager myContentManager;
|
||||
@NotNull private final ContentManagerListener myContentManagerListener;
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
|
||||
public RuntimeDashboardContent(@NotNull Project project, @NotNull ContentManager contentManager) {
|
||||
public RuntimeDashboardContent(@NotNull Project project, @NotNull ContentManager contentManager, @NotNull List<Grouper> groupers) {
|
||||
super(new BorderLayout());
|
||||
myProject = project;
|
||||
myGroupers = groupers;
|
||||
|
||||
myTreeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
|
||||
myTree = new Tree(myTreeModel);
|
||||
@@ -80,7 +94,7 @@ class RuntimeDashboardContent extends JPanel implements Disposable {
|
||||
myTree.setCellRenderer(new NodeRenderer());
|
||||
myTree.setLineStyleAngled();
|
||||
|
||||
//TODO [konstantin.aleev] Create toolbar.
|
||||
add(createToolbar(), BorderLayout.WEST);
|
||||
|
||||
Splitter splitter = new OnePixelSplitter(false, 0.3f);
|
||||
splitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myTree, SideBorder.LEFT));
|
||||
@@ -146,7 +160,10 @@ class RuntimeDashboardContent extends JPanel implements Disposable {
|
||||
}
|
||||
});
|
||||
|
||||
//TODO [konstantin.aleev] setup popup actions.
|
||||
DefaultActionGroup popupActionGroup = new DefaultActionGroup();
|
||||
popupActionGroup.add(ActionManager.getInstance().getAction(RUNTIME_DASHBOARD_TOOLBAR));
|
||||
popupActionGroup.add(ActionManager.getInstance().getAction(RUNTIME_DASHBOARD_POPUP));
|
||||
PopupHandler.installPopupHandler(myTree, popupActionGroup, ActionPlaces.UNKNOWN, ActionManager.getInstance());
|
||||
|
||||
new TreeSpeedSearch(myTree, TreeSpeedSearch.NODE_DESCRIPTOR_TOSTRING, true);
|
||||
}
|
||||
@@ -198,7 +215,7 @@ class RuntimeDashboardContent extends JPanel implements Disposable {
|
||||
}
|
||||
|
||||
private void setupBuilder() {
|
||||
RuntimeDashboardTreeStructure structure = new RuntimeDashboardTreeStructure(myProject);
|
||||
RuntimeDashboardTreeStructure structure = new RuntimeDashboardTreeStructure(myProject, myGroupers);
|
||||
myBuilder = new AbstractTreeBuilder(myTree, myTreeModel, structure, IndexComparator.INSTANCE) {
|
||||
@Override
|
||||
protected boolean isAutoExpandNode(NodeDescriptor nodeDescriptor) {
|
||||
@@ -231,7 +248,10 @@ class RuntimeDashboardContent extends JPanel implements Disposable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processTerminated(@NotNull String executorId, @NotNull ExecutionEnvironment env, @NotNull ProcessHandler handler, int exitCode) {
|
||||
public void processTerminated(@NotNull String executorId,
|
||||
@NotNull ExecutionEnvironment env,
|
||||
@NotNull ProcessHandler handler,
|
||||
int exitCode) {
|
||||
updateTreeIfNeeded(env.getRunnerAndConfigurationSettings());
|
||||
}
|
||||
});
|
||||
@@ -243,11 +263,98 @@ class RuntimeDashboardContent extends JPanel implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private JComponent createToolbar() {
|
||||
JPanel toolBarPanel = new JPanel(new GridLayout());
|
||||
DefaultActionGroup leftGroup = new DefaultActionGroup();
|
||||
leftGroup.add(ActionManager.getInstance().getAction(RUNTIME_DASHBOARD_TOOLBAR));
|
||||
// TODO [konstantin.aleev] provide context help ID
|
||||
//leftGroup.add(new Separator());
|
||||
//leftGroup.add(new ContextHelpAction(HELP_ID));
|
||||
|
||||
ActionToolbar leftActionToolBar = ActionManager.getInstance().createActionToolbar(PLACE_TOOLBAR, leftGroup, false);
|
||||
toolBarPanel.add(leftActionToolBar.getComponent());
|
||||
|
||||
myTree.putClientProperty(DataManager.CLIENT_PROPERTY_DATA_PROVIDER, new DataProvider() {
|
||||
@Override
|
||||
public Object getData(@NonNls String dataId) {
|
||||
if (KEY.getName().equals(dataId)) {
|
||||
return RuntimeDashboardContent.this;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
leftActionToolBar.setTargetComponent(myTree);
|
||||
|
||||
DefaultActionGroup rightGroup = new DefaultActionGroup();
|
||||
|
||||
TreeExpander treeExpander = new DefaultTreeExpander(myTree);
|
||||
AnAction expandAllAction = CommonActionsManager.getInstance().createExpandAllAction(treeExpander, this);
|
||||
rightGroup.add(expandAllAction);
|
||||
|
||||
AnAction collapseAllAction = CommonActionsManager.getInstance().createCollapseAllAction(treeExpander, this);
|
||||
rightGroup.add(collapseAllAction);
|
||||
|
||||
rightGroup.add(new Separator());
|
||||
myGroupers.forEach(grouper -> rightGroup.add(new GroupAction(grouper)));
|
||||
|
||||
ActionToolbar rightActionToolBar = ActionManager.getInstance().createActionToolbar(PLACE_TOOLBAR, rightGroup, false);
|
||||
toolBarPanel.add(rightActionToolBar.getComponent());
|
||||
rightActionToolBar.setTargetComponent(myTree);
|
||||
return toolBarPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
public void updateTree() {
|
||||
ApplicationManager.getApplication().invokeLater(myBuilder::queueUpdate, myProject.getDisposed());
|
||||
ApplicationManager.getApplication().invokeLater(() -> myBuilder.queueUpdate().doWhenDone(() -> {
|
||||
// Remove nodes not presented in the tree from collapsed node values set.
|
||||
// Children retrieving is quick since grouping and run configuration nodes are already constructed.
|
||||
Set<Object> nodes = new HashSet<>();
|
||||
myBuilder.accept(AbstractTreeNode.class, new TreeVisitor<AbstractTreeNode>() {
|
||||
@Override
|
||||
public boolean visit(@NotNull AbstractTreeNode node) {
|
||||
nodes.add(node.getValue());
|
||||
return false;
|
||||
}
|
||||
});
|
||||
myCollapsedTreeNodeValues.retainAll(nodes);
|
||||
}), myProject.getDisposed());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AbstractTreeBuilder getBuilder() {
|
||||
return myBuilder;
|
||||
}
|
||||
|
||||
private class GroupAction extends ToggleAction implements DumbAware {
|
||||
private Grouper myGrouper;
|
||||
|
||||
public GroupAction(Grouper grouper) {
|
||||
super();
|
||||
myGrouper = grouper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
super.update(e);
|
||||
Presentation presentation = e.getPresentation();
|
||||
ActionPresentation actionPresentation = myGrouper.getRule().getPresentation();
|
||||
presentation.setText(actionPresentation.getText());
|
||||
presentation.setDescription(actionPresentation.getDescription());
|
||||
presentation.setIcon(actionPresentation.getIcon());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
return myGrouper.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
myGrouper.setEnabled(state);
|
||||
updateTree();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+64
-2
@@ -15,8 +15,16 @@
|
||||
*/
|
||||
package com.intellij.execution.dashboard;
|
||||
|
||||
import com.intellij.execution.dashboard.tree.ConfigurationTypeGroupingRule;
|
||||
import com.intellij.execution.dashboard.tree.FolderGroupingRule;
|
||||
import com.intellij.execution.dashboard.tree.Grouper;
|
||||
import com.intellij.execution.dashboard.tree.StatusGroupingRule;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.components.StoragePathMacros;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
@@ -28,16 +36,30 @@ import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentFactory;
|
||||
import com.intellij.ui.content.ContentManager;
|
||||
import com.intellij.ui.content.ContentUI;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class RuntimeDashboardManagerImpl implements RuntimeDashboardManager {
|
||||
@State(
|
||||
name = "RuntimeDashboard",
|
||||
storages = @Storage(StoragePathMacros.WORKSPACE_FILE)
|
||||
)
|
||||
public class RuntimeDashboardManagerImpl implements RuntimeDashboardManager, PersistentStateComponent<Element> {
|
||||
@NonNls private static final String GROUPERS_TAG = "groupers";
|
||||
@NonNls private static final String GROUPER_TAG = "grouper";
|
||||
@NonNls private static final String NAME_ATTR = "name";
|
||||
@NonNls private static final String ENABLED_ATTR = "enabled";
|
||||
|
||||
@NotNull private final ContentManager myContentManager;
|
||||
private List<Grouper> myGroupers = new ArrayList<>();
|
||||
|
||||
public RuntimeDashboardManagerImpl(@NotNull final Project project) {
|
||||
ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
|
||||
@@ -49,7 +71,11 @@ public class RuntimeDashboardManagerImpl implements RuntimeDashboardManager {
|
||||
project, true);
|
||||
toolWindow.setIcon(getToolWindowIcon());
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
RuntimeDashboardContent dashboardContent = new RuntimeDashboardContent(project, myContentManager);
|
||||
myGroupers.add(new Grouper(new ConfigurationTypeGroupingRule()));
|
||||
myGroupers.add(new Grouper(new StatusGroupingRule()));
|
||||
myGroupers.add(new Grouper(new FolderGroupingRule()));
|
||||
|
||||
RuntimeDashboardContent dashboardContent = new RuntimeDashboardContent(project, myContentManager, myGroupers);
|
||||
Content content = contentFactory.createContent(dashboardContent, null, false);
|
||||
Disposer.register(content, dashboardContent);
|
||||
toolWindow.getContentManager().addContent(content);
|
||||
@@ -76,4 +102,40 @@ public class RuntimeDashboardManagerImpl implements RuntimeDashboardManager {
|
||||
public Icon getToolWindowIcon() {
|
||||
return AllIcons.Toolwindows.ToolWindowRun; // TODO [konstantin.aleev] provide new icon
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Element getState() {
|
||||
final Element element = new Element("state");
|
||||
final Element groupers = new Element(GROUPERS_TAG);
|
||||
element.addContent(groupers);
|
||||
myGroupers.forEach(grouper -> groupers.addContent(writeGrouperState(grouper)));
|
||||
return element;
|
||||
}
|
||||
|
||||
private static Element writeGrouperState(Grouper grouper) {
|
||||
Element element = new Element(GROUPER_TAG);
|
||||
element.setAttribute(NAME_ATTR, grouper.getRule().getName());
|
||||
element.setAttribute(ENABLED_ATTR, Boolean.toString(grouper.isEnabled()));
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(Element element) {
|
||||
Element groupersElement = element.getChild(GROUPERS_TAG);
|
||||
if (groupersElement != null) {
|
||||
List<Element> groupers = groupersElement.getChildren(GROUPER_TAG);
|
||||
groupers.forEach(this::readGrouperState);
|
||||
}
|
||||
}
|
||||
|
||||
private void readGrouperState(Element grouperElement) {
|
||||
String id = grouperElement.getAttributeValue(NAME_ATTR);
|
||||
for (Grouper grouper : myGroupers) {
|
||||
if (grouper.getRule().getName().equals(id)) {
|
||||
grouper.setEnabled(Boolean.valueOf(grouperElement.getAttributeValue(ENABLED_ATTR, "true")));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.actions;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.RunManagerEx;
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings;
|
||||
import com.intellij.execution.configuration.ConfigurationFactoryEx;
|
||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||
import com.intellij.execution.dashboard.DashboardRunConfigurationNode;
|
||||
import com.intellij.execution.impl.RunnerAndConfigurationSettingsImpl;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class CopyConfigurationAction extends RunConfigurationTreeAction {
|
||||
public CopyConfigurationAction() {
|
||||
super(ExecutionBundle.message("copy.configuration.action.name"),
|
||||
ExecutionBundle.message("copy.configuration.action.name"),
|
||||
PlatformIcons.COPY_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void doActionPerformed(DashboardRunConfigurationNode node) {
|
||||
RunManagerEx runManager = RunManagerEx.getInstanceEx(node.getProject());
|
||||
RunnerAndConfigurationSettings settings = node.getConfigurationSettings();
|
||||
|
||||
RunnerAndConfigurationSettings copiedSettings = ((RunnerAndConfigurationSettingsImpl)settings).clone();
|
||||
runManager.setUniqueNameIfNeed(copiedSettings);
|
||||
copiedSettings.setFolderName(settings.getFolderName());
|
||||
|
||||
final ConfigurationFactory factory = settings.getFactory();
|
||||
if (factory instanceof ConfigurationFactoryEx) {
|
||||
((ConfigurationFactoryEx)factory).onConfigurationCopied(settings.getConfiguration());
|
||||
}
|
||||
|
||||
runManager.addConfiguration(copiedSettings, runManager.isConfigurationShared(settings),
|
||||
runManager.getBeforeRunTasks(settings.getConfiguration()), false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.actions;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.ExecutorRegistry;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.wm.ToolWindowId;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class DebugAction extends ExecutorAction {
|
||||
public DebugAction() {
|
||||
super(ExecutionBundle.message("runtime.dashboard.debug.action.name"),
|
||||
ExecutionBundle.message("runtime.dashboard.debug.action.name"),
|
||||
AllIcons.Toolwindows.ToolWindowDebugger);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Executor getExecutor() {
|
||||
return ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.DEBUG);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.actions;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.dashboard.DashboardRunConfigurationNode;
|
||||
import com.intellij.execution.impl.RunDialog;
|
||||
import com.intellij.icons.AllIcons;
|
||||
|
||||
public class EditConfigurationAction extends RunConfigurationTreeAction {
|
||||
public EditConfigurationAction() {
|
||||
super(ExecutionBundle.message("runtime.dashboard.edit.configuration.action.name"),
|
||||
ExecutionBundle.message("runtime.dashboard.edit.configuration.action.name"),
|
||||
AllIcons.Actions.EditSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doActionPerformed(DashboardRunConfigurationNode node) {
|
||||
RunDialog.editConfiguration(node.getProject(), node.getConfigurationSettings(),
|
||||
ExecutionBundle.message("runtime.dashboard.edit.configuration.dialog.title"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.actions;
|
||||
|
||||
import com.intellij.execution.ExecutionManager;
|
||||
import com.intellij.execution.ExecutionTargetManager;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.ProgramRunnerUtil;
|
||||
import com.intellij.execution.dashboard.DashboardRunConfigurationNode;
|
||||
import com.intellij.execution.runners.ProgramRunner;
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public abstract class ExecutorAction extends RuntimeDashboardTreeLeafAction<DashboardRunConfigurationNode> {
|
||||
protected ExecutorAction(String text, String description, Icon icon) {
|
||||
super(text, description, icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled4(DashboardRunConfigurationNode node) {
|
||||
String executorId = getExecutor().getId();
|
||||
ProgramRunner runner = ProgramRunnerUtil.getRunner(executorId, node.getConfigurationSettings());
|
||||
return runner != null && runner.canRun(executorId, node.getConfigurationSettings().getConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doActionPerformed(DashboardRunConfigurationNode node) {
|
||||
RunContentDescriptor descriptor = node.getDescriptor();
|
||||
ExecutionManager.getInstance(node.getProject()).restartRunProfile(node.getProject(),
|
||||
getExecutor(),
|
||||
ExecutionTargetManager.getActiveTarget(node.getProject()),
|
||||
node.getConfigurationSettings(),
|
||||
descriptor == null ? null : descriptor.getProcessHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<DashboardRunConfigurationNode> getTargetNodeClass() {
|
||||
return DashboardRunConfigurationNode.class;
|
||||
}
|
||||
|
||||
protected abstract Executor getExecutor();
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.actions;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.RunManagerEx;
|
||||
import com.intellij.execution.dashboard.DashboardRunConfigurationNode;
|
||||
import com.intellij.execution.dashboard.RuntimeDashboardContent;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class RemoveConfigurationAction extends RunConfigurationTreeAction {
|
||||
public RemoveConfigurationAction() {
|
||||
super(ExecutionBundle.message("runtime.dashboard.remove.configuration.action.name"),
|
||||
ExecutionBundle.message("runtime.dashboard.remove.configuration.action.name"),
|
||||
AllIcons.General.Remove);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled4(DashboardRunConfigurationNode node) {
|
||||
return node.isTerminated();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isMultiSelectionAllowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doActionPerformed(@NotNull RuntimeDashboardContent content, AnActionEvent e, List<DashboardRunConfigurationNode> nodes) {
|
||||
if (Messages.showYesNoDialog((Project)null,
|
||||
ExecutionBundle.message("runtime.dashboard.remove.configuration.dialog.message"),
|
||||
ExecutionBundle.message("runtime.dashboard.remove.configuration.dialog.title"),
|
||||
Messages.getWarningIcon())
|
||||
!= Messages.YES) {
|
||||
return;
|
||||
}
|
||||
super.doActionPerformed(content, e, nodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doActionPerformed(DashboardRunConfigurationNode node) {
|
||||
RunManagerEx.getInstanceEx(node.getProject()).removeConfiguration(node.getConfigurationSettings());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.actions;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.executors.DefaultRunExecutor;
|
||||
import com.intellij.icons.AllIcons;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class RunAction extends ExecutorAction {
|
||||
public RunAction() {
|
||||
super(ExecutionBundle.message("runtime.dashboard.run.action.name"),
|
||||
ExecutionBundle.message("runtime.dashboard.run.action.name"),
|
||||
AllIcons.Toolwindows.ToolWindowRun);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Executor getExecutor() {
|
||||
return DefaultRunExecutor.getRunExecutorInstance();
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.actions;
|
||||
|
||||
import com.intellij.execution.dashboard.DashboardRunConfigurationNode;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public abstract class RunConfigurationTreeAction extends RuntimeDashboardTreeAction<DashboardRunConfigurationNode> {
|
||||
protected RunConfigurationTreeAction(String text, String description, Icon icon) {
|
||||
super(text, description, icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<DashboardRunConfigurationNode> getTargetNodeClass() {
|
||||
return DashboardRunConfigurationNode.class;
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.actions;
|
||||
|
||||
import com.intellij.execution.dashboard.*;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public abstract class RuntimeDashboardTreeAction<T extends DashboardNode> extends DashboardTreeAction<T, RuntimeDashboardContent> {
|
||||
protected RuntimeDashboardTreeAction(String text, String description, Icon icon) {
|
||||
super(text, description, icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final RuntimeDashboardContent getTreeContent(AnActionEvent e) {
|
||||
return e.getData(RuntimeDashboardContent.KEY);
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.actions;
|
||||
|
||||
import com.intellij.execution.dashboard.DashboardNode;
|
||||
import com.intellij.execution.dashboard.tree.GroupingNode;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeBuilder;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public abstract class RuntimeDashboardTreeLeafAction<T extends DashboardNode> extends RuntimeDashboardTreeAction<T> {
|
||||
protected RuntimeDashboardTreeLeafAction(String text, String description, Icon icon) {
|
||||
super(text, description, icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final boolean isMultiSelectionAllowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected Set<?> collectNodes(@NotNull AbstractTreeBuilder treeBuilder) {
|
||||
Set<Object> selectedElement = treeBuilder.getSelectedElements();
|
||||
List<AbstractTreeNode> nodes = new ArrayList<>();
|
||||
for (Object o : selectedElement) {
|
||||
if (!(o instanceof AbstractTreeNode)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
AbstractTreeNode node = (AbstractTreeNode)o;
|
||||
if (node instanceof GroupingNode && node.getChildren().isEmpty()) {
|
||||
// Action could not be performed if current selection contains empty grouping nodes
|
||||
return Collections.emptySet();
|
||||
}
|
||||
nodes.add(node);
|
||||
}
|
||||
return getLeaves(nodes);
|
||||
}
|
||||
|
||||
private static Set<AbstractTreeNode> getLeaves(Collection<? extends AbstractTreeNode> nodes) {
|
||||
Set<AbstractTreeNode> result = new HashSet<>();
|
||||
for (AbstractTreeNode<?> node : nodes) {
|
||||
Collection<? extends AbstractTreeNode> children = node.getChildren();
|
||||
if (children.isEmpty()) {
|
||||
if (!(node instanceof GroupingNode)) {
|
||||
// Do not add grouping nodes to the target set
|
||||
result.add(node);
|
||||
}
|
||||
} else {
|
||||
result.addAll(getLeaves(children));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.actions;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.dashboard.DashboardRunConfigurationNode;
|
||||
import com.intellij.execution.impl.ExecutionManagerImpl;
|
||||
import com.intellij.icons.AllIcons;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class StopAction extends RuntimeDashboardTreeLeafAction<DashboardRunConfigurationNode> {
|
||||
public StopAction() {
|
||||
super(ExecutionBundle.message("runtime.dashboard.stop.action.name"),
|
||||
ExecutionBundle.message("runtime.dashboard.stop.action.name"),
|
||||
AllIcons.Actions.Suspend);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doActionPerformed(DashboardRunConfigurationNode node) {
|
||||
ExecutionManagerImpl.stopProcess(node.getDescriptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<DashboardRunConfigurationNode> getTargetNodeClass() {
|
||||
return DashboardRunConfigurationNode.class;
|
||||
}
|
||||
}
|
||||
+7
-11
@@ -15,15 +15,14 @@
|
||||
*/
|
||||
package com.intellij.execution.dashboard.tree;
|
||||
|
||||
import com.intellij.execution.RunManagerEx;
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings;
|
||||
import com.intellij.execution.dashboard.DashboardNode;
|
||||
import com.intellij.execution.dashboard.DashboardRunConfigurationNode;
|
||||
import com.intellij.execution.dashboard.RuntimeDashboardContributor;
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
import com.intellij.ide.projectView.PresentationData;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.RowIcon;
|
||||
import com.intellij.ui.content.Content;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -32,7 +31,7 @@ import javax.swing.*;
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
abstract class AbstractRunConfigurationNode<T> extends AbstractTreeNode<T> implements DashboardNode {
|
||||
abstract class AbstractRunConfigurationNode<T> extends AbstractTreeNode<T> implements DashboardRunConfigurationNode {
|
||||
@NotNull private final RunnerAndConfigurationSettings myConfigurationSettings;
|
||||
|
||||
protected AbstractRunConfigurationNode(Project project, T value, @NotNull RunnerAndConfigurationSettings configurationSettings) {
|
||||
@@ -43,7 +42,7 @@ abstract class AbstractRunConfigurationNode<T> extends AbstractTreeNode<T> imple
|
||||
@Override
|
||||
protected void update(PresentationData presentation) {
|
||||
presentation.setPresentableText(myConfigurationSettings.getName());
|
||||
Icon icon = myConfigurationSettings.getConfiguration().getIcon();
|
||||
Icon icon = RunManagerEx.getInstanceEx(getProject()).getConfigurationIcon(myConfigurationSettings);
|
||||
Icon decorator = getIconDecorator();
|
||||
if (decorator != null) {
|
||||
icon = new RowIcon(icon, decorator);
|
||||
@@ -56,14 +55,11 @@ abstract class AbstractRunConfigurationNode<T> extends AbstractTreeNode<T> imple
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Content getContent() {
|
||||
return getDescriptor() == null ? null : getDescriptor().getAttachedContent();
|
||||
@NotNull
|
||||
public RunnerAndConfigurationSettings getConfigurationSettings() {
|
||||
return myConfigurationSettings;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract Icon getIconDecorator();
|
||||
|
||||
@Nullable
|
||||
protected abstract RunContentDescriptor getDescriptor();
|
||||
}
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.tree;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings;
|
||||
import com.intellij.execution.configurations.ConfigurationType;
|
||||
import com.intellij.execution.dashboard.Group;
|
||||
import com.intellij.execution.dashboard.GroupingRule;
|
||||
import com.intellij.execution.dashboard.DashboardRunConfigurationNode;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentation;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentationData;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class ConfigurationTypeGroupingRule implements GroupingRule {
|
||||
@NonNls private static final String NAME = "TypeGroupingRule";
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ActionPresentation getPresentation() {
|
||||
return new ActionPresentationData(ExecutionBundle.message("runtime.dashboard.group.by.type.action.name"),
|
||||
ExecutionBundle.message("runtime.dashboard.group.by.type.action.name"),
|
||||
AllIcons.Actions.GroupByFile);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Group getGroup(AbstractTreeNode<?> node) {
|
||||
if (node instanceof DashboardRunConfigurationNode) {
|
||||
RunnerAndConfigurationSettings configurationSettings = ((DashboardRunConfigurationNode)node).getConfigurationSettings();
|
||||
ConfigurationType type = configurationSettings.getType();
|
||||
if (type != null) {
|
||||
return new GroupImpl<>(type, type.getDisplayName(), type.getIcon());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.tree;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings;
|
||||
import com.intellij.execution.dashboard.Group;
|
||||
import com.intellij.execution.dashboard.GroupingRule;
|
||||
import com.intellij.execution.dashboard.DashboardRunConfigurationNode;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentation;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentationData;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class FolderGroupingRule implements GroupingRule {
|
||||
@NonNls private static final String NAME = "FolderGroupingRule";
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ActionPresentation getPresentation() {
|
||||
return new ActionPresentationData(ExecutionBundle.message("runtime.dashboard.group.by.folder.action.name"),
|
||||
ExecutionBundle.message("runtime.dashboard.group.by.folder.action.name"),
|
||||
AllIcons.Actions.GroupByPackage);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Group getGroup(AbstractTreeNode<?> node) {
|
||||
if (node instanceof DashboardRunConfigurationNode) {
|
||||
RunnerAndConfigurationSettings configurationSettings = ((DashboardRunConfigurationNode)node).getConfigurationSettings();
|
||||
String folderName = configurationSettings.getFolderName();
|
||||
if (folderName != null) {
|
||||
return new GroupImpl<>(folderName, folderName, AllIcons.Nodes.Folder);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.tree;
|
||||
|
||||
import com.intellij.execution.dashboard.Group;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class GroupImpl<T> implements Group {
|
||||
private final T myValue;
|
||||
private final String myName;
|
||||
private final Icon myIcon;
|
||||
|
||||
public GroupImpl(T value, String name, Icon icon) {
|
||||
myValue = value;
|
||||
myName = name;
|
||||
myIcon = icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return myIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myValue.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
if (obj instanceof GroupImpl) {
|
||||
return myValue.equals(((GroupImpl)obj).myValue);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.tree;
|
||||
|
||||
import com.intellij.execution.dashboard.GroupingRule;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class Grouper {
|
||||
@NotNull private final GroupingRule myRule;
|
||||
private boolean myEnabled = true;
|
||||
|
||||
public Grouper(@NotNull GroupingRule rule) {
|
||||
myRule = rule;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GroupingRule getRule() {
|
||||
return myRule;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return myEnabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
myEnabled = enabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.tree;
|
||||
|
||||
import com.intellij.execution.dashboard.DashboardNode;
|
||||
import com.intellij.execution.dashboard.Group;
|
||||
import com.intellij.ide.projectView.PresentationData;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class GroupingNode extends AbstractTreeNode<Pair<Object, Group>> implements DashboardNode {
|
||||
private final List<AbstractTreeNode> myChildren = new ArrayList<>();
|
||||
|
||||
public GroupingNode(Project project, Object parent, Group group) {
|
||||
super(project, Pair.create(parent, group));
|
||||
}
|
||||
|
||||
public Group getGroup() {
|
||||
//noinspection ConstantConditions ???
|
||||
return getValue().getSecond();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<? extends AbstractTreeNode> getChildren() {
|
||||
return myChildren;
|
||||
}
|
||||
|
||||
public void addChildren(Collection<? extends AbstractTreeNode> children) {
|
||||
myChildren.addAll(children);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void update(PresentationData presentation) {
|
||||
presentation.setPresentableText(getGroup().getName());
|
||||
presentation.setIcon(getGroup().getIcon());
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -77,10 +77,20 @@ class RunConfigurationNode extends AbstractRunConfigurationNode<RunnerAndConfigu
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected RunContentDescriptor getDescriptor() {
|
||||
public RunContentDescriptor getDescriptor() {
|
||||
if (myChildren.size() == 1) {
|
||||
return myChildren.get(0).getDescriptor();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTerminated() {
|
||||
for (RunDescriptorNode node : myChildren) {
|
||||
if (!node.isTerminated()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,9 @@ class RunDescriptorNode extends AbstractRunConfigurationNode<RunContentDescripto
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected RunContentDescriptor getDescriptor() {
|
||||
public RunContentDescriptor getDescriptor() {
|
||||
return getValue();
|
||||
}
|
||||
|
||||
@@ -62,4 +63,9 @@ class RunDescriptorNode extends AbstractRunConfigurationNode<RunContentDescripto
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTerminated() {
|
||||
return getContent() == null || RunContentManagerImpl.isTerminated(getContent());
|
||||
}
|
||||
}
|
||||
|
||||
+42
-8
@@ -16,6 +16,8 @@
|
||||
package com.intellij.execution.dashboard.tree;
|
||||
|
||||
import com.intellij.execution.RunManager;
|
||||
import com.intellij.execution.dashboard.Group;
|
||||
import com.intellij.execution.dashboard.GroupingRule;
|
||||
import com.intellij.execution.dashboard.RuntimeDashboardContributor;
|
||||
import com.intellij.ide.projectView.PresentationData;
|
||||
import com.intellij.ide.projectView.TreeStructureProvider;
|
||||
@@ -25,9 +27,7 @@ import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -35,11 +35,13 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class RuntimeDashboardTreeStructure extends AbstractTreeStructureBase {
|
||||
private final Project myProject;
|
||||
private final List<Grouper> myGroupers;
|
||||
private final RunConfigurationsTreeRootNode myRootElement;
|
||||
|
||||
public RuntimeDashboardTreeStructure(@NotNull Project project) {
|
||||
public RuntimeDashboardTreeStructure(@NotNull Project project, @NotNull List<Grouper> groupers) {
|
||||
super(project);
|
||||
myProject = project;
|
||||
myGroupers = groupers;
|
||||
myRootElement = new RunConfigurationsTreeRootNode();
|
||||
}
|
||||
|
||||
@@ -71,10 +73,13 @@ public class RuntimeDashboardTreeStructure extends AbstractTreeStructureBase {
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<? extends AbstractTreeNode> getChildren() {
|
||||
return RunManager.getInstance(myProject).getAllSettings().stream()
|
||||
.filter(runConfiguration -> RuntimeDashboardContributor.isShowInDashboard(runConfiguration.getType()))
|
||||
.map(runConfiguration -> new RunConfigurationNode(myProject, runConfiguration))
|
||||
.collect(Collectors.toList());
|
||||
return group(myProject,
|
||||
this,
|
||||
myGroupers.stream().filter(Grouper::isEnabled).map(Grouper::getRule).collect(Collectors.toList()),
|
||||
RunManager.getInstance(myProject).getAllSettings().stream()
|
||||
.filter(runConfiguration -> RuntimeDashboardContributor.isShowInDashboard(runConfiguration.getType()))
|
||||
.map(runConfiguration -> new RunConfigurationNode(myProject, runConfiguration))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,4 +87,33 @@ public class RuntimeDashboardTreeStructure extends AbstractTreeStructureBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static Collection<? extends AbstractTreeNode> group(final Project project, final AbstractTreeNode parent,
|
||||
List<GroupingRule> rules, List<AbstractTreeNode> nodes) {
|
||||
if (rules.isEmpty()) {
|
||||
return nodes;
|
||||
}
|
||||
final List<GroupingRule> remaining = new ArrayList<>(rules);
|
||||
GroupingRule rule = remaining.remove(0);
|
||||
Map<Group, List<AbstractTreeNode>> groups = nodes.stream().collect(
|
||||
HashMap::new,
|
||||
(map, node) -> map.computeIfAbsent(rule.getGroup(node), key -> new ArrayList<>()).add(node),
|
||||
(firstMap, secondMap) -> firstMap.forEach((key, value) -> value.addAll(secondMap.get(key)))
|
||||
);
|
||||
rule.getPermanentGroups().forEach(group -> groups.computeIfAbsent(group, key -> new ArrayList<>()));
|
||||
final List<AbstractTreeNode> result = new ArrayList<>();
|
||||
final List<AbstractTreeNode> ungroupedNodes = new ArrayList<>();
|
||||
groups.forEach((group, groupedNodes) -> {
|
||||
if (group == null) {
|
||||
ungroupedNodes.addAll(group(project, parent, remaining, groupedNodes));
|
||||
} else {
|
||||
GroupingNode node = new GroupingNode(project, parent.getValue(), group);
|
||||
node.addChildren(group(project, node, remaining, groupedNodes));
|
||||
result.add(node);
|
||||
}
|
||||
});
|
||||
|
||||
Collections.sort(result, Comparator.comparing(node -> ((GroupingNode)node).getGroup().getName()));
|
||||
result.addAll(ungroupedNodes);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.dashboard.tree;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.dashboard.Group;
|
||||
import com.intellij.execution.dashboard.GroupingRule;
|
||||
import com.intellij.execution.dashboard.DashboardRunConfigurationNode;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentation;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentationData;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author konstantin.aleev
|
||||
*/
|
||||
public class StatusGroupingRule implements GroupingRule {
|
||||
@NonNls private static final String NAME = "StatusGroupingRule";
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ActionPresentation getPresentation() {
|
||||
return new ActionPresentationData(ExecutionBundle.message("runtime.dashboard.group.by.status.action.name"),
|
||||
ExecutionBundle.message("runtime.dashboard.group.by.status.action.name"),
|
||||
AllIcons.Actions.GroupByPrefix); // TODO [konstantin.aleev] provide new icon
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Group> getPermanentGroups() {
|
||||
return Arrays.stream(Status.values()).map(Status::getGroup).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Group getGroup(AbstractTreeNode<?> node) {
|
||||
if (node instanceof DashboardRunConfigurationNode) {
|
||||
if (((DashboardRunConfigurationNode)node).isTerminated()) {
|
||||
return Status.STOPPED.getGroup();
|
||||
} else {
|
||||
return Status.STARTED.getGroup();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public enum Status {
|
||||
STARTED(ExecutionBundle.message("runtime.dashboard.started.group.name"), AllIcons.Toolwindows.ToolWindowRun),
|
||||
STOPPED(ExecutionBundle.message("runtime.dashboard.stopped.group.name"), AllIcons.Actions.Suspend);
|
||||
|
||||
private final String myLabel;
|
||||
private final Icon myIcon;
|
||||
|
||||
Status(String label, Icon icon) {
|
||||
myLabel = label;
|
||||
myIcon = icon;
|
||||
}
|
||||
|
||||
public Group getGroup() {
|
||||
return new GroupImpl<>(this, myLabel, myIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,7 +218,7 @@ public class ExecutionManagerImpl extends ExecutionManager implements Disposable
|
||||
Messages.getQuestionIcon(), option) == Messages.OK;
|
||||
}
|
||||
|
||||
private static void stop(@Nullable RunContentDescriptor descriptor) {
|
||||
public static void stopProcess(@Nullable RunContentDescriptor descriptor) {
|
||||
ProcessHandler processHandler = descriptor != null ? descriptor.getProcessHandler() : null;
|
||||
if (processHandler == null) {
|
||||
return;
|
||||
@@ -502,7 +502,7 @@ public class ExecutionManagerImpl extends ExecutionManager implements Disposable
|
||||
}
|
||||
|
||||
for (RunContentDescriptor descriptor : runningToStop) {
|
||||
stop(descriptor);
|
||||
stopProcess(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -376,3 +376,16 @@ sm.test.runner.magnitude.assertion.failed.title=Assertion failed
|
||||
sm.test.runner.magnitude.testerror.title=Error
|
||||
|
||||
runtime.dashboard.empty.selection.message=Select a node in the tree to view details
|
||||
runtime.dashboard.group.by.type.action.name=Group by Type
|
||||
runtime.dashboard.group.by.status.action.name=Group by Status
|
||||
runtime.dashboard.group.by.folder.action.name=Group by Folder
|
||||
runtime.dashboard.run.action.name=(Re)run
|
||||
runtime.dashboard.debug.action.name=(Re)run in Debug Mode
|
||||
runtime.dashboard.stop.action.name=Stop
|
||||
runtime.dashboard.edit.configuration.action.name=Edit Configuration
|
||||
runtime.dashboard.edit.configuration.dialog.title=Edit Run Configuration
|
||||
runtime.dashboard.remove.configuration.action.name=Remove Run Configuration
|
||||
runtime.dashboard.remove.configuration.dialog.title=Remove Run Configuration
|
||||
runtime.dashboard.remove.configuration.dialog.message=Are you sure to remove selected run configuration(s)?
|
||||
runtime.dashboard.started.group.name=Started
|
||||
runtime.dashboard.stopped.group.name=Stopped
|
||||
|
||||
@@ -58,7 +58,7 @@ tool.window.name.version.control=Version Control
|
||||
tool.window.name.module.dependencies=Module Dependencies
|
||||
tool.window.name.tasks=Time Tracking
|
||||
tool.window.name.database=Database
|
||||
tool.window.name.runtime.dashboard=Runtime Dashboard
|
||||
tool.window.name.runtime.dashboard=Run Dashboard
|
||||
tool.window.move.to.action.group.name=Move to
|
||||
tool.window.move.to.top.action.name=Top
|
||||
tool.window.move.to.left.action.name=Left
|
||||
|
||||
@@ -1016,5 +1016,15 @@
|
||||
<action id="DisableInspection" class="com.intellij.codeInspection.ui.actions.KeyAwareInspectionViewAction$DisableInspection"/>
|
||||
<action id="RunInspectionOn" class="com.intellij.codeInspection.ui.actions.KeyAwareInspectionViewAction$RunInspectionOn"/>
|
||||
</group>
|
||||
|
||||
<group id="RuntimeDashboardToolbar">
|
||||
<action id="RuntimeDashboard.Run" class="com.intellij.execution.dashboard.actions.RunAction"/>
|
||||
<action id="RuntimeDashboard.Debug" class="com.intellij.execution.dashboard.actions.DebugAction"/>
|
||||
<action id="RuntimeDashboard.Stop" class="com.intellij.execution.dashboard.actions.StopAction"/>
|
||||
<action id="RuntimeDashboard.EditConfiguration" class="com.intellij.execution.dashboard.actions.EditConfigurationAction"/>
|
||||
<action id="RuntimeDashboard.CopyConfiguration" class="com.intellij.execution.dashboard.actions.CopyConfigurationAction"/>
|
||||
<action id="RuntimeDashboard.RemoveConfiguration" class="com.intellij.execution.dashboard.actions.RemoveConfigurationAction"/>
|
||||
</group>
|
||||
<group id="RuntimeDashboardPopup"/>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
|
||||
+4
-1
@@ -1,5 +1,6 @@
|
||||
package com.intellij.remoteServer.impl.runtime.ui;
|
||||
|
||||
import com.intellij.execution.dashboard.TreeContent;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.actions.ContextHelpAction;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
@@ -45,7 +46,7 @@ import java.util.Set;
|
||||
/**
|
||||
* @author michael.golubev
|
||||
*/
|
||||
public class ServersToolWindowContent extends JPanel implements Disposable, ServersTreeNodeSelector {
|
||||
public class ServersToolWindowContent extends JPanel implements Disposable, ServersTreeNodeSelector, TreeContent {
|
||||
public static final DataKey<ServersToolWindowContent> KEY = DataKey.create("serversToolWindowContent");
|
||||
@NonNls private static final String PLACE_TOOLBAR = "ServersToolWindowContent#Toolbar";
|
||||
@NonNls private static final String SERVERS_TOOL_WINDOW_TOOLBAR = "RemoteServersViewToolbar";
|
||||
@@ -289,6 +290,8 @@ public class ServersToolWindowContent extends JPanel implements Disposable, Serv
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public TreeBuilderBase getBuilder() {
|
||||
return myBuilder;
|
||||
}
|
||||
|
||||
+4
-100
@@ -1,117 +1,21 @@
|
||||
package com.intellij.remoteServer.impl.runtime.ui.tree.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.execution.dashboard.DashboardTreeAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.remoteServer.impl.runtime.ui.ServersToolWindowContent;
|
||||
import com.intellij.remoteServer.impl.runtime.ui.tree.ServersTreeNode;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class ServersTreeAction<T extends ServersTreeNode> extends AnAction implements DumbAware {
|
||||
|
||||
public abstract class ServersTreeAction<T extends ServersTreeNode> extends DashboardTreeAction<T, ServersToolWindowContent>
|
||||
implements DumbAware {
|
||||
protected ServersTreeAction(String text, String description, Icon icon) {
|
||||
super(text, description, icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
Presentation presentation = e.getPresentation();
|
||||
List<T> targetNodes = getTargetNodes(e);
|
||||
|
||||
boolean visible;
|
||||
boolean enabled;
|
||||
|
||||
if (targetNodes == null) {
|
||||
visible = false;
|
||||
enabled = false;
|
||||
}
|
||||
else {
|
||||
visible = true;
|
||||
enabled = true;
|
||||
for (T targetNode : targetNodes) {
|
||||
visible &= isVisible4(targetNode);
|
||||
enabled &= visible && isEnabled4(targetNode);
|
||||
}
|
||||
}
|
||||
|
||||
presentation.setVisible(visible);
|
||||
presentation.setEnabled(enabled);
|
||||
updatePresentation(presentation, ContainerUtil.getFirstItem(targetNodes));
|
||||
}
|
||||
|
||||
private List<T> getTargetNodes(AnActionEvent e) {
|
||||
ServersToolWindowContent content = getContent(e);
|
||||
if (content == null) {
|
||||
return null;
|
||||
}
|
||||
Set<Object> selectedElements = content.getBuilder().getSelectedElements();
|
||||
int selectionCount = selectedElements.size();
|
||||
if (selectionCount == 0 || selectionCount > 1 && !isMultiSelectionAllowed()) {
|
||||
return null;
|
||||
}
|
||||
Class<T> targetNodeClass = getTargetNodeClass();
|
||||
List<T> result = new ArrayList<>();
|
||||
for (Object selectedElement : selectedElements) {
|
||||
ServersTreeNode node = (ServersTreeNode)selectedElement;
|
||||
if (!targetNodeClass.isInstance(node)) {
|
||||
return null;
|
||||
}
|
||||
result.add(targetNodeClass.cast(node));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ServersToolWindowContent getContent(AnActionEvent e) {
|
||||
protected final ServersToolWindowContent getTreeContent(AnActionEvent e) {
|
||||
return e.getData(ServersToolWindowContent.KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
List<T> targetNodes = getTargetNodes(e);
|
||||
if (targetNodes == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<T> verifiedTargetNodes = ContainerUtil.filter(targetNodes, targetNode -> isVisible4(targetNode) && isEnabled4(targetNode));
|
||||
doActionPerformed(getContent(e), e, verifiedTargetNodes);
|
||||
}
|
||||
|
||||
protected boolean isMultiSelectionAllowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isVisible4(T node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isEnabled4(T node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void updatePresentation(@NotNull Presentation presentation, @Nullable T node) {
|
||||
}
|
||||
|
||||
protected void doActionPerformed(@NotNull ServersToolWindowContent content, AnActionEvent e, List<T> nodes) {
|
||||
for (T node : nodes) {
|
||||
doActionPerformed(content, e, node);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doActionPerformed(@NotNull ServersToolWindowContent content, AnActionEvent e, T node) {
|
||||
doActionPerformed(node);
|
||||
}
|
||||
|
||||
protected void doActionPerformed(T node) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected abstract Class<T> getTargetNodeClass();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user