| package com.intellij.execution.console; |
| |
| import com.google.common.collect.Lists; |
| import com.intellij.execution.ExecutionBundle; |
| import com.intellij.execution.filters.Filter; |
| import com.intellij.execution.filters.HyperlinkInfo; |
| import com.intellij.execution.process.ProcessHandler; |
| import com.intellij.execution.ui.ConsoleView; |
| import com.intellij.execution.ui.ConsoleViewContentType; |
| import com.intellij.execution.ui.ObservableConsoleView; |
| import com.intellij.icons.AllIcons; |
| import com.intellij.ide.util.PropertiesComponent; |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.actionSystem.AnAction; |
| import com.intellij.openapi.actionSystem.AnActionEvent; |
| import com.intellij.openapi.actionSystem.Presentation; |
| import com.intellij.openapi.actionSystem.ToggleAction; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.project.DumbAware; |
| import com.intellij.openapi.util.Disposer; |
| import com.intellij.util.ArrayUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| public class DuplexConsoleView<S extends ConsoleView, T extends ConsoleView> extends JPanel implements ConsoleView, ObservableConsoleView { |
| private final static String PRIMARY_CONSOLE_PANEL = "PRIMARY_CONSOLE_PANEL"; |
| private final static String SECONDARY_CONSOLE_PANEL = "SECONDARY_CONSOLE_PANEL"; |
| |
| @NotNull |
| private final S myPrimaryConsoleView; |
| @NotNull |
| private final T mySecondaryConsoleView; |
| @Nullable |
| private final String myStateStorageKey; |
| |
| private boolean myPrimary; |
| @Nullable |
| private ProcessHandler myProcessHandler; |
| @NotNull |
| private final SwitchDuplexConsoleViewAction mySwitchConsoleAction; |
| |
| |
| public DuplexConsoleView(@NotNull S primaryConsoleView, @NotNull T secondaryConsoleView) { |
| this(primaryConsoleView, secondaryConsoleView, null); |
| } |
| |
| public DuplexConsoleView(@NotNull S primaryConsoleView, @NotNull T secondaryConsoleView, @Nullable String stateStorageKey) { |
| super(new CardLayout()); |
| myPrimaryConsoleView = primaryConsoleView; |
| mySecondaryConsoleView = secondaryConsoleView; |
| myStateStorageKey = stateStorageKey; |
| |
| add(myPrimaryConsoleView.getComponent(), PRIMARY_CONSOLE_PANEL); |
| add(mySecondaryConsoleView.getComponent(), SECONDARY_CONSOLE_PANEL); |
| |
| mySwitchConsoleAction = new SwitchDuplexConsoleViewAction(); |
| |
| myPrimary = true; |
| enableConsole(getStoredState()); |
| |
| Disposer.register(this, myPrimaryConsoleView); |
| Disposer.register(this, mySecondaryConsoleView); |
| } |
| |
| public static <S extends ConsoleView, T extends ConsoleView> DuplexConsoleView<S, T> create(@NotNull S primary, |
| @NotNull T secondary, |
| @Nullable String stateStorageKey) { |
| return new DuplexConsoleView<S, T>(primary, secondary, stateStorageKey); |
| } |
| |
| private void setStoredState(boolean primary) { |
| if (myStateStorageKey != null) { |
| PropertiesComponent.getInstance().setValue(myStateStorageKey, String.valueOf(primary)); |
| } |
| } |
| |
| private boolean getStoredState() { |
| if (myStateStorageKey == null) { |
| return false; |
| } |
| return PropertiesComponent.getInstance().getBoolean(myStateStorageKey, false); |
| } |
| |
| public void enableConsole(boolean primary) { |
| if (primary == myPrimary) { |
| // nothing to do |
| return; |
| } |
| |
| CardLayout cl = (CardLayout)(getLayout()); |
| cl.show(this, primary ? PRIMARY_CONSOLE_PANEL : SECONDARY_CONSOLE_PANEL); |
| |
| getSubConsoleView(primary).getComponent().requestFocus(); |
| |
| myPrimary = primary; |
| } |
| |
| public boolean isPrimaryConsoleEnabled() { |
| return myPrimary; |
| } |
| |
| @NotNull |
| public S getPrimaryConsoleView() { |
| return myPrimaryConsoleView; |
| } |
| |
| @NotNull |
| public T getSecondaryConsoleView() { |
| return mySecondaryConsoleView; |
| } |
| |
| public ConsoleView getSubConsoleView(boolean primary) { |
| return primary ? getPrimaryConsoleView() : getSecondaryConsoleView(); |
| } |
| |
| @Override |
| public void print(@NotNull String s, @NotNull ConsoleViewContentType contentType) { |
| myPrimaryConsoleView.print(s, contentType); |
| mySecondaryConsoleView.print(s, contentType); |
| } |
| |
| @Override |
| public void clear() { |
| myPrimaryConsoleView.clear(); |
| mySecondaryConsoleView.clear(); |
| } |
| |
| @Override |
| public void scrollTo(int offset) { |
| myPrimaryConsoleView.scrollTo(offset); |
| mySecondaryConsoleView.scrollTo(offset); |
| } |
| |
| @Override |
| public void attachToProcess(ProcessHandler processHandler) { |
| myProcessHandler = processHandler; |
| |
| myPrimaryConsoleView.attachToProcess(processHandler); |
| mySecondaryConsoleView.attachToProcess(processHandler); |
| } |
| |
| @Override |
| public void setOutputPaused(boolean value) { |
| myPrimaryConsoleView.setOutputPaused(value); |
| mySecondaryConsoleView.setOutputPaused(value); |
| } |
| |
| @Override |
| public boolean isOutputPaused() { |
| return false; |
| } |
| |
| @Override |
| public boolean hasDeferredOutput() { |
| return myPrimaryConsoleView.hasDeferredOutput() && mySecondaryConsoleView.hasDeferredOutput(); |
| } |
| |
| @Override |
| public void performWhenNoDeferredOutput(Runnable runnable) { |
| } |
| |
| @Override |
| public void setHelpId(String helpId) { |
| myPrimaryConsoleView.setHelpId(helpId); |
| mySecondaryConsoleView.setHelpId(helpId); |
| } |
| |
| @Override |
| public void addMessageFilter(Filter filter) { |
| myPrimaryConsoleView.addMessageFilter(filter); |
| mySecondaryConsoleView.addMessageFilter(filter); |
| } |
| |
| @Override |
| public void printHyperlink(String hyperlinkText, HyperlinkInfo info) { |
| myPrimaryConsoleView.printHyperlink(hyperlinkText, info); |
| mySecondaryConsoleView.printHyperlink(hyperlinkText, info); |
| } |
| |
| @Override |
| public int getContentSize() { |
| return myPrimaryConsoleView.getContentSize(); |
| } |
| |
| @Override |
| public boolean canPause() { |
| return false; |
| } |
| |
| |
| @NotNull |
| @Override |
| public AnAction[] createConsoleActions() { |
| List<AnAction> actions = Lists.newArrayList(); |
| actions.addAll(Arrays.asList(myPrimaryConsoleView.createConsoleActions())); |
| |
| actions.add(mySwitchConsoleAction); |
| |
| return ArrayUtil.toObjectArray(actions, AnAction.class); |
| } |
| |
| @Override |
| public void allowHeavyFilters() { |
| myPrimaryConsoleView.allowHeavyFilters(); |
| } |
| |
| @Override |
| public JComponent getComponent() { |
| return this; |
| } |
| |
| @Override |
| public JComponent getPreferredFocusableComponent() { |
| return this; |
| } |
| |
| @Override |
| public void dispose() { |
| // registered children in constructor |
| } |
| |
| @Override |
| public void addChangeListener(@NotNull ChangeListener listener, @NotNull Disposable parent) { |
| if (myPrimaryConsoleView instanceof ObservableConsoleView) { |
| ((ObservableConsoleView)myPrimaryConsoleView).addChangeListener(listener, parent); |
| } |
| if (mySecondaryConsoleView instanceof ObservableConsoleView) { |
| ((ObservableConsoleView)mySecondaryConsoleView).addChangeListener(listener, parent); |
| } |
| } |
| |
| @NotNull |
| public Presentation getSwitchConsoleActionPresentation() { |
| return mySwitchConsoleAction.getTemplatePresentation(); |
| } |
| |
| private class SwitchDuplexConsoleViewAction extends ToggleAction implements DumbAware { |
| |
| public SwitchDuplexConsoleViewAction() { |
| super(ExecutionBundle.message("run.configuration.show.command.line.action.name"), null, |
| AllIcons.Debugger.ToolConsole); |
| } |
| |
| @Override |
| public boolean isSelected(final AnActionEvent event) { |
| return !isPrimaryConsoleEnabled(); |
| } |
| |
| @Override |
| public void setSelected(final AnActionEvent event, final boolean flag) { |
| enableConsole(!flag); |
| setStoredState(!flag); |
| ApplicationManager.getApplication().invokeLater(new Runnable() { |
| @Override |
| public void run() { |
| update(event); |
| } |
| }); |
| } |
| |
| @Override |
| public void update(final AnActionEvent event) { |
| super.update(event); |
| final Presentation presentation = event.getPresentation(); |
| final boolean isRunning = myProcessHandler != null && !myProcessHandler.isProcessTerminated(); |
| if (isRunning) { |
| presentation.setEnabled(true); |
| } |
| else { |
| enableConsole(true); |
| presentation.putClientProperty(SELECTED_PROPERTY, false); |
| presentation.setEnabled(false); |
| } |
| } |
| } |
| } |