Build tool window: side-by-side view UX-496

This commit is contained in:
Vladislav.Soroka
2019-03-18 09:08:34 +03:00
parent 144b57146f
commit b23f82d2dc
11 changed files with 304 additions and 166 deletions
@@ -350,6 +350,9 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
if (progressListener != null) {
long eventTime = System.currentTimeMillis();
AnAction rerunTaskAction = new MyTaskRerunAction(progressListener, myEnv, myContentDescriptor);
BuildViewSettingsProvider viewSettingsProvider =
consoleView instanceof BuildViewSettingsProvider ?
new BuildViewSettingsProviderAdapter((BuildViewSettingsProvider)consoleView) : null;
progressListener.onEvent(
new StartBuildEventImpl(new DefaultBuildDescriptor(id, executionName, workingDir, eventTime), "running...")
.withProcessHandler(processHandler, view -> {
@@ -360,6 +363,7 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
.withRestartAction(rerunTaskAction)
.withRestartActions(restartActions)
.withExecutionEnvironment(myEnv)
.withBuildViewSettingsProvider(viewSettingsProvider)
);
}
}
@@ -8,7 +8,9 @@ import com.intellij.execution.filters.TextConsoleBuilderFactory;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -66,6 +68,8 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import static com.intellij.build.BuildView.CONSOLE_VIEW_NAME;
/**
* @author Vladislav.Soroka
*/
@@ -73,11 +77,14 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
private static final Logger LOG = Logger.getInstance(BuildTreeConsoleView.class);
@NonNls private static final String TREE = "tree";
@NonNls private static final String SPLITTER_PROPERTY = "SMTestRunner.Splitter.Proportion";
private final JPanel myPanel = new JPanel();
private final Map<Object, ExecutionNode> nodesMap = ContainerUtil.newConcurrentMap();
private final Project myProject;
private final DetailsHandler myDetailsHandler;
private final ConsoleViewHandler myConsoleViewHandler;
@NotNull
private final BuildViewSettingsProvider myViewSettingsProvider;
private final TableColumn myTimeColumn;
private final String myWorkingDir;
private final AtomicBoolean myDisposed = new AtomicBoolean();
@@ -86,7 +93,10 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
private final ExecutionNode myRootNode;
private volatile int myTimeColumnWidth;
public BuildTreeConsoleView(Project project, BuildDescriptor buildDescriptor) {
public BuildTreeConsoleView(Project project,
BuildDescriptor buildDescriptor,
@Nullable ExecutionConsole executionConsole,
@NotNull BuildViewSettingsProvider buildViewSettingsProvider) {
myProject = project;
myWorkingDir = FileUtil.toSystemIndependentName(buildDescriptor.getWorkingDir());
final ColumnInfo[] COLUMNS = {
@@ -107,6 +117,7 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
}
}
};
myViewSettingsProvider = buildViewSettingsProvider;
myRootNode = new ExecutionNode(myProject, null);
myRootNode.setAutoExpandNode(true);
@@ -182,7 +193,7 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
myTimeColumn = treeTable.getColumnModel().getColumn(1);
myTimeColumn.setResizable(false);
updateTimeColumnWidth("Running for " + StringUtil.formatDuration(11111L), true);
updateTimeColumnWidth(StringUtil.formatDurationApproximate(11111L), true);
TreeUtil.installActions(myTree);
@@ -192,29 +203,38 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
myPanel.setLayout(new BorderLayout());
ThreeComponentsSplitter myThreeComponentsSplitter = new ThreeComponentsSplitter() {
@Override
public void setFirstSize(int size) {
super.setFirstSize(size);
float proportion = size / (float)getWidth();
PropertiesComponent.getInstance().setValue(SPLITTER_PROPERTY, proportion, 0.3f);
}
@Override
public void doLayout() {
super.doLayout();
JComponent detailsComponent = myDetailsHandler.getComponent();
JComponent detailsComponent = myConsoleViewHandler.getComponent();
if (detailsComponent != null && detailsComponent.isVisible()) {
int firstSize = getFirstSize();
int lastSize = getLastSize();
if (firstSize == 0 && lastSize == 0) {
int width = Math.round(getWidth() / 2f);
if (width > 0) {
setFirstSize(width);
}
}
updateSplitter(this);
}
}
};
Disposer.register(this, myThreeComponentsSplitter);
myThreeComponentsSplitter.setFirstComponent(myContentPanel);
myDetailsHandler = new DetailsHandler(myProject, myTree, myThreeComponentsSplitter);
myThreeComponentsSplitter.setLastComponent(myDetailsHandler.getComponent());
myConsoleViewHandler =
new ConsoleViewHandler(myProject, myTree, myThreeComponentsSplitter, executionConsole, buildViewSettingsProvider);
myThreeComponentsSplitter.setLastComponent(myConsoleViewHandler.getComponent());
myPanel.add(myThreeComponentsSplitter, BorderLayout.CENTER);
}
@Override
public void clear() {
getRootElement().removeChildren();
nodesMap.clear();
myConsoleViewHandler.clear();
myTreeModel.invalidate();
}
private ExecutionNode getRootElement() {
return myRootNode;
}
@@ -223,96 +243,6 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
public void print(@NotNull String text, @NotNull ConsoleViewContentType contentType) {
}
@Override
public void clear() {
getRootElement().removeChildren();
nodesMap.clear();
myDetailsHandler.clear();
myTreeModel.invalidate();
}
@Override
public void scrollTo(int offset) {
}
@Override
public void attachToProcess(ProcessHandler processHandler) {
}
@Override
public boolean isOutputPaused() {
return false;
}
@Override
public void setOutputPaused(boolean value) {
}
@Override
public boolean hasDeferredOutput() {
return false;
}
@Override
public void performWhenNoDeferredOutput(@NotNull Runnable runnable) {
}
@Override
public void setHelpId(@NotNull String helpId) {
}
@Override
public void addMessageFilter(@NotNull Filter filter) {
}
@Override
public void printHyperlink(@NotNull String hyperlinkText, @Nullable HyperlinkInfo info) {
}
@Override
public int getContentSize() {
return 0;
}
@Override
public boolean canPause() {
return false;
}
@NotNull
@Override
public AnAction[] createConsoleActions() {
return AnAction.EMPTY_ARRAY;
}
@Override
public void allowHeavyFilters() {
}
@Override
public JComponent getComponent() {
return myPanel;
}
@Override
public JComponent getPreferredFocusableComponent() {
return myTree;
}
@Override
public void dispose() {
myDisposed.set(true);
}
public boolean isDisposed() {
return myDisposed.get();
}
@Override
public void onEvent(@NotNull BuildEvent event) {
myTreeModel.getInvoker().runOrInvokeLater(() -> onEventInternal(event));
}
public void onEventInternal(@NotNull BuildEvent event) {
ExecutionNode parentNode = event.getParentId() == null ? null : nodesMap.get(event.getParentId());
ExecutionNode currentNode = nodesMap.get(event.getId());
@@ -396,9 +326,12 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
aHint = aHint == null ? "at " + time : aHint + " at " + time;
currentNode.setHint(aHint);
updateTimeColumnWidth(myTimeColumnWidth);
if (myDetailsHandler.myExecutionNode == null) {
if (myViewSettingsProvider.isSideBySideView()) {
currentNode.setResult(null);
}
if (myConsoleViewHandler.myExecutionNode == null) {
ExecutionNode element = getRootElement();
ApplicationManager.getApplication().invokeLater(() -> myDetailsHandler.setNode(element));
ApplicationManager.getApplication().invokeLater(() -> myConsoleViewHandler.setNode(element));
}
if (((FinishBuildEvent)event).getResult() instanceof FailureResult) {
@@ -421,6 +354,101 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
scheduleUpdate(currentNode);
}
@Override
public void scrollTo(int offset) {
}
@Override
public void attachToProcess(ProcessHandler processHandler) {
}
@Override
public boolean isOutputPaused() {
return false;
}
@Override
public void setOutputPaused(boolean value) {
}
@Override
public boolean hasDeferredOutput() {
return false;
}
@Override
public void performWhenNoDeferredOutput(@NotNull Runnable runnable) {
}
@Override
public void setHelpId(@NotNull String helpId) {
}
@Override
public void addMessageFilter(@NotNull Filter filter) {
}
@Override
public void printHyperlink(@NotNull String hyperlinkText, @Nullable HyperlinkInfo info) {
}
@Override
public int getContentSize() {
return 0;
}
@Override
public boolean canPause() {
return false;
}
@NotNull
@Override
public AnAction[] createConsoleActions() {
return AnAction.EMPTY_ARRAY;
}
@Override
public void allowHeavyFilters() {
}
@Override
public JComponent getComponent() {
return myPanel;
}
@Override
public JComponent getPreferredFocusableComponent() {
return myTree;
}
@Override
public void dispose() {
myDisposed.set(true);
}
public boolean isDisposed() {
return myDisposed.get();
}
@Override
public void onEvent(@NotNull BuildEvent event) {
myTreeModel.getInvoker().runOrInvokeLater(() -> onEventInternal(event));
}
private static void updateSplitter(@NotNull ThreeComponentsSplitter myThreeComponentsSplitter) {
int firstSize = myThreeComponentsSplitter.getFirstSize();
//int lastSize = myThreeComponentsSplitter.getLastSize();
int splitterWidth = myThreeComponentsSplitter.getWidth();
if (firstSize == 0/* && lastSize == 0*/) {
float proportion = PropertiesComponent.getInstance().getFloat(SPLITTER_PROPERTY, 0.3f);
int width = Math.round(splitterWidth * proportion);
if (width > 0) {
myThreeComponentsSplitter.setFirstSize(width);
}
}
}
protected void expand(TreeTableTree tree) {
TreeUtil.expand(tree,
path -> {
@@ -601,30 +629,45 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
return node;
}
private static class DetailsHandler {
private final ThreeComponentsSplitter mySplitter;
private final ConsoleView myConsole;
private static class ConsoleViewHandler {
private static final String TASK_OUTPUT_VIEW_NAME = "taskOutputView";
private final JPanel myPanel;
private final CompositeView<ExecutionConsole> myView;
@NotNull
private final BuildViewSettingsProvider myViewSettingsProvider;
@Nullable
private ExecutionNode myExecutionNode;
DetailsHandler(Project project,
TreeTableTree tree,
ThreeComponentsSplitter threeComponentsSplitter) {
myConsole = TextConsoleBuilderFactory.getInstance().createBuilder(project).getConsole();
mySplitter = threeComponentsSplitter;
ConsoleViewHandler(Project project,
TreeTableTree tree,
ThreeComponentsSplitter threeComponentsSplitter,
@Nullable ExecutionConsole executionConsole,
@NotNull BuildViewSettingsProvider buildViewSettingsProvider) {
myPanel = new JPanel(new BorderLayout());
JComponent consoleComponent = myConsole.getComponent();
AnAction[] consoleActions = myConsole.createConsoleActions();
ConsoleView myNodeConsole = TextConsoleBuilderFactory.getInstance().createBuilder(project).getConsole();
myViewSettingsProvider = buildViewSettingsProvider;
myView = new CompositeView<>(null);
if (executionConsole != null && buildViewSettingsProvider.isSideBySideView()) {
myView.addView(executionConsole, CONSOLE_VIEW_NAME, true);
}
myView.addView(myNodeConsole, TASK_OUTPUT_VIEW_NAME, false);
if (buildViewSettingsProvider.isSideBySideView()) {
myView.enableView(CONSOLE_VIEW_NAME, false);
myPanel.setVisible(true);
}
else {
myPanel.setVisible(false);
}
JComponent consoleComponent = myNodeConsole.getComponent();
AnAction[] consoleActions = myNodeConsole.createConsoleActions();
consoleComponent.setFocusable(true);
final Color editorBackground = EditorColorsManager.getInstance().getGlobalScheme().getDefaultBackground();
consoleComponent.setBorder(new CompoundBorder(IdeBorderFactory.createBorder(SideBorder.RIGHT),
new SideBorder(editorBackground, SideBorder.LEFT)));
myPanel.add(consoleComponent, BorderLayout.CENTER);
myPanel.add(myView.getComponent(), BorderLayout.CENTER);
final ActionToolbar toolbar = ActionManager.getInstance()
.createActionToolbar("BuildResults", new DefaultActionGroup(consoleActions), false);
myPanel.add(toolbar.getComponent(), BorderLayout.EAST);
myPanel.setVisible(false);
tree.addTreeSelectionListener(e -> {
TreePath path = e.getPath();
if (path == null || !e.isAddedPath()) {
@@ -634,15 +677,21 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
setNode(selectionPath != null ? (DefaultMutableTreeNode)selectionPath.getLastPathComponent() : null);
});
Disposer.register(threeComponentsSplitter, myConsole);
Disposer.register(threeComponentsSplitter, myView);
Disposer.register(threeComponentsSplitter, myNodeConsole);
}
private ConsoleView getTaskOutputView() {
return (ConsoleView)myView.getView(TASK_OUTPUT_VIEW_NAME);
}
public boolean setNode(@NotNull ExecutionNode node) {
EventResult eventResult = node.getResult();
boolean hasChanged = false;
ConsoleView taskOutputView = getTaskOutputView();
if (eventResult instanceof FailureResult) {
myConsole.clear();
taskOutputView.clear();
List<? extends Failure> failures = ((FailureResult)eventResult).getFailures();
if (failures.isEmpty()) return false;
for (Iterator<? extends Failure> iterator = failures.iterator(); iterator.hasNext(); ) {
@@ -655,7 +704,7 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
printDetails(failure, text);
hasChanged = true;
if (iterator.hasNext()) {
myConsole.print("\n\n", ConsoleViewContentType.NORMAL_OUTPUT);
taskOutputView.print("\n\n", ConsoleViewContentType.NORMAL_OUTPUT);
}
}
}
@@ -667,27 +716,22 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
if (details.isEmpty()) {
return false;
}
myConsole.clear();
taskOutputView.clear();
printDetails(null, details);
hasChanged = true;
}
if (!hasChanged) return false;
myConsole.scrollTo(0);
int firstSize = mySplitter.getFirstSize();
int lastSize = mySplitter.getLastSize();
taskOutputView.scrollTo(0);
if (firstSize == 0 && lastSize == 0) {
int width = Math.round(mySplitter.getWidth() / 2f);
mySplitter.setFirstSize(width);
}
myView.enableView(TASK_OUTPUT_VIEW_NAME, !myViewSettingsProvider.isSideBySideView());
myPanel.setVisible(true);
return true;
}
private boolean printDetails(Failure failure, @Nullable String details) {
return BuildConsoleUtils.printDetails(myConsole, failure, details);
return BuildConsoleUtils.printDetails(getTaskOutputView(), failure, details);
}
public void setNode(@Nullable DefaultMutableTreeNode node) {
@@ -700,7 +744,13 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
}
myExecutionNode = null;
myPanel.setVisible(false);
if (myView.getView(CONSOLE_VIEW_NAME) != null) {
myView.enableView(CONSOLE_VIEW_NAME);
myPanel.setVisible(true);
}
else {
myPanel.setVisible(false);
}
}
public JComponent getComponent() {
@@ -709,7 +759,7 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
public void clear() {
myPanel.setVisible(false);
myConsole.clear();
getTaskOutputView().clear();
}
}
}
@@ -18,6 +18,7 @@ package com.intellij.build;
import com.intellij.build.events.BuildEvent;
import com.intellij.build.events.OutputBuildEvent;
import com.intellij.build.events.StartBuildEvent;
import com.intellij.build.events.impl.StartBuildEventImpl;
import com.intellij.build.process.BuildProcessHandler;
import com.intellij.execution.actions.StopAction;
import com.intellij.execution.actions.StopProcessAction;
@@ -61,6 +62,8 @@ public class BuildView extends CompositeView<ExecutionConsole> implements BuildP
private final AtomicBoolean isBuildStartEventProcessed = new AtomicBoolean();
private final List<BuildEvent> myAfterStartEvents = ContainerUtil.createConcurrentList();
private final ViewManager myViewManager;
@Nullable private ExecutionConsole myExecutionConsole;
private BuildViewSettingsProvider myViewSettingsProvider;
public BuildView(Project project, BuildDescriptor buildDescriptor, String selectionStateKey, ViewManager viewManager) {
this(project, null, buildDescriptor, selectionStateKey, viewManager);
@@ -75,9 +78,7 @@ public class BuildView extends CompositeView<ExecutionConsole> implements BuildP
myProject = project;
myBuildDescriptor = buildDescriptor;
myViewManager = viewManager;
if (executionConsole != null) {
addView(executionConsole, CONSOLE_VIEW_NAME, viewManager.isConsoleEnabledByDefault());
}
myExecutionConsole = executionConsole;
}
@Override
@@ -120,38 +121,53 @@ public class BuildView extends CompositeView<ExecutionConsole> implements BuildP
private void onStartBuild(StartBuildEvent startBuildEvent) {
myStartBuildEventRef.set(startBuildEvent);
String eventViewName = BuildTreeConsoleView.class.getName();
BuildTreeConsoleView eventView = getView(eventViewName, BuildTreeConsoleView.class);
if (eventView == null) {
eventView = new BuildTreeConsoleView(myProject, myBuildDescriptor);
addView(eventView, eventViewName, !myViewManager.isConsoleEnabledByDefault());
if (startBuildEvent instanceof StartBuildEventImpl) {
myViewSettingsProvider = ((StartBuildEventImpl)startBuildEvent).getBuildViewSettingsProvider();
}
ExecutionConsole executionConsoleView = getConsoleView();
if (executionConsoleView == null) {
if (myViewSettingsProvider == null) {
myViewSettingsProvider = () -> false;
}
if (myExecutionConsole == null) {
Supplier<RunContentDescriptor> descriptorSupplier = startBuildEvent.getContentDescriptorSupplier();
RunContentDescriptor runContentDescriptor = descriptorSupplier != null ? descriptorSupplier.get() : null;
executionConsoleView = runContentDescriptor != null &&
myExecutionConsole = runContentDescriptor != null &&
runContentDescriptor.getExecutionConsole() != null &&
runContentDescriptor.getExecutionConsole() != this ?
runContentDescriptor.getExecutionConsole() : new BuildTextConsoleView(myProject);
addView(executionConsoleView, CONSOLE_VIEW_NAME, myViewManager.isConsoleEnabledByDefault());
runContentDescriptor.getExecutionConsole() : new BuildTextConsoleView(myProject);
if (runContentDescriptor != null && Disposer.findRegisteredObject(runContentDescriptor, this) == null) {
Disposer.register(this, runContentDescriptor);
}
}
if (myExecutionConsole != null) {
myExecutionConsole.getComponent(); //create editor to be able to add console editor actions
if (myViewSettingsProvider.isExecutionViewHidden() || !myViewSettingsProvider.isSideBySideView()) {
addView(myExecutionConsole, CONSOLE_VIEW_NAME, myViewManager.isConsoleEnabledByDefault());
}
}
BuildTreeConsoleView eventView = null;
if (!myViewSettingsProvider.isExecutionViewHidden()) {
String eventViewName = BuildTreeConsoleView.class.getName();
eventView = getView(eventViewName, BuildTreeConsoleView.class);
if (eventView == null) {
eventView = new BuildTreeConsoleView(myProject, myBuildDescriptor,
myExecutionConsole,
myViewSettingsProvider);
addView(eventView, eventViewName, myViewSettingsProvider.isSideBySideView() || !myViewManager.isConsoleEnabledByDefault());
}
}
BuildProcessHandler processHandler = startBuildEvent.getProcessHandler();
if (executionConsoleView instanceof ConsoleView) {
if (myExecutionConsole instanceof ConsoleView) {
for (Filter filter : startBuildEvent.getExecutionFilters()) {
((ConsoleView)executionConsoleView).addMessageFilter(filter);
((ConsoleView)myExecutionConsole).addMessageFilter(filter);
}
if (processHandler != null) {
((ConsoleView)executionConsoleView).attachToProcess(processHandler);
((ConsoleView)myExecutionConsole).attachToProcess(processHandler);
Consumer<ConsoleView> attachedConsoleConsumer = startBuildEvent.getAttachedConsoleConsumer();
if (attachedConsoleConsumer != null) {
attachedConsoleConsumer.consume((ConsoleView)executionConsoleView);
attachedConsoleConsumer.consume((ConsoleView)myExecutionConsole);
}
if (!processHandler.isStartNotified()) {
processHandler.startNotify();
@@ -162,11 +178,13 @@ public class BuildView extends CompositeView<ExecutionConsole> implements BuildP
processHandler.startNotify();
}
eventView.onEvent(startBuildEvent);
if (eventView != null) {
eventView.onEvent(startBuildEvent);
}
}
private ExecutionConsole getConsoleView() {
return getView(CONSOLE_VIEW_NAME, ExecutionConsole.class);
return myExecutionConsole;
}
@Override
@@ -273,12 +291,13 @@ public class BuildView extends CompositeView<ExecutionConsole> implements BuildP
public void update(@NotNull AnActionEvent e) {
super.update(e);
String eventViewName = BuildTreeConsoleView.class.getName();
e.getPresentation().setVisible(!BuildView.this.isViewEnabled(eventViewName));
e.getPresentation().setVisible(!myViewSettingsProvider.isSideBySideView() && !BuildView.this.isViewEnabled(eventViewName));
}
};
ExecutionConsole consoleView = getConsoleView();
if (consoleView instanceof ConsoleView) {
consoleView.getComponent(); //create editor to be able to add console editor actions
final AnAction[] consoleActions = ((ConsoleView)consoleView).createConsoleActions();
for (AnAction anAction : consoleActions) {
if (anAction instanceof StopAction) {
@@ -303,7 +322,7 @@ public class BuildView extends CompositeView<ExecutionConsole> implements BuildP
rerunActionGroup.add(stopAction);
}
actionGroup.add(rerunActionGroup);
if (myViewManager.isBuildContentView()) {
if (myViewManager.isBuildContentView() && !myViewSettingsProvider.isSideBySideView()) {
actionGroup.addAll(getSwitchActions());
actionGroup.addSeparator();
}
@@ -0,0 +1,14 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.build;
import com.intellij.openapi.util.registry.Registry;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Experimental
public interface BuildViewSettingsProvider {
boolean isExecutionViewHidden();
default boolean isSideBySideView() {
return Registry.is("build.view.side-by-side", false);
}
}
@@ -0,0 +1,15 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.build;
public class BuildViewSettingsProviderAdapter implements BuildViewSettingsProvider {
private boolean myExecutionViewHidden;
public BuildViewSettingsProviderAdapter(BuildViewSettingsProvider buildViewSettingsProvider) {
myExecutionViewHidden = buildViewSettingsProvider.isExecutionViewHidden();
}
@Override
public boolean isExecutionViewHidden() {
return myExecutionViewHidden;
}
}
@@ -55,7 +55,7 @@ public class CompositeView<T extends ComponentContainer> extends JPanel implemen
mySwitchViewAction = new SwitchViewAction();
}
public void addView(T view, String viewName, boolean enable) {
public void addView(@NotNull T view, @NotNull String viewName, boolean enable) {
T oldView = getView(viewName);
if (oldView != null) {
remove(oldView.getComponent());
@@ -73,17 +73,23 @@ public class CompositeView<T extends ComponentContainer> extends JPanel implemen
}
public void enableView(@NotNull String viewName) {
enableView(viewName, true);
}
public void enableView(@NotNull String viewName, boolean requestFocus) {
if (!StringUtil.equals(viewName, myEnabledViewRef.get())) {
myEnabledViewRef.set(viewName);
CardLayout cl = (CardLayout)(getLayout());
cl.show(this, viewName);
}
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> {
ComponentContainer view = getView(viewName);
if (view != null) {
IdeFocusManager.getGlobalInstance().requestFocus(view.getPreferredFocusableComponent(), true);
}
});
if (requestFocus) {
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> {
ComponentContainer view = getView(viewName);
if (view != null) {
IdeFocusManager.getGlobalInstance().requestFocus(view.getPreferredFocusableComponent(), true);
}
});
}
}
public boolean isViewEnabled(String viewName) {
@@ -162,9 +168,11 @@ public class CompositeView<T extends ComponentContainer> extends JPanel implemen
public void update(@NotNull AnActionEvent e) {
final Presentation presentation = e.getPresentation();
if (myViewMap.size() <= 1) {
presentation.setVisible(false);
presentation.setEnabled(false);
}
else {
presentation.setVisible(true);
presentation.setEnabled(true);
presentation.putClientProperty(SELECTED_PROPERTY, isSelected(e));
}
@@ -173,12 +173,12 @@ public class ExecutionNode extends CachingSimpleNode {
if (startTime == endTime) return null;
if (isRunning()) {
final long duration = startTime == 0 ? 0 : System.currentTimeMillis() - startTime;
String durationText = StringUtil.formatDuration(duration);
String durationText = StringUtil.formatDurationApproximate(duration);
int index = durationText.indexOf("s ");
if (index != -1) {
durationText = durationText.substring(0, index + 1);
}
return "Running for " + durationText;
return durationText;
}
else {
return isSkipped(myResult) ? null : StringUtil.formatDuration(endTime - startTime);
@@ -16,6 +16,7 @@
package com.intellij.build.events.impl;
import com.intellij.build.BuildDescriptor;
import com.intellij.build.BuildViewSettingsProvider;
import com.intellij.build.events.StartBuildEvent;
import com.intellij.build.process.BuildProcessHandler;
import com.intellij.execution.filters.Filter;
@@ -25,6 +26,7 @@ import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.util.Consumer;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -50,6 +52,8 @@ public class StartBuildEventImpl extends StartEventImpl implements StartBuildEve
private ExecutionEnvironment myExecutionEnvironment;
@Nullable
private Supplier<RunContentDescriptor> myContentDescriptorSupplier;
@Nullable
private BuildViewSettingsProvider myBuildViewSettingsProvider;
public StartBuildEventImpl(@NotNull BuildDescriptor descriptor, @NotNull String message) {
super(descriptor.getId(), null, descriptor.getStartTime(), message);
@@ -104,6 +108,12 @@ public class StartBuildEventImpl extends StartEventImpl implements StartBuildEve
return myAttachedConsoleConsumer;
}
@Nullable
@ApiStatus.Experimental
public BuildViewSettingsProvider getBuildViewSettingsProvider() {
return myBuildViewSettingsProvider;
}
public StartBuildEventImpl withProcessHandler(@Nullable BuildProcessHandler processHandler,
@Nullable Consumer<ConsoleView> attachedConsoleConsumer) {
myProcessHandler = processHandler;
@@ -140,4 +150,10 @@ public class StartBuildEventImpl extends StartEventImpl implements StartBuildEve
myFilters.addAll(Arrays.asList(filters));
return this;
}
@ApiStatus.Experimental
public StartBuildEventImpl withBuildViewSettingsProvider(@Nullable BuildViewSettingsProvider viewSettingsProvider) {
myBuildViewSettingsProvider = viewSettingsProvider;
return this;
}
}
@@ -33,8 +33,10 @@ class BuildTreeConsoleViewTest: LightPlatformTestCase() {
"test descriptor",
"fake path",
1L)
treeConsoleView = BuildTreeConsoleView(getProject(), buildDescriptor)
treeConsoleView = BuildTreeConsoleView(getProject(), buildDescriptor, null, object : BuildViewSettingsProvider {
override fun isExecutionViewHidden(): Boolean = false
override fun isSideBySideView(): Boolean = true
})
}
@Test
@@ -1876,4 +1876,7 @@ ide.service.view=true
ide.service.view.description=Enable Services tool window
ide.service.view.restartRequired=true
build.view.side-by-side=false
build.view.side-by-side.description=Enable Build tool window tree and console side-by-side view
# TODO please use EP com.intellij.registryKey for plugin/product specific keys
@@ -15,10 +15,12 @@
*/
package org.jetbrains.plugins.gradle.execution.test.runner;
import com.intellij.build.BuildViewSettingsProvider;
import com.intellij.execution.testframework.TestConsoleProperties;
import com.intellij.execution.testframework.sm.runner.SMTestLocator;
import com.intellij.execution.testframework.sm.runner.SMTestProxy;
import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable;
@@ -27,7 +29,7 @@ import java.util.Map;
/**
* @author Vladislav.Soroka
*/
public class GradleTestsExecutionConsole extends SMTRunnerConsoleView {
public class GradleTestsExecutionConsole extends SMTRunnerConsoleView implements BuildViewSettingsProvider {
private final Map<String, SMTestProxy> testsMap = ContainerUtil.newHashMap();
private final StringBuilder myBuffer = new StringBuilder();
@@ -52,4 +54,9 @@ public class GradleTestsExecutionConsole extends SMTRunnerConsoleView {
public SMTestLocator getUrlProvider() {
return GradleConsoleProperties.GRADLE_TEST_LOCATOR;
}
@Override
public boolean isExecutionViewHidden() {
return Registry.is("build.view.side-by-side", false);
}
}