| /*=============================================================================# |
| # Copyright (c) 2005, 2018 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.nico.ui.console; |
| |
| import static org.eclipse.statet.ecommons.ui.actions.UIActions.ADDITIONS_GROUP_ID; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.ResourceBundle; |
| import java.util.Set; |
| |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.commands.IHandler2; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.debug.core.DebugEvent; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.IDebugEventSetListener; |
| import org.eclipse.debug.core.model.IDebugTarget; |
| import org.eclipse.debug.core.model.IProcess; |
| import org.eclipse.debug.internal.ui.views.console.ConsoleRemoveAllTerminatedAction; |
| import org.eclipse.debug.internal.ui.views.console.ConsoleRemoveLaunchAction; |
| import org.eclipse.debug.ui.IDebugUIConstants; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.GroupMarker; |
| import org.eclipse.jface.action.IMenuListener; |
| import org.eclipse.jface.action.IMenuListener2; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.IToolBarManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.text.DocumentEvent; |
| import org.eclipse.jface.text.IDocumentListener; |
| import org.eclipse.jface.text.IFindReplaceTarget; |
| import org.eclipse.jface.text.source.SourceViewer; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.TreePath; |
| import org.eclipse.jface.viewers.TreeSelection; |
| import org.eclipse.jface.wizard.WizardDialog; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.dnd.Clipboard; |
| import org.eclipse.swt.dnd.TextTransfer; |
| import org.eclipse.swt.dnd.Transfer; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.KeyListener; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.Sash; |
| import org.eclipse.swt.widgets.ScrollBar; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Widget; |
| import org.eclipse.ui.IActionBars; |
| import org.eclipse.ui.IWorkbenchActionConstants; |
| import org.eclipse.ui.IWorkbenchCommandConstants; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.actions.ActionFactory; |
| import org.eclipse.ui.console.IConsoleConstants; |
| import org.eclipse.ui.console.IConsoleView; |
| import org.eclipse.ui.console.TextConsoleViewer; |
| import org.eclipse.ui.console.actions.ClearOutputAction; |
| import org.eclipse.ui.editors.text.EditorsUI; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.menus.CommandContributionItem; |
| import org.eclipse.ui.menus.CommandContributionItemParameter; |
| import org.eclipse.ui.part.IPageBookViewPage; |
| import org.eclipse.ui.part.IPageSite; |
| import org.eclipse.ui.part.IShowInSource; |
| import org.eclipse.ui.part.IShowInTargetList; |
| import org.eclipse.ui.part.ShowInContext; |
| import org.eclipse.ui.services.IServiceLocator; |
| import org.eclipse.ui.texteditor.FindReplaceAction; |
| |
| import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet; |
| |
| import org.eclipse.statet.ecommons.preferences.PreferencesUtil; |
| import org.eclipse.statet.ecommons.preferences.SettingsChangeNotifier.ChangeListener; |
| import org.eclipse.statet.ecommons.text.ui.TextViewerAction; |
| import org.eclipse.statet.ecommons.text.ui.TextViewerEditorColorUpdater; |
| import org.eclipse.statet.ecommons.ts.core.util.ActiveToolListener; |
| import org.eclipse.statet.ecommons.ts.core.util.ActiveToolListener.ActiveToolEvent; |
| import org.eclipse.statet.ecommons.ts.core.util.ToolProvider; |
| import org.eclipse.statet.ecommons.ui.ISettingsChangedHandler; |
| import org.eclipse.statet.ecommons.ui.SharedMessages; |
| import org.eclipse.statet.ecommons.ui.actions.HandlerCollection; |
| import org.eclipse.statet.ecommons.ui.actions.HandlerContributionItem; |
| import org.eclipse.statet.ecommons.ui.actions.SimpleContributionItem; |
| import org.eclipse.statet.ecommons.ui.dialogs.DialogUtils; |
| import org.eclipse.statet.ecommons.ui.util.DNDUtils; |
| import org.eclipse.statet.ecommons.ui.util.LayoutUtils; |
| import org.eclipse.statet.ecommons.ui.util.NestedServices; |
| import org.eclipse.statet.ecommons.ui.util.UIAccess; |
| import org.eclipse.statet.ecommons.ui.workbench.ContextHandlers; |
| |
| import org.eclipse.statet.internal.nico.ui.LocalTaskTransfer; |
| import org.eclipse.statet.internal.nico.ui.Messages; |
| import org.eclipse.statet.internal.nico.ui.NicoUIPlugin; |
| import org.eclipse.statet.internal.nico.ui.console.OutputViewer; |
| import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditorViewerConfigurator; |
| import org.eclipse.statet.nico.core.runtime.Prompt; |
| import org.eclipse.statet.nico.core.runtime.Queue; |
| import org.eclipse.statet.nico.core.runtime.ToolController; |
| import org.eclipse.statet.nico.core.runtime.ToolProcess; |
| import org.eclipse.statet.nico.core.runtime.ToolStatus; |
| import org.eclipse.statet.nico.core.runtime.ToolWorkspace; |
| import org.eclipse.statet.nico.ui.NicoUI; |
| import org.eclipse.statet.nico.ui.actions.CancelHandler; |
| import org.eclipse.statet.nico.ui.util.ExportConsoleOutputWizard; |
| import org.eclipse.statet.nico.ui.util.NicoWizardDialog; |
| import org.eclipse.statet.nico.ui.util.OpenTrackingFilesContributionItem; |
| |
| |
| /** |
| * A page for a <code>NIConsole</code>. |
| * <p> |
| * The page contains beside the usual output viewer |
| * a separete input field with submit button. |
| */ |
| public abstract class NIConsolePage implements IPageBookViewPage, |
| IAdaptable, IShowInSource, IShowInTargetList, |
| IPropertyChangeListener, ScrollLockAction.Receiver, ToolProvider, ChangeListener { |
| |
| |
| private static final String DIALOG_ID= "Console"; //$NON-NLS-1$ |
| private static final String SETTING_INPUTHEIGHT= "InputHeight"; //$NON-NLS-1$ |
| |
| public static final String NICO_CONTROL_MENU_ID= "nico.control"; //$NON-NLS-1$ |
| |
| |
| private class FindReplaceUpdater implements IDocumentListener { |
| |
| private boolean wasEmpty= true; |
| |
| @Override |
| public void documentAboutToBeChanged(final DocumentEvent event) { |
| } |
| |
| @Override |
| public void documentChanged(final DocumentEvent event) { |
| final boolean isEmpty= (event.fDocument.getLength() == 0); |
| if (isEmpty != this.wasEmpty) { |
| NIConsolePage.this.multiActionHandler.updateEnabledState(); |
| this.wasEmpty= isEmpty; |
| } |
| } |
| |
| } |
| |
| private class PostUpdater implements IDocumentListener, Runnable { |
| |
| private volatile boolean fIsSheduled= false; |
| |
| @Override |
| public void documentAboutToBeChanged(final DocumentEvent event) { |
| } |
| |
| @Override |
| public void documentChanged(final DocumentEvent event) { |
| if (!this.fIsSheduled) { |
| this.fIsSheduled= true; |
| final Display display= UIAccess.getDisplay(getSite().getShell()); |
| display.asyncExec(this); |
| } |
| } |
| |
| @Override |
| public void run() { |
| // post change run |
| this.fIsSheduled= false; |
| NIConsolePage.this.multiActionHandler.updateEnabledState(); |
| } |
| |
| } |
| |
| private class SizeController implements Listener { |
| |
| private final Sash fSash; |
| private final GridData fOutputGD; |
| private final GridData fInputGD; |
| private int fLastExplicit; |
| |
| public SizeController(final Sash sash, final GridData outputGD, final GridData inputGD) { |
| this.fSash= sash; |
| this.fOutputGD= outputGD; |
| this.fInputGD= inputGD; |
| this.fLastExplicit= -1; |
| } |
| |
| @Override |
| public void handleEvent(final Event event) { |
| if (event.widget == this.fSash) { |
| if (event.type == SWT.Selection && event.detail != SWT.DRAG) { |
| final Rectangle bounds= NIConsolePage.this.control.getClientArea(); |
| // System.out.println(bounds.height); |
| // Rectangle bounds2= fInputGroup.getComposite().getBounds(); |
| // System.out.println(bounds2.y+bounds2.height); |
| |
| setNewInputHeight(bounds.height - event.y - this.fSash.getSize().y, true); |
| } |
| return; |
| } |
| if (event.widget == NIConsolePage.this.control) { |
| if (event.type == SWT.Resize) { |
| setNewInputHeight(this.fInputGD.heightHint, false); |
| } |
| } |
| } |
| |
| private void setNewInputHeight(int height, final boolean explicit) { |
| if (!explicit) { |
| height= this.fLastExplicit; |
| } |
| if (height == -1) { |
| return; |
| } |
| final Rectangle bounds= NIConsolePage.this.control.getClientArea(); |
| final int max= bounds.height - this.fOutputGD.minimumHeight - this.fSash.getSize().y; |
| if (height > max) { |
| height= max; |
| } |
| if (height < this.fInputGD.minimumHeight) { |
| height= -1; |
| } |
| if (explicit) { |
| this.fLastExplicit= height; |
| } |
| |
| if (this.fInputGD.heightHint == height) { |
| return; |
| } |
| this.fInputGD.heightHint= height; |
| NIConsolePage.this.control.layout(new Control[] { NIConsolePage.this.inputGroup.getComposite() }); |
| } |
| |
| private void fontChanged() { |
| this.fOutputGD.minimumHeight= LayoutUtils.hintHeight(NIConsolePage.this.outputViewer.getTextWidget(), 4); |
| final ScrollBar bar= NIConsolePage.this.outputViewer.getTextWidget().getHorizontalBar(); |
| if (bar.isVisible()) { |
| this.fOutputGD.minimumHeight+= bar.getSize().y; |
| } |
| this.fInputGD.minimumHeight= NIConsolePage.this.inputGroup.getComposite().computeSize(800, -1).y; |
| if (this.fInputGD.heightHint != -1 |
| && this.fInputGD.minimumHeight > this.fInputGD.heightHint) { |
| this.fInputGD.heightHint= -1; |
| } |
| } |
| |
| } |
| |
| private class StatusListener implements IDebugEventSetListener { |
| |
| private boolean isProcessing= false; |
| private boolean isTerminated= false; |
| |
| private int updateId= Integer.MIN_VALUE; |
| private Prompt fNewPrompt= null; |
| private boolean fCurrentBusy= false; |
| private boolean fNewBusy= false; |
| |
| public void init() { |
| final ToolController controller= getConsole().getProcess().getController(); |
| synchronized (StatusListener.this) { |
| if (controller != null) { |
| final ToolStatus status= controller.getStatus(); |
| this.isProcessing= (status == ToolStatus.STARTED_PROCESSING || status == ToolStatus.STARTING); |
| this.isTerminated= (status == ToolStatus.TERMINATED); |
| this.fCurrentBusy= this.fNewBusy= (this.isProcessing || this.isTerminated); |
| } |
| else { |
| this.isProcessing= false; |
| this.isTerminated= true; |
| this.fCurrentBusy= this.fNewBusy= true; |
| } |
| NIConsolePage.this.inputGroup.updatePrompt(null); |
| NIConsolePage.this.inputGroup.updateBusy(this.fCurrentBusy); |
| } |
| } |
| |
| @Override |
| public void handleDebugEvents(final DebugEvent[] events) { |
| final ToolProcess process= getConsole().getProcess(); |
| final ToolWorkspace data= process.getWorkspaceData(); |
| |
| Prompt prompt= null; |
| boolean match= false; |
| |
| ITER_EVENTS: for (final DebugEvent event : events) { |
| if (event.getSource() == process) { |
| if (event.getKind() == DebugEvent.TERMINATE) { |
| match= true; |
| this.isTerminated= true; |
| onToolTerminated(); |
| } |
| continue ITER_EVENTS; |
| } |
| if (event.getSource() == process.getQueue()) { |
| if (Queue.isStateChange(event)) { |
| final Queue.StateDelta delta= (Queue.StateDelta) event.getData(); |
| match= true; |
| this.isProcessing= (delta.newState == Queue.PROCESSING_STATE); |
| this.isTerminated= (delta.newState == Queue.TERMINATED_STATE); |
| } |
| continue ITER_EVENTS; |
| } |
| if (event.getSource() == data) { |
| if (event.getKind() == DebugEvent.CHANGE |
| && event.getDetail() == ToolWorkspace.DETAIL_PROMPT) { |
| match= true; |
| prompt= (Prompt) event.getData(); |
| } |
| continue ITER_EVENTS; |
| } |
| } |
| if (!match) { |
| return; |
| } |
| final int thisId; |
| final long schedule; |
| synchronized (StatusListener.this) { |
| this.fNewBusy= this.isProcessing || this.isTerminated; |
| schedule= (this.fNewBusy) ? (System.nanoTime() + 50000000L) : System.nanoTime(); |
| if (prompt != null) { |
| this.fNewPrompt= prompt; |
| } |
| if (!NIConsolePage.this.isCreated || |
| (this.fNewBusy == this.fCurrentBusy && this.fNewPrompt == null)) { |
| return; |
| } |
| thisId= ++this.updateId; |
| } |
| UIAccess.getDisplay().asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| final long diff= (schedule - System.nanoTime()) / 1000000L; |
| if (diff > 5) { |
| Display.getCurrent().timerExec((int) diff, this); |
| return; |
| } |
| if (!NIConsolePage.this.isCreated) { |
| return; |
| } |
| synchronized (StatusListener.this) { |
| if (thisId != StatusListener.this.updateId) { |
| return; |
| } |
| if (StatusListener.this.fNewPrompt != null) { |
| NIConsolePage.this.inputGroup.updatePrompt(StatusListener.this.fNewPrompt); |
| StatusListener.this.fNewPrompt= null; |
| } |
| if (StatusListener.this.fNewBusy != StatusListener.this.fCurrentBusy) { |
| NIConsolePage.this.inputGroup.updateBusy(StatusListener.this.fNewBusy); |
| StatusListener.this.fCurrentBusy= StatusListener.this.fNewBusy; |
| } |
| } |
| }; |
| }); |
| } |
| |
| } |
| |
| |
| private final NIConsole console; |
| private final IConsoleView consoleView; |
| private IPageSite site; |
| private Composite control; |
| private Clipboard clipboard; |
| |
| private OutputViewer outputViewer; |
| private ConsolePageEditor inputGroup; |
| private SizeController resizer; |
| private MenuManager outputMenuManager; |
| private MenuManager inputMenuManager; |
| |
| private volatile boolean isCreated= false; |
| |
| // Actions |
| private MultiActionHandler multiActionHandler; |
| private final CopyOnWriteIdentityListSet<ActiveToolListener> toolListeners= new CopyOnWriteIdentityListSet<>(); |
| NestedServices inputServices; |
| |
| private FindReplaceUpdater findReplaceUpdater; |
| private FindReplaceAction findReplaceAction; |
| |
| // Output viewer actions |
| private TextViewerAction outputCopyAction; |
| private SubmitPasteAction outputPasteAction; |
| private TextViewerAction outputSelectAllAction; |
| private ClearOutputAction outputClearAllAction; |
| private Action outputScrollLockAction; |
| |
| // Input viewer actions |
| private TextViewerAction inputDeleteAction; |
| private TextViewerAction inputCutAction; |
| private TextViewerAction inputCopyAction; |
| private TextViewerAction inputPasteAction; |
| private TextViewerAction inputSelectAllAction; |
| private TextViewerAction inputUndoAction; |
| private TextViewerAction inputRedoAction; |
| |
| // Process control actions |
| private StatusListener debugListener; |
| private ConsoleRemoveLaunchAction removeAction; |
| private ConsoleRemoveAllTerminatedAction removeAllAction; |
| private TerminateToolAction terminateAction; |
| |
| private ContextHandlers pageHandlers; |
| private ContextHandlers inputHandlers; |
| |
| |
| /** |
| * Constructs a console page for the given console in the given view. |
| * |
| * @param console the console |
| * @param view the console view the page is contained in |
| */ |
| public NIConsolePage(final NIConsole console, final IConsoleView view) { |
| this.console= console; |
| this.consoleView= view; |
| } |
| |
| |
| @Override |
| public void init(final IPageSite site) throws PartInitException { |
| this.site= site; |
| this.inputGroup= createInputGroup(); |
| |
| this.debugListener= new StatusListener(); |
| DebugPlugin.getDefault().addDebugEventListener(this.debugListener); |
| } |
| |
| protected ConsolePageEditor createInputGroup() { |
| return new ConsolePageEditor(this, null); |
| } |
| |
| protected ConsolePageEditor getInputGroup() { |
| return this.inputGroup; |
| } |
| |
| @Override |
| public void createControl(final Composite parent) { |
| PreferencesUtil.getSettingsChangeNotifier().addChangeListener(this); |
| this.console.addPropertyChangeListener(this); |
| |
| this.control= new Composite(parent, SWT.NONE) { |
| @Override |
| public boolean setFocus() { |
| NIConsolePage.this.setFocus(); |
| return true; |
| } |
| @Override |
| public void setVisible(final boolean visible) { |
| super.setVisible(visible); |
| if (visible) { |
| NIConsolePage.this.setFocus(); |
| } |
| } |
| @Override |
| public void redraw() { |
| super.redraw(); |
| |
| // required for hyperlinks / org.eclipse.ui.internal.console.ConsoleManager$RepaintJob |
| if (UIAccess.isOkToUse(NIConsolePage.this.outputViewer)) { |
| NIConsolePage.this.outputViewer.getControl().redraw(); |
| } |
| } |
| }; |
| final GridLayout layout= new GridLayout(1, false); |
| layout.marginHeight= 0; |
| layout.verticalSpacing= 0; |
| layout.marginWidth= 0; |
| this.control.setLayout(layout); |
| |
| this.outputViewer= new OutputViewer(this.control, this.console); |
| final GridData outputGD= new GridData(SWT.FILL, SWT.FILL, true, true); |
| this.outputViewer.getControl().setLayoutData(outputGD); |
| |
| new TextViewerEditorColorUpdater(this.outputViewer, EditorsUI.getPreferenceStore()); |
| |
| this.outputViewer.getTextWidget().addKeyListener(new KeyListener() { |
| @Override |
| public void keyPressed(final KeyEvent e) { |
| if (e.doit |
| && (e.character > 0) |
| && (e.stateMask == SWT.NONE || e.stateMask == SWT.SHIFT) |
| && ((e.keyCode & SWT.KEYCODE_BIT) == 0) ) { |
| final StyledText textWidget= NIConsolePage.this.inputGroup.getViewer().getTextWidget(); |
| if (!UIAccess.isOkToUse(textWidget)) { |
| return; |
| } |
| final int cType= Character.getType(e.character); |
| if (cType > 0 && cType < Character.CONTROL && textWidget.getCharCount() == 0) { |
| textWidget.replaceTextRange(0, 0, Character.toString(e.character)); |
| textWidget.setCaretOffset(textWidget.getCharCount()); |
| } |
| else { |
| Display.getCurrent().beep(); |
| } |
| setFocus(); |
| } |
| } |
| @Override |
| public void keyReleased(final KeyEvent e) { |
| } |
| }); |
| |
| final Sash sash= new Sash(this.control, SWT.HORIZONTAL); |
| // sash.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW)); |
| sash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); |
| |
| this.inputGroup.createControl(this.control, createInputEditorConfigurator()); |
| final GridData inputGD= new GridData(SWT.FILL, SWT.FILL, true, false); |
| this.inputGroup.getComposite().setLayoutData(inputGD); |
| |
| this.outputViewer.getTextWidget().getHorizontalBar().setVisible(false); |
| |
| this.resizer= new SizeController(sash, outputGD, inputGD); |
| sash.addListener(SWT.Selection, this.resizer); |
| this.control.addListener(SWT.Resize, this.resizer); |
| |
| this.clipboard= new Clipboard(this.control.getDisplay()); |
| initActions(); |
| hookContextMenu(); |
| hookDND(); |
| contributeToActionBars(getSite(), getSite().getActionBars(), this.pageHandlers); |
| |
| new ConsoleActivationNotifier(); |
| this.isCreated= true; |
| this.debugListener.init(); |
| |
| final IDialogSettings dialogSettings= DialogUtils.getDialogSettings(NicoUIPlugin.getInstance(), DIALOG_ID); |
| try { |
| final int height= dialogSettings.getInt(SETTING_INPUTHEIGHT); |
| if (height > 0) { |
| this.resizer.fLastExplicit= height; |
| } |
| } |
| catch (final NumberFormatException e) { |
| // missing value |
| } |
| this.resizer.fontChanged(); |
| |
| Display.getCurrent().asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| if (NIConsolePage.this.inputGroup != null && UIAccess.isOkToUse(NIConsolePage.this.inputGroup.getViewer())) { |
| NIConsolePage.this.outputViewer.revealEndOfDocument(); |
| if (NIConsolePage.this.outputViewer.getControl().isFocusControl()) { |
| setFocus(); |
| } |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Creates the adapter to configure the input source viewer. |
| * Will be disposed automatically. |
| * |
| * @return the adapter |
| */ |
| protected abstract SourceEditorViewerConfigurator createInputEditorConfigurator(); |
| |
| |
| private class ConsoleActivationNotifier implements Listener { |
| |
| private ConsoleActivationNotifier() { |
| NIConsolePage.this.control.addListener(SWT.Activate, this); |
| NIConsolePage.this.control.addListener(SWT.Deactivate, this); |
| NIConsolePage.this.control.addListener(SWT.Dispose, this); |
| if (NIConsolePage.this.control.isVisible()) { |
| activated(); |
| } |
| } |
| |
| @Override |
| public void handleEvent(final Event event) { |
| switch (event.type) { |
| case SWT.Activate: |
| activated(); |
| break; |
| case SWT.Deactivate: |
| deactivated(); |
| break; |
| case SWT.Dispose: |
| NIConsolePage.this.control.removeListener(SWT.Activate, this); |
| NIConsolePage.this.control.removeListener(SWT.Dispose, this); |
| break; |
| } |
| } |
| |
| } |
| |
| private void activated() { |
| NicoUIPlugin.getInstance().getToolRegistry().consoleActivated(this.consoleView, this.console); |
| |
| // E-Bug 473941 |
| final IEclipseContext service= this.site.getService(IEclipseContext.class); |
| if (service != null) { |
| service.activate(); |
| } |
| } |
| |
| private void deactivated() { |
| // E-Bug 473941 |
| final IEclipseContext service= this.site.getService(IEclipseContext.class); |
| if (service != null) { |
| service.deactivate(); |
| } |
| } |
| |
| private void initActions() { |
| final Control outputControl= this.outputViewer.getControl(); |
| final SourceViewer inputViewer= this.inputGroup.getViewer(); |
| final Control inputControl= inputViewer.getControl(); |
| |
| final IServiceLocator pageServiceLocator= getSite(); |
| this.inputServices= new NestedServices(pageServiceLocator, "ConsoleInput"); |
| this.inputServices.bindTo(inputControl); |
| |
| final IHandlerService pageHandlerService= pageServiceLocator |
| .getService(IHandlerService.class); |
| this.pageHandlers= new ContextHandlers(pageHandlerService); |
| final IHandlerService inputHandlerService= this.inputServices.getLocator() |
| .getService(IHandlerService.class); |
| this.inputHandlers= new ContextHandlers(inputHandlerService); |
| |
| this.multiActionHandler= new MultiActionHandler(); |
| |
| this.removeAction= new ConsoleRemoveLaunchAction(this.console.getProcess().getLaunch()); |
| this.removeAllAction= new ConsoleRemoveAllTerminatedAction(); |
| this.terminateAction= new TerminateToolAction(this.console.getProcess()); |
| { final IHandler2 handler= new CancelHandler(this, ToolController.CANCEL_CURRENT); |
| this.pageHandlers.add(NicoUI.CANCEL_CURRENT_COMMAND_ID, handler); |
| pageHandlerService.activateHandler(NicoUI.CANCEL_CURRENT_COMMAND_ID, handler); |
| } |
| { final IHandler2 handler= new CancelHandler(this, ToolController.CANCEL_ALL); |
| this.pageHandlers.add(NicoUI.CANCEL_ALL_COMMAND_ID, handler); |
| pageHandlerService.activateHandler(NicoUI.CANCEL_ALL_COMMAND_ID, handler); |
| } |
| { final IHandler2 handler= new CancelHandler(this, ToolController.CANCEL_CURRENT | ToolController.CANCEL_PAUSE); |
| this.pageHandlers.add(NicoUI.CANCEL_PAUSE_COMMAND_ID, handler); |
| pageHandlerService.activateHandler(NicoUI.CANCEL_PAUSE_COMMAND_ID, handler); |
| } |
| |
| // Conflict with binding CTRL+Z (in console EOF) |
| // pageKeys.activateContext("org.eclipse.debug.ui.console"); //$NON-NLS-1$ |
| |
| this.outputCopyAction= TextViewerAction.createCopyAction(this.outputViewer); |
| this.multiActionHandler.addGlobalAction(outputControl, ActionFactory.COPY.getId(), this.outputCopyAction); |
| this.outputPasteAction= new SubmitPasteAction(this); |
| this.outputPasteAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_PASTE); |
| this.multiActionHandler.addGlobalAction(outputControl, ActionFactory.PASTE.getId(), this.outputPasteAction); |
| this.outputSelectAllAction= TextViewerAction.createSelectAllAction(this.outputViewer); |
| this.multiActionHandler.addGlobalAction(outputControl, ActionFactory.SELECT_ALL.getId(), this.outputSelectAllAction); |
| |
| this.outputClearAllAction= new ClearOutputAction(this.console); |
| this.outputScrollLockAction= new ScrollLockAction(this, false); |
| |
| this.inputDeleteAction= TextViewerAction.createDeleteAction(inputViewer); |
| this.multiActionHandler.addGlobalAction(inputControl, ActionFactory.DELETE.getId(), this.inputDeleteAction); |
| this.inputCutAction= TextViewerAction.createCutAction(inputViewer); |
| this.multiActionHandler.addGlobalAction(inputControl, ActionFactory.CUT.getId(), this.inputCutAction); |
| this.inputCopyAction= TextViewerAction.createCopyAction(inputViewer); |
| this.multiActionHandler.addGlobalAction(inputControl, ActionFactory.COPY.getId(), this.inputCopyAction); |
| this.inputPasteAction= TextViewerAction.createPasteAction(inputViewer); |
| this.multiActionHandler.addGlobalAction(inputControl, ActionFactory.PASTE.getId(), this.inputPasteAction); |
| this.inputSelectAllAction= TextViewerAction.createSelectAllAction(inputViewer); |
| this.multiActionHandler.addGlobalAction(inputControl, ActionFactory.SELECT_ALL.getId(), this.inputSelectAllAction); |
| |
| this.inputUndoAction= TextViewerAction.createUndoAction(inputViewer); |
| this.multiActionHandler.addGlobalAction(inputControl, ActionFactory.UNDO.getId(), this.inputUndoAction); |
| this.inputRedoAction= TextViewerAction.createRedoAction(inputViewer); |
| this.multiActionHandler.addGlobalAction(inputControl, ActionFactory.REDO.getId(), this.inputRedoAction); |
| |
| final ResourceBundle bundle= SharedMessages.getCompatibilityBundle(); |
| this.findReplaceAction= new FindReplaceAction(bundle, "FindReplaceAction_", this.consoleView); //$NON-NLS-1$ |
| this.findReplaceAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_FIND_AND_REPLACE); |
| this.multiActionHandler.addGlobalAction(outputControl, ActionFactory.FIND.getId(), this.findReplaceAction); |
| this.multiActionHandler.addGlobalAction(inputControl, ActionFactory.FIND.getId(), this.findReplaceAction); |
| this.findReplaceUpdater= new FindReplaceUpdater(); |
| this.console.getDocument().addDocumentListener(this.findReplaceUpdater); |
| inputViewer.getDocument().addDocumentListener(new PostUpdater()); |
| |
| inputViewer.addSelectionChangedListener(this.multiActionHandler); |
| this.outputViewer.addSelectionChangedListener(this.multiActionHandler); |
| |
| initActions(getSite(), this.pageHandlers); |
| this.inputGroup.initActions(this.inputServices.getLocator(), this.inputHandlers); |
| } |
| |
| protected void initActions(final IServiceLocator serviceLocator, final HandlerCollection handlers) { |
| } |
| |
| private void hookContextMenu() { |
| String id= NIConsole.NICONSOLE_TYPE + "#OutputContextMenu"; //$NON-NLS-1$ |
| this.outputMenuManager= new MenuManager("ContextMenu", id); //$NON-NLS-1$ |
| this.outputMenuManager.setRemoveAllWhenShown(true); |
| this.outputMenuManager.addMenuListener(new IMenuListener() { |
| @Override |
| public void menuAboutToShow(final IMenuManager manager) { |
| fillOutputContextMenu(manager); |
| } |
| }); |
| Control control= this.outputViewer.getControl(); |
| Menu menu= this.outputMenuManager.createContextMenu(control); |
| control.setMenu(menu); |
| getSite().registerContextMenu(id, this.outputMenuManager, this.outputViewer); |
| |
| id= NIConsole.NICONSOLE_TYPE + "#InputContextMenu"; //$NON-NLS-1$ |
| this.inputMenuManager= new MenuManager("ContextMenu", id); //$NON-NLS-1$ |
| this.inputMenuManager.setRemoveAllWhenShown(true); |
| this.inputMenuManager.addMenuListener(new IMenuListener() { |
| @Override |
| public void menuAboutToShow(final IMenuManager manager) { |
| fillInputContextMenu(manager); |
| } |
| }); |
| control= this.inputGroup.getViewer().getControl(); |
| menu= this.inputMenuManager.createContextMenu(control); |
| control.setMenu(menu); |
| getSite().registerContextMenu(id, this.inputMenuManager, this.inputGroup.getViewer()); |
| } |
| |
| protected void hookDND() { |
| DNDUtils.addDropSupport(this.outputViewer.getControl(), |
| new SubmitDropAdapter(this), |
| new Transfer[] { |
| TextTransfer.getInstance(), |
| LocalTaskTransfer.getTransfer() |
| } ); |
| } |
| |
| protected void contributeToActionBars(final IServiceLocator serviceLocator, |
| final IActionBars actionBars, final HandlerCollection handlers) { |
| this.multiActionHandler.registerActions(actionBars); |
| |
| final IToolBarManager toolBarManager= actionBars.getToolBarManager(); |
| toolBarManager.appendToGroup(IConsoleConstants.OUTPUT_GROUP, this.outputClearAllAction); |
| toolBarManager.appendToGroup(IConsoleConstants.OUTPUT_GROUP, this.outputScrollLockAction); |
| |
| toolBarManager.appendToGroup(IConsoleConstants.LAUNCH_GROUP, new HandlerContributionItem( |
| new CommandContributionItemParameter(serviceLocator, CancelHandler.MENU_ID, |
| NicoUI.CANCEL_CURRENT_COMMAND_ID, null, |
| null, null, null, |
| Messages.CancelAction_name, null, Messages.CancelAction_tooltip, |
| HandlerContributionItem.STYLE_PULLDOWN, null, false), |
| this.pageHandlers.get(NicoUI.CANCEL_CURRENT_COMMAND_ID) ) { |
| // Workaround for E-Bug #366528 |
| @Override |
| protected void initDropDownMenu(final MenuManager menuManager) { |
| menuManager.addMenuListener(new IMenuListener2() { |
| @Override |
| public void menuAboutToShow(final IMenuManager manager) { |
| manager.add(new CommandContributionItem( |
| new CommandContributionItemParameter(serviceLocator, |
| null, NicoUI.CANCEL_CURRENT_COMMAND_ID, |
| CommandContributionItem.STYLE_PUSH ))); |
| manager.add(new CommandContributionItem( |
| new CommandContributionItemParameter(serviceLocator, |
| null, NicoUI.CANCEL_PAUSE_COMMAND_ID, |
| CommandContributionItem.STYLE_PUSH ))); |
| manager.add(new CommandContributionItem( |
| new CommandContributionItemParameter(serviceLocator, |
| null, NicoUI.CANCEL_ALL_COMMAND_ID, |
| CommandContributionItem.STYLE_PUSH ))); |
| } |
| @Override |
| public void menuAboutToHide(final IMenuManager manager) { |
| display.asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| menuManager.dispose(); |
| } |
| }); |
| } |
| }); |
| } |
| }); |
| toolBarManager.appendToGroup(IConsoleConstants.LAUNCH_GROUP, this.terminateAction); |
| toolBarManager.appendToGroup(IConsoleConstants.LAUNCH_GROUP, this.removeAction); |
| toolBarManager.appendToGroup(IConsoleConstants.LAUNCH_GROUP, this.removeAllAction); |
| |
| final IMenuManager menuManager= actionBars.getMenuManager(); |
| menuManager.add(new Separator(NICO_CONTROL_MENU_ID)); |
| menuManager.add(new Separator(ADDITIONS_GROUP_ID)); |
| |
| menuManager.add(new Separator("tracking")); //$NON-NLS-1$ |
| final MenuManager trackingMenu= new MenuManager("Open In Editor") { |
| @Override |
| public boolean isVisible() { |
| return !getTool().getTracks().isEmpty(); |
| } |
| }; |
| trackingMenu.add(new OpenTrackingFilesContributionItem(getTool())); |
| menuManager.add(trackingMenu); |
| menuManager.add(new SimpleContributionItem("Export Console Output...", null) { |
| @Override |
| protected void execute() throws ExecutionException { |
| final ToolProcess tool= getTool(); |
| if (tool == null) { |
| return; |
| } |
| final ExportConsoleOutputWizard wizard= new ExportConsoleOutputWizard(NIConsolePage.this); |
| final WizardDialog dialog= new NicoWizardDialog(getSite().getShell(), wizard); |
| dialog.setBlockOnOpen(false); |
| dialog.open(); |
| } |
| }); |
| |
| menuManager.add(new Separator("settings")); //$NON-NLS-1$ |
| menuManager.add(new SimpleContributionItem("Preferences...", "P") { |
| @Override |
| protected void execute() throws ExecutionException { |
| final Shell shell= getSite().getShell(); |
| final List<String> pageIds= new ArrayList<>(); |
| NIConsolePage.this.collectContextMenuPreferencePages(pageIds); |
| if (!pageIds.isEmpty() && (shell == null || !shell.isDisposed())) { |
| org.eclipse.ui.dialogs.PreferencesUtil.createPreferenceDialogOn(shell, |
| pageIds.get(0), pageIds.toArray(new String[pageIds.size()]), null) |
| .open(); |
| } |
| } |
| }); |
| |
| menuManager.add(new Separator()); |
| } |
| |
| protected void fillInputContextMenu(final IMenuManager manager) { |
| manager.add(this.inputCutAction); |
| manager.add(this.inputCopyAction); |
| manager.add(this.inputPasteAction); |
| manager.add(new GroupMarker(IWorkbenchActionConstants.CUT_EXT)); |
| |
| manager.add(new Separator()); |
| manager.add(this.inputUndoAction); |
| manager.add(this.inputRedoAction); |
| manager.add(new GroupMarker(IWorkbenchActionConstants.UNDO_EXT)); |
| |
| manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); |
| } |
| |
| protected void fillOutputContextMenu(final IMenuManager manager) { |
| manager.add(this.outputCopyAction); |
| manager.add(this.outputSelectAllAction); |
| |
| manager.add(new Separator("more")); //$NON-NLS-1$ |
| manager.add(this.findReplaceAction); |
| // manager.add(new FollowHyperlinkAction(fViewer)); |
| |
| manager.add(new Separator("submit")); //$NON-NLS-1$ |
| manager.add(this.outputPasteAction); |
| |
| manager.add(new Separator("view")); //$NON-NLS-1$ |
| manager.add(this.outputClearAllAction); |
| manager.add(this.outputScrollLockAction); |
| |
| manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); |
| } |
| |
| @Override |
| public void dispose() { |
| this.console.removePropertyChangeListener(this); |
| PreferencesUtil.getSettingsChangeNotifier().removeChangeListener(this); |
| if (this.debugListener != null) { |
| final DebugPlugin debug= DebugPlugin.getDefault(); |
| if (debug != null) { |
| debug.removeDebugEventListener(this.debugListener); |
| } |
| this.debugListener= null; |
| } |
| |
| if (this.isCreated) { // control created |
| this.isCreated= false; |
| |
| try { |
| this.console.getDocument().removeDocumentListener(this.findReplaceUpdater); |
| this.outputViewer.removeSelectionChangedListener(this.multiActionHandler); |
| this.inputGroup.getViewer().removeSelectionChangedListener(this.multiActionHandler); |
| } |
| catch (final Exception e) { |
| NicoUIPlugin.logError(NicoUIPlugin.INTERNAL_ERROR, Messages.Console_error_UnexpectedException_message, e); |
| } |
| |
| if (this.pageHandlers != null) { |
| this.pageHandlers.dispose(); |
| this.pageHandlers= null; |
| } |
| if (this.inputHandlers != null) { |
| this.inputHandlers.dispose(); |
| this.inputHandlers= null; |
| } |
| |
| this.multiActionHandler.dispose(); |
| this.multiActionHandler= null; |
| this.inputServices.dispose(); |
| this.inputServices= null; |
| |
| this.findReplaceAction= null; |
| |
| this.outputCopyAction= null; |
| this.outputPasteAction= null; |
| this.outputSelectAllAction= null; |
| this.outputClearAllAction= null; |
| |
| this.inputDeleteAction= null; |
| this.inputCutAction= null; |
| this.inputCopyAction= null; |
| this.inputPasteAction= null; |
| this.inputSelectAllAction= null; |
| this.inputUndoAction= null; |
| |
| this.debugListener= null; |
| this.removeAction.dispose(); |
| this.removeAction= null; |
| this.removeAllAction.dispose(); |
| this.removeAllAction= null; |
| this.terminateAction.dispose(); |
| this.terminateAction= null; |
| |
| this.outputViewer= null; |
| } |
| |
| if (this.inputGroup != null) { |
| this.inputGroup.dispose(); |
| this.inputGroup= null; |
| } |
| } |
| |
| |
| @Override |
| public IPageSite getSite() { |
| return this.site; |
| } |
| |
| public IConsoleView getView() { |
| return this.consoleView; |
| } |
| |
| @Override |
| public Control getControl() { |
| return this.control; |
| } |
| |
| public NIConsole getConsole() { |
| return this.console; |
| } |
| |
| public Clipboard getClipboard() { |
| return this.clipboard; |
| } |
| |
| @Override |
| public ToolProcess getTool() { |
| return this.console.getProcess(); |
| } |
| |
| @Override |
| public void addToolListener(final ActiveToolListener listener) { |
| this.toolListeners.add(listener); |
| } |
| |
| @Override |
| public void removeToolListener(final ActiveToolListener listener) { |
| this.toolListeners.remove(listener); |
| } |
| |
| public TextConsoleViewer getOutputViewer() { |
| return this.outputViewer; |
| } |
| |
| public IMenuManager getOutputContextMenuManager() { |
| return this.outputMenuManager; |
| } |
| |
| public IMenuManager getInputContextMenuManager() { |
| return this.inputMenuManager; |
| } |
| |
| /** |
| * Return the text in the input line. |
| * |
| * @return |
| */ |
| public String getInput() { |
| return this.inputGroup.getDocument().get(); |
| } |
| |
| /** |
| * Clear the input line (e.g. after successful submit). |
| */ |
| public void clearInput() { |
| this.inputGroup.clear(); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public <T> T getAdapter(final Class<T> adapterType) { |
| if (this.inputGroup != null) { |
| if (adapterType == Widget.class) { |
| if (this.outputViewer.getControl().isFocusControl()) { |
| return (T) this.outputViewer.getTextWidget(); |
| } |
| return (T) this.inputGroup.getViewer().getTextWidget(); |
| } |
| if (adapterType == IFindReplaceTarget.class) { |
| if (this.inputGroup.getViewer().getControl().isFocusControl()) { |
| return (T) this.inputGroup.getViewer().getFindReplaceTarget(); |
| } |
| return (T) this.outputViewer.getFindReplaceTarget(); |
| } |
| } |
| if (adapterType == ISourceEditor.class) { |
| return (T) this.inputGroup; |
| } |
| if (adapterType == IShowInSource.class) { |
| return (T) this; |
| } |
| if (adapterType == IShowInTargetList.class) { |
| return (T) this; |
| } |
| return this.console.getAdapter(adapterType); |
| } |
| |
| @Override |
| public ShowInContext getShowInContext() { |
| final IProcess process= this.console.getProcess(); |
| if (process == null) { |
| return null; |
| } |
| final IDebugTarget target= process.getAdapter(IDebugTarget.class); |
| ISelection selection= null; |
| if (target == null) { |
| selection= new TreeSelection(new TreePath(new Object[]{ |
| DebugPlugin.getDefault().getLaunchManager(), |
| process.getLaunch(), |
| process})); |
| } else { |
| selection= new TreeSelection(new TreePath(new Object[]{ |
| DebugPlugin.getDefault().getLaunchManager(), |
| target.getLaunch(), |
| target})); |
| } |
| return new ShowInContext(null, selection); |
| } |
| |
| @Override |
| public String[] getShowInTargetIds() { |
| return new String[] { IDebugUIConstants.ID_DEBUG_VIEW }; |
| } |
| |
| |
| @Override |
| public void setActionBars(final IActionBars actionBars) { |
| // fOutputViewer.setActionBars(actionBars); |
| } |
| |
| @Override |
| public void setFocus() { |
| this.inputGroup.getViewer().getControl().setFocus(); |
| } |
| |
| |
| protected void onToolTerminated() { |
| if (this.isCreated) { |
| this.terminateAction.update(); |
| final ActiveToolEvent event= new ActiveToolEvent(ActiveToolEvent.TOOL_TERMINATED, getTool()); |
| for (final ActiveToolListener listener : this.toolListeners) { |
| listener.onToolChanged(event); |
| } |
| this.outputPasteAction.setEnabled(false); |
| final Button button= this.inputGroup.getSubmitButton(); |
| UIAccess.getDisplay(getSite().getShell()).asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| if (UIAccess.isOkToUse(button)) { |
| button.setEnabled(false); |
| } |
| } |
| }); |
| final IDialogSettings dialogSettings= DialogUtils.getDialogSettings(NicoUIPlugin.getInstance(), DIALOG_ID); |
| dialogSettings.put(SETTING_INPUTHEIGHT, this.resizer.fLastExplicit); |
| } |
| } |
| |
| @Override |
| public void setAutoScroll(final boolean enabled) { |
| this.outputViewer.setAutoScroll(enabled); |
| this.outputScrollLockAction.setChecked(!enabled); |
| } |
| |
| @Override |
| public void propertyChange(final PropertyChangeEvent event) { |
| if (UIAccess.isOkToUse(this.control) ) { |
| final Object source= event.getSource(); |
| final String property= event.getProperty(); |
| |
| if (source.equals(this.console) && property.equals(IConsoleConstants.P_FONT)) { |
| final Font font= this.console.getFont(); |
| this.outputViewer.setFont(font); |
| this.inputGroup.setFont(font); |
| this.resizer.fontChanged(); |
| this.control.layout(); |
| } |
| else if (property.equals(IConsoleConstants.P_FONT_STYLE)) { |
| this.control.redraw(); |
| this.outputViewer.getTextWidget().redraw(); |
| } |
| else if (property.equals(IConsoleConstants.P_STREAM_COLOR)) { |
| this.outputViewer.getTextWidget().redraw(); |
| } |
| // else if (source.equals(fConsole) && property.equals(IConsoleConstants.P_TAB_SIZE)) { |
| // int tabSize= ((Integer) event.getNewValue()).intValue(); |
| // fOutputViewer.setTabWidth(tabSize); |
| // fInputGroup.getSourceViewer().setTabWidth(tabSize); |
| // } |
| else if (source.equals(this.console) && property.equals(IConsoleConstants.P_CONSOLE_WIDTH)) { |
| this.outputViewer.setConsoleWidth(this.console.getConsoleWidth()); |
| } |
| } |
| } |
| |
| @Override |
| public void settingsChanged(final Set<String> groupIds) { |
| final Map<String, Object> options= new HashMap<>(); |
| UIAccess.getDisplay().syncExec(new Runnable() { |
| @Override |
| public void run() { |
| handleSettingsChanged(groupIds, options); |
| } |
| }); |
| } |
| |
| /** |
| * @see ISettingsChangedHandler#handleSettingsChanged(Set, Map) |
| */ |
| protected void handleSettingsChanged(final Set<String> groupIds, final Map<String, Object> options) { |
| if (this.inputGroup != null && UIAccess.isOkToUse(this.control)) { |
| this.inputGroup.handleSettingsChanged(groupIds, options); |
| } |
| } |
| |
| protected void collectContextMenuPreferencePages(final List<String> pageIds) { |
| pageIds.add("org.eclipse.statet.nico.preferencePages.Console"); //$NON-NLS-1$ |
| } |
| |
| } |