diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/Deployment.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/Deployment.java index 5c4f100e3da3..95be378ec6f4 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/Deployment.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/Deployment.java @@ -32,5 +32,9 @@ public interface Deployment { void setStatus(@NotNull DeploymentStatus status, @Nullable String statusText); + @NotNull ServerConnection getConnection(); + + @Nullable + String getGroup(); } diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java index 692dd7ecbd74..b2c989857820 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java @@ -30,6 +30,11 @@ public abstract class ServerRuntimeInstance { return source.getPresentableName(); } + @Nullable + public String getDeploymentGroup(@NotNull DeploymentSource source, D configuration) { + return null; + } + public abstract void disconnect(); public interface DeploymentOperationCallback extends RemoteOperationCallback { @@ -44,7 +49,8 @@ public abstract class ServerRuntimeInstance { Deployment addDeployment(@NotNull String deploymentName, @Nullable DeploymentRuntime deploymentRuntime, @Nullable DeploymentStatus deploymentStatus, - @Nullable String deploymentStatusText); + @Nullable String deploymentStatusText, + @Nullable String deploymentGroup); void succeeded(); } diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java index a03477c24995..be30dca9ebb4 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java @@ -131,10 +131,17 @@ public class ServerConnectionImpl implements @Override public void connected(@NotNull ServerRuntimeInstance instance) { DeploymentSource source = task.getSource(); - String deploymentName = instance.getDeploymentName(source, task.getConfiguration()); + D configuration = task.getConfiguration(); + String deploymentName = instance.getDeploymentName(source, configuration); LocalDeploymentImpl deployment; synchronized (myLocalDeployments) { - deployment = new LocalDeploymentImpl(ServerConnectionImpl.this, deploymentName, DeploymentStatus.DEPLOYING, null, null, task); + deployment = new LocalDeploymentImpl(ServerConnectionImpl.this, + deploymentName, + DeploymentStatus.DEPLOYING, + null, + null, + task, + instance.getDeploymentGroup(source, configuration)); myLocalDeployments.put(deploymentName, deployment); } DeploymentLogManagerImpl logManager = new DeploymentLogManagerImpl(task.getProject(), new ChangeListener()) @@ -186,14 +193,15 @@ public class ServerConnectionImpl implements @Override public void addDeployment(@NotNull String deploymentName, @Nullable DeploymentRuntime deploymentRuntime) { - addDeployment(deploymentName, deploymentRuntime, null, null); + addDeployment(deploymentName, deploymentRuntime, null, null, null); } @Override public Deployment addDeployment(@NotNull String deploymentName, @Nullable DeploymentRuntime deploymentRuntime, @Nullable DeploymentStatus deploymentStatus, - @Nullable String deploymentStatusText) { + @Nullable String deploymentStatusText, + @Nullable String deploymentGroup) { DeploymentImpl result; if (deploymentStatus == null) { deploymentStatus = DeploymentStatus.DEPLOYED; @@ -206,7 +214,8 @@ public class ServerConnectionImpl implements deploymentStatus, deploymentStatusText, deploymentRuntime, - null); + null, + deploymentGroup); } else if (!result.getStatus().isTransition()) { result.changeState(result.getStatus(), deploymentStatus, deploymentStatusText, deploymentRuntime); diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/DeploymentImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/DeploymentImpl.java index 9f713ccd0fac..cf2937e47d88 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/DeploymentImpl.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/DeploymentImpl.java @@ -18,6 +18,7 @@ public class DeploymentImpl implements Deployment { private final ServerConnectionImpl myConnection; private final String myName; private final DeploymentTask myDeploymentTask; + private final String myGroup; private volatile DeploymentState myState; public DeploymentImpl(@NotNull ServerConnectionImpl connection, @@ -25,10 +26,12 @@ public class DeploymentImpl implements Deployment { @NotNull DeploymentStatus status, @Nullable String statusText, @Nullable DeploymentRuntime runtime, - @Nullable DeploymentTask deploymentTask) { + @Nullable DeploymentTask deploymentTask, + @Nullable String group) { myConnection = connection; myName = name; myDeploymentTask = deploymentTask; + myGroup = group; myState = new DeploymentState(status, statusText, runtime); } @@ -76,11 +79,18 @@ public class DeploymentImpl implements Deployment { }); } + @NotNull @Override public ServerConnection getConnection() { return myConnection; } + @Nullable + @Override + public String getGroup() { + return myGroup; + } + public boolean changeState(@NotNull DeploymentStatus oldStatus, @NotNull DeploymentStatus newStatus, @Nullable String statusText, @Nullable DeploymentRuntime runtime) { if (myState.getStatus() == oldStatus) { diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/LocalDeploymentImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/LocalDeploymentImpl.java index 805fb62cd310..0080337aef85 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/LocalDeploymentImpl.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/LocalDeploymentImpl.java @@ -31,8 +31,9 @@ public class LocalDeploymentImpl extends DeploymentImpl { @NotNull DeploymentStatus status, @Nullable String statusText, @Nullable DeploymentRuntime runtime, - @Nullable DeploymentTask deploymentTask) { - super(connection, name, status, statusText, runtime, deploymentTask); + @Nullable DeploymentTask deploymentTask, + @Nullable String group) { + super(connection, name, status, statusText, runtime, deploymentTask, group); } public void setRemoteDeployment(DeploymentImpl remoteDeployment) { diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/ServersToolWindowContent.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/ServersToolWindowContent.java index 88107cdc83fd..d54a53dd0536 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/ServersToolWindowContent.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/ServersToolWindowContent.java @@ -13,8 +13,6 @@ 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.remoteServer.configuration.RemoteServer; -import com.intellij.remoteServer.impl.runtime.log.LoggingHandlerImpl; import com.intellij.remoteServer.impl.runtime.ui.tree.ServersTreeStructure; import com.intellij.remoteServer.impl.runtime.ui.tree.TreeBuilderBase; import com.intellij.remoteServer.runtime.ConnectionStatus; @@ -25,11 +23,14 @@ import com.intellij.ui.*; import com.intellij.ui.components.panels.Wrapper; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.Alarm; +import com.intellij.util.ObjectUtils; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; @@ -37,6 +38,7 @@ import javax.swing.tree.DefaultTreeModel; import java.awt.*; import java.awt.event.MouseEvent; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -162,8 +164,7 @@ public class ServersToolWindowContent extends JPanel implements Disposable { } private void updateServerDetails(ServersTreeStructure.RemoteServerNode node) { - RemoteServer server = ((ServersTreeStructure.RemoteServerNode)node).getValue(); - ServerConnection connection = ServerConnectionManager.getInstance().getConnection(server); + ServerConnection connection = ServerConnectionManager.getInstance().getConnection(node.getServer()); if (connection == null) { showMessageLabel("Double-click on the server node to connect"); } @@ -182,7 +183,9 @@ public class ServersToolWindowContent extends JPanel implements Disposable { myBuilder = new TreeBuilderBase(myTree, structure, myTreeModel) { @Override protected boolean isAutoExpandNode(NodeDescriptor nodeDescriptor) { - return nodeDescriptor instanceof ServersTreeStructure.RemoteServerNode || nodeDescriptor instanceof ServersTreeStructure.DeploymentNodeImpl; + return nodeDescriptor instanceof ServersTreeStructure.RemoteServerNode + || nodeDescriptor instanceof ServersTreeStructure.DeploymentNodeImpl + || nodeDescriptor instanceof ServersTreeStructure.GroupNode; } }; Disposer.register(this, myBuilder); @@ -324,14 +327,13 @@ public class ServersToolWindowContent extends JPanel implements Disposable { private static boolean isServerNodeMatch(@NotNull final ServersTreeStructure.RemoteServerNode node, @NotNull final ServerConnection connection) { - return node.getValue().equals(connection.getServer()); + return node.getServer().equals(connection.getServer()); } private static boolean isDeploymentNodeMatch(@NotNull ServersTreeStructure.DeploymentNodeImpl node, @NotNull final ServerConnection connection, @NotNull final String deploymentName) { - AbstractTreeNode parent = node.getParent(); - return parent instanceof ServersTreeStructure.RemoteServerNode && - isServerNodeMatch((ServersTreeStructure.RemoteServerNode)parent, connection) - && node.getValue().getName().equals(deploymentName); + ServersTreeStructure.RemoteServerNode serverNode = node.getServerNode(); + return isServerNodeMatch(serverNode, connection) + && node.getDeployment().getName().equals(deploymentName); } } diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/tree/ServersTreeStructure.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/tree/ServersTreeStructure.java index 5ea107c3d37e..9b7016a4dc67 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/tree/ServersTreeStructure.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/tree/ServersTreeStructure.java @@ -20,6 +20,7 @@ import com.intellij.openapi.ui.popup.ListPopup; import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.text.StringUtil; import com.intellij.remoteServer.ServerType; import com.intellij.remoteServer.configuration.RemoteServer; @@ -42,16 +43,16 @@ import com.intellij.remoteServer.runtime.deployment.DeploymentTask; import com.intellij.ui.LayeredIcon; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.hash.*; +import com.intellij.util.containers.hash.HashSet; import icons.RemoteServersIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; +import java.util.HashMap; /** * @author michael.golubev @@ -136,27 +137,40 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { } public class RemoteServerNode extends AbstractTreeNode> implements ServerNode { - public RemoteServerNode(RemoteServer server) { + public RemoteServerNode(@NotNull RemoteServer server) { super(doGetProject(), server); } + @NotNull + public RemoteServer getServer() { + return getValue(); + } + @NotNull @Override public Collection getChildren() { - ServerConnection connection = getConnection(); + final ServerConnection connection = getConnection(); if (connection == null) { return Collections.emptyList(); } - List children = new ArrayList(); + + final List children = new ArrayList(); + Set groups = new HashSet(); for (Deployment deployment : connection.getDeployments()) { - children.add(new DeploymentNodeImpl(connection, this, deployment)); + final String groupName = deployment.getGroup(); + if (groupName == null) { + children.add(new DeploymentNodeImpl(connection, this, deployment)); + } + else if (groups.add(groupName)) { + children.add(new GroupNode(connection, this, groupName)); + } } return children; } @Override protected void update(PresentationData presentation) { - RemoteServer server = getValue(); + RemoteServer server = getServer(); ServerConnection connection = getConnection(); presentation.setPresentableText(server.getName()); presentation.setIcon(getServerNodeIcon(server.getType().getIcon(), connection != null ? getStatusIcon(connection.getStatus()) : null)); @@ -165,7 +179,7 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { @Nullable private ServerConnection getConnection() { - return ServerConnectionManager.getInstance().getConnection(getValue()); + return ServerConnectionManager.getInstance().getConnection(getServer()); } public boolean isConnected() { @@ -182,7 +196,7 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { } public void doDeploy(AnActionEvent e, final Executor executor, String popupTitle, boolean canCreate) { - final RemoteServer server = getValue(); + final RemoteServer server = getServer(); final ServerType serverType = server.getType(); final DeploymentConfigurationManager configurationManager = DeploymentConfigurationManager.getInstance(doGetProject()); final List list = new ArrayList(ContainerUtil.filter( @@ -251,18 +265,23 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { public class DeploymentNodeImpl extends AbstractTreeNode implements LogProvidingNode, DeploymentNode { private final ServerConnection myConnection; - private final RemoteServerNode myParentNode; + private final RemoteServerNode myServerNode; - private DeploymentNodeImpl(@NotNull ServerConnection connection, @NotNull RemoteServerNode parentNode, Deployment value) { + private DeploymentNodeImpl(@NotNull ServerConnection connection, @NotNull RemoteServerNode serverNode, @NotNull Deployment value) { super(doGetProject(), value); myConnection = connection; - myParentNode = parentNode; + myServerNode = serverNode; + } + + @NotNull + public Deployment getDeployment() { + return getValue(); } @NotNull @Override - public ServerNode getServerNode() { - return myParentNode; + public RemoteServerNode getServerNode() { + return myServerNode; } @Override @@ -282,7 +301,7 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { } public void doDeploy(Executor executor) { - DeploymentTask deploymentTask = getValue().getDeploymentTask(); + DeploymentTask deploymentTask = getDeployment().getDeploymentTask(); if (deploymentTask != null) { ExecutionEnvironment environment = ((DeploymentTaskImpl)deploymentTask).getExecutionEnvironment(); RunnerAndConfigurationSettings settings = environment.getRunnerAndConfigurationSettings(); @@ -294,7 +313,7 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { @Override public boolean isDebugActionVisible() { - return myParentNode.getValue().getType().createDebugConnector() != null; + return myServerNode.getServer().getType().createDebugConnector() != null; } @Override @@ -304,24 +323,24 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { @Override public boolean isUndeployActionEnabled() { - DeploymentRuntime runtime = getValue().getRuntime(); + DeploymentRuntime runtime = getDeployment().getRuntime(); return runtime != null && runtime.isUndeploySupported(); } @Override public void undeploy() { - DeploymentRuntime runtime = getValue().getRuntime(); + DeploymentRuntime runtime = getDeployment().getRuntime(); if (runtime != null) { - getConnection().undeploy(getValue(), runtime); + getConnection().undeploy(getDeployment(), runtime); } } public boolean isEditConfigurationActionVisible() { - return getValue().getDeploymentTask() != null; + return getDeployment().getDeploymentTask() != null; } public void editConfiguration() { - DeploymentTask task = getValue().getDeploymentTask(); + DeploymentTask task = getDeployment().getDeploymentTask(); if (task != null) { RunnerAndConfigurationSettings settings = ((DeploymentTaskImpl)task).getExecutionEnvironment().getRunnerAndConfigurationSettings(); if (settings != null) { @@ -332,12 +351,12 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { @Override public boolean isDeployed() { - return getValue().getStatus() == DeploymentStatus.DEPLOYED; + return getDeployment().getStatus() == DeploymentStatus.DEPLOYED; } @Override public String getDeploymentName() { - return getValue().getName(); + return getDeployment().getName(); } public ServerConnection getConnection() { @@ -355,11 +374,11 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { @Nullable private DeploymentLogManagerImpl getLogManager() { - return (DeploymentLogManagerImpl)myConnection.getLogManager(getValue()); + return (DeploymentLogManagerImpl)myConnection.getLogManager(getDeployment()); } public String getId() { - return myParentNode.getName() + ";deployment" + getValue().getName(); + return myServerNode.getName() + ";deployment" + getDeployment().getName(); } @NotNull @@ -371,7 +390,7 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { @NotNull @Override public Collection getChildren() { - DeploymentLogManagerImpl logManager = (DeploymentLogManagerImpl)getConnection().getLogManager(getValue()); + DeploymentLogManagerImpl logManager = (DeploymentLogManagerImpl)getConnection().getLogManager(getDeployment()); if (logManager != null) { List nodes = new ArrayList(); for (LoggingHandlerBase loggingComponent : logManager.getAdditionalLoggingHandlers()) { @@ -384,7 +403,7 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { @Override protected void update(PresentationData presentation) { - Deployment deployment = getValue(); + Deployment deployment = getDeployment(); presentation.setIcon(deployment.getStatus().getIcon()); presentation.setPresentableText(deployment.getName()); presentation.setTooltip(deployment.getStatusText()); @@ -427,4 +446,39 @@ public class ServersTreeStructure extends AbstractTreeStructureBase { return myDeploymentNode.getId() + ";log:" + getLogName(); } } + + public class GroupNode extends AbstractTreeNode implements ServersTreeNode { + + @NotNull private final ServerConnection myConnection; + @NotNull private final RemoteServerNode myServerNode; + + public GroupNode(@NotNull ServerConnection connection, @NotNull RemoteServerNode serverNode, @NotNull String group) { + super(doGetProject(), group); + myConnection = connection; + myServerNode = serverNode; + } + + @NotNull + public String getGroup() { + return getValue(); + } + + @NotNull + @Override + public Collection getChildren() { + List children = new ArrayList(); + for (Deployment deployment : myConnection.getDeployments()) { + if (StringUtil.equals(getGroup(), deployment.getGroup())) { + children.add(new DeploymentNodeImpl(myConnection, myServerNode, deployment)); + } + } + return children; + } + + @Override + protected void update(PresentationData presentation) { + presentation.setIcon(myServerNode.getServer().getType().getIcon()); + presentation.setPresentableText(getGroup()); + } + } } diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudApplicationRuntime.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudApplicationRuntime.java index 1bc9f8620253..44a7bf3385e1 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudApplicationRuntime.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudApplicationRuntime.java @@ -72,6 +72,11 @@ public abstract class CloudApplicationRuntime extends DeploymentRuntime { protected abstract ServerType getCloudType(); + @Nullable + public String getGroup() { + return null; + } + protected abstract class LoggingTask { public void perform(final Project project, final Runnable onDone) { diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudServerRuntimeInstance.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudServerRuntimeInstance.java index ff09df16fcc5..7b5be53aa87f 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudServerRuntimeInstance.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudServerRuntimeInstance.java @@ -97,7 +97,11 @@ public abstract class CloudServerRuntimeInstance try { for (CloudApplicationRuntime application : getApplications()) { Deployment deployment - = callback.addDeployment(application.getApplicationName(), application, application.getStatus(), application.getStatusText()); + = callback.addDeployment(application.getApplicationName(), + application, + application.getStatus(), + application.getStatusText(), + application.getGroup()); application.setDeploymentModel(deployment); } callback.succeeded();