blob: f25b87052bad48e63e486f80e97e6f6e116239d8 [file] [log] [blame]
package org.eclipse.debug.internal.ui.views.console;
/**********************************************************************
Copyright (c) 2000, 2002 IBM Corp. All rights reserved.
This file is made available under the terms of the Common Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/cpl-v10.html
**********************************************************************/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchListener;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.actions.ClearOutputAction;
import org.eclipse.debug.internal.ui.actions.FollowHyperlinkAction;
import org.eclipse.debug.internal.ui.actions.KeyBindingFollowHyperlinkAction;
import org.eclipse.debug.internal.ui.actions.TextViewerAction;
import org.eclipse.debug.internal.ui.actions.TextViewerGotoLineAction;
import org.eclipse.debug.internal.ui.views.AbstractDebugEventHandlerView;
import org.eclipse.debug.internal.ui.views.DebugUIViewsMessages;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.console.ConsoleColorProvider;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.IFindReplaceTarget;
import org.eclipse.jface.text.ITextInputListener;
import org.eclipse.jface.text.ITextStore;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.IShowInTargetList;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.texteditor.FindReplaceAction;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.IUpdate;
public class ConsoleView extends AbstractDebugEventHandlerView implements IDocumentListener, ISelectionListener, IShowInSource, IShowInTargetList {
protected ClearOutputAction fClearOutputAction= null;
protected FollowHyperlinkAction fFollowLinkAction = null;
protected KeyBindingFollowHyperlinkAction fKeyBindingFollowLinkAction = null;
protected ProcessDropDownAction fProcessDropDownAction = null;
protected ScrollLockAction fScrollLockAction = null;
private boolean fIsLocked = false;
protected Map fGlobalActions= new HashMap(10);
protected List fSelectionActions = new ArrayList(3);
protected IDocument fCurrentDocument= null;
protected int fMode = MODE_CURRENT_PROCESS;
// view modes
/**
* Shows the output of the selected process in the debug view,
* or the current process when there is no debug view
*/
public static final int MODE_CURRENT_PROCESS = 1;
/**
* Shows the output of a specific process
*/
public static final int MODE_SPECIFIC_PROCESS = 2;
/**
* The current process being viewed, or <code>null</code.
*/
private IProcess fProcess;
/**
* Current launch listener, or <code>null</code> if none.
*/
private ILaunchListener fLaunchListener = null;
/**
* An empty document.
*/
class EmptyConsoleDocument extends ConsoleDocument {
public EmptyConsoleDocument() {
super(new ConsoleColorProvider());
}
protected ITextStore newTextStore() {
return new ConsoleOutputTextStore(0);
}
}
/**
* If showing the output for a specific process, the console view reverts to
* showing the output of the current process if that launch is removed.
*/
class LaunchListener implements ILaunchListener {
/**
* @see org.eclipse.debug.core.ILaunchListener#launchAdded(org.eclipse.debug.core.ILaunch)
*/
public void launchAdded(ILaunch launch) {
}
/**
* @see org.eclipse.debug.core.ILaunchListener#launchChanged(org.eclipse.debug.core.ILaunch)
*/
public void launchChanged(ILaunch launch) {
}
/**
* @see org.eclipse.debug.core.ILaunchListener#launchRemoved(org.eclipse.debug.core.ILaunch)
*/
public void launchRemoved(ILaunch launch) {
if (getMode() == MODE_SPECIFIC_PROCESS) {
IProcess process = getProcess();
if (process != null && launch.equals(process.getLaunch())) {
setMode(MODE_CURRENT_PROCESS);
setViewerInput(DebugUITools.getCurrentProcess());
}
}
}
}
/**
* @see AbstractDebugView#createViewer(Composite)
*/
protected Viewer createViewer(Composite parent) {
ConsoleViewer cv = new ConsoleViewer(parent);
cv.getSelectionProvider().addSelectionChangedListener(getSelectionChangedListener());
cv.addTextInputListener(getTextInputListener());
getSite().setSelectionProvider(cv.getSelectionProvider());
// listen to selection changes in the debug view
getSite().getPage().addSelectionListener(IDebugUIConstants.ID_DEBUG_VIEW, this);
setEventHandler(new ConsoleViewEventHandler(this));
return cv;
}
/**
* @see AbstractDebugView#getHelpContextId()
*/
protected String getHelpContextId() {
return IDebugHelpContextIds.CONSOLE_VIEW;
}
/**
* Sets the input to the current process if no debug view is present
* on the current active page or if the current process is <code>null</code>.
*/
public void setViewerInputFromConsoleDocumentManager(IProcess process) {
if (getMode() == MODE_CURRENT_PROCESS) {
IViewPart debugView= findView(IDebugUIConstants.ID_DEBUG_VIEW);
if (debugView == null || process == null) {
setViewerInput(process);
}
}
}
/**
* Sets the console to view the document's streams
* associated with the given process.
*/
public void setViewerInput(IProcess process) {
if (!isAvailable()) {
return;
}
if (getProcess() == process) {
// do nothing if the input is the same as what is
// being viewed. If this is the first input, set
// the console to an empty document
if (getConsoleViewer().getDocument() == null) {
getConsoleViewer().setDocument(new EmptyConsoleDocument());
getConsoleViewer().setEditable(false);
updateObjects();
}
return;
}
setProcess(process) ;
Runnable r = new Runnable() {
public void run() {
if (!isAvailable()) {
return;
}
IDocument doc = null;
if (getProcess() != null) {
doc = DebugUIPlugin.getDefault().getConsoleDocumentManager().getConsoleDocument(getProcess());
}
if (doc == null) {
doc = new EmptyConsoleDocument();
}
getConsoleViewer().setDocument(doc);
getConsoleViewer().setEditable(getProcess() != null && !getProcess().isTerminated());
updateTitle();
updateObjects();
updateSelectionDependentActions();
fKeyBindingFollowLinkAction.clearStatusLine();
}
};
asyncExec(r);
}
protected void updateTitle() {
// update view title
String title = null;
if (getProcess() == null) {
title = DebugUIViewsMessages.getString("ConsoleView.Console_1"); //$NON-NLS-1$
} else {
// use debug target title if applicable
Object obj = getProcess().getAdapter(IDebugTarget.class);
if (obj == null) {
obj = getProcess();
}
StringBuffer buff= new StringBuffer(DebugUIViewsMessages.getString("ConsoleView.Console_1")); //$NON-NLS-1$
buff.append(" ["); //$NON-NLS-1$
buff.append(DebugUIPlugin.getModelPresentation().getText(obj));
buff.append(']');
title= buff.toString();
}
setTitle(title);
}
/**
* @see AbstractDebugView#createActions()
*/
protected void createActions() {
fClearOutputAction= new ClearOutputAction(getConsoleViewer());
// In order for the clipboard actions to accessible via their shortcuts
// (e.g., Ctrl-C, Ctrl-V), we *must* set a global action handler for
// each action
IActionBars actionBars= getViewSite().getActionBars();
TextViewerAction action= new TextViewerAction(getTextViewer(), TextViewer.CUT);
action.configureAction(DebugUIViewsMessages.getString("ConsoleView.Cu&t@Ctrl+X_3"), DebugUIViewsMessages.getString("ConsoleView.Cut_4"), DebugUIViewsMessages.getString("ConsoleView.Cut_4")); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
setGlobalAction(actionBars, ITextEditorActionConstants.CUT, action);
action= new TextViewerAction(getTextViewer(), TextViewer.COPY);
action.configureAction(DebugUIViewsMessages.getString("ConsoleView.&Copy@Ctrl+C_6"), DebugUIViewsMessages.getString("ConsoleView.Copy_7"), DebugUIViewsMessages.getString("ConsoleView.Copy_7")); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
setGlobalAction(actionBars, ITextEditorActionConstants.COPY, action);
action= new TextViewerAction(getTextViewer(), TextViewer.PASTE);
action.configureAction(DebugUIViewsMessages.getString("ConsoleView.&Paste@Ctrl+V_9"), DebugUIViewsMessages.getString("ConsoleView.Paste_10"), DebugUIViewsMessages.getString("ConsoleView.Paste_Clipboard_Text_11")); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
setGlobalAction(actionBars, ITextEditorActionConstants.PASTE, action);
action= new TextViewerAction(getTextViewer(), TextViewer.SELECT_ALL);
action.configureAction(DebugUIViewsMessages.getString("ConsoleView.Select_&All@Ctrl+A_12"), DebugUIViewsMessages.getString("ConsoleView.Select_All"), DebugUIViewsMessages.getString("ConsoleView.Select_All")); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
setGlobalAction(actionBars, ITextEditorActionConstants.SELECT_ALL, action);
//XXX Still using "old" resource access
ResourceBundle bundle= ResourceBundle.getBundle("org.eclipse.debug.internal.ui.views.DebugUIViewsMessages"); //$NON-NLS-1$
setGlobalAction(actionBars, ITextEditorActionConstants.FIND, new FindReplaceAction(bundle, "find_replace_action.", this)); //$NON-NLS-1$
action= new TextViewerGotoLineAction(getConsoleViewer());
setGlobalAction(actionBars, ITextEditorActionConstants.GOTO_LINE, action);
fFollowLinkAction = new FollowHyperlinkAction(getConsoleViewer());
fKeyBindingFollowLinkAction= new KeyBindingFollowHyperlinkAction(this);
fKeyBindingFollowLinkAction.setActionDefinitionId("org.eclipse.jdt.ui.edit.text.java.open.editor"); //$NON-NLS-1$
getSite().getKeyBindingService().registerAction(fKeyBindingFollowLinkAction);
fProcessDropDownAction = new ProcessDropDownAction(this);
fScrollLockAction = new ScrollLockAction(getConsoleViewer());
fScrollLockAction.setChecked(fIsLocked);
getConsoleViewer().setAutoScroll(!fIsLocked);
actionBars.updateActionBars();
getConsoleViewer().getTextWidget().addVerifyKeyListener(new VerifyKeyListener() {
public void verifyKey(VerifyEvent event) {
if (event.stateMask == SWT.CTRL && event.keyCode == 0 && event.character == 0x0C) {
IAction gotoLine= (IAction)fGlobalActions.get(ITextEditorActionConstants.GOTO_LINE);
if (gotoLine.isEnabled()) {
gotoLine.run();
event.doit= false;
}
}
}
});
fSelectionActions.add(ITextEditorActionConstants.CUT);
fSelectionActions.add(ITextEditorActionConstants.COPY);
fSelectionActions.add(ITextEditorActionConstants.PASTE);
// initialize input, after viewer has been created
setViewerInput(DebugUITools.getCurrentProcess());
}
protected void setGlobalAction(IActionBars actionBars, String actionID, IAction action) {
fGlobalActions.put(actionID, action);
actionBars.setGlobalActionHandler(actionID, action);
}
/**
* @see AbstractDebugView#configureToolBar(IToolBarManager)
*/
protected void configureToolBar(IToolBarManager mgr) {
mgr.add(new Separator(IDebugUIConstants.LAUNCH_GROUP));
mgr.add(new Separator(IDebugUIConstants.OUTPUT_GROUP));
mgr.add(fProcessDropDownAction);
mgr.add(fScrollLockAction);
mgr.add(fClearOutputAction);
}
/**
* Adds the text manipulation actions to the <code>ConsoleViewer</code>
*/
protected void fillContextMenu(IMenuManager menu) {
ConsoleDocument doc= (ConsoleDocument)getConsoleViewer().getDocument();
if (doc == null) {
return;
}
if (doc.isReadOnly()) {
menu.add((IAction)fGlobalActions.get(ITextEditorActionConstants.COPY));
menu.add((IAction)fGlobalActions.get(ITextEditorActionConstants.SELECT_ALL));
} else {
updateAction(ITextEditorActionConstants.PASTE);
menu.add((IAction)fGlobalActions.get(ITextEditorActionConstants.CUT));
menu.add((IAction)fGlobalActions.get(ITextEditorActionConstants.COPY));
menu.add((IAction)fGlobalActions.get(ITextEditorActionConstants.PASTE));
menu.add((IAction)fGlobalActions.get(ITextEditorActionConstants.SELECT_ALL));
}
menu.add(new Separator("FIND")); //$NON-NLS-1$
menu.add((IAction)fGlobalActions.get(ITextEditorActionConstants.FIND));
menu.add((IAction)fGlobalActions.get(ITextEditorActionConstants.GOTO_LINE));
fFollowLinkAction.setEnabled(fFollowLinkAction.getHyperLink() != null);
menu.add(fFollowLinkAction);
menu.add(fClearOutputAction);
menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
/**
* @see WorkbenchPart#getAdapter(Class)
*/
public Object getAdapter(Class required) {
if (!isAvailable()) {
return null;
}
if (IFindReplaceTarget.class.equals(required)) {
return getConsoleViewer().getFindReplaceTarget();
}
if (Widget.class.equals(required)) {
return getConsoleViewer().getTextWidget();
}
if (IShowInSource.class.equals(required)) {
return this;
}
if (IShowInTargetList.class.equals(required)) {
return this;
}
return super.getAdapter(required);
}
protected final ISelectionChangedListener getSelectionChangedListener() {
return new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
updateSelectionDependentActions();
}
};
}
protected final ITextInputListener getTextInputListener() {
return new ITextInputListener() {
public void inputDocumentAboutToBeChanged(IDocument old, IDocument nw) {
if (old != null) {
old.removeDocumentListener(ConsoleView.this);
}
fCurrentDocument = nw;
if (nw != null) {
nw.addDocumentListener(ConsoleView.this);
}
}
public void inputDocumentChanged(IDocument doc, IDocument doc2) {
updateAction(ITextEditorActionConstants.FIND);
}
};
}
protected void updateSelectionDependentActions() {
Iterator iterator= fSelectionActions.iterator();
while (iterator.hasNext()) {
updateAction((String)iterator.next());
}
}
protected void updateAction(String actionId) {
if (!isAvailable()) {
return;
}
IAction action= (IAction)fGlobalActions.get(actionId);
if (action instanceof IUpdate) {
((IUpdate) action).update();
}
}
public void dispose() {
getSite().getPage().removeSelectionListener(IDebugUIConstants.ID_DEBUG_VIEW, this);
if (getConsoleViewer() != null) {
getConsoleViewer().dispose();
}
if (fCurrentDocument != null) {
fCurrentDocument.removeDocumentListener(this);
}
if (fFollowLinkAction != null) {
fFollowLinkAction.dispose();
}
if (fKeyBindingFollowLinkAction != null) {
fKeyBindingFollowLinkAction.dispose();
getSite().getKeyBindingService().unregisterAction(fKeyBindingFollowLinkAction);
}
if (fLaunchListener != null) {
DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(fLaunchListener);
fLaunchListener = null;
}
if (fProcessDropDownAction != null) {
fProcessDropDownAction.dispose();
fProcessDropDownAction = null;
}
super.dispose();
}
/**
* @see IDocumentListener#documentAboutToBeChanged(DocumentEvent)
*/
public void documentAboutToBeChanged(DocumentEvent e) {
}
/**
* @see IDocumentListener#documentChanged(DocumentEvent)
*/
public void documentChanged(DocumentEvent e) {
updateAction(ITextEditorActionConstants.FIND);
}
public ConsoleViewer getConsoleViewer() {
return (ConsoleViewer)getViewer();
}
/**
* Sets the process being viewed
*
* @param process process or <code>null</code>
*/
private void setProcess(IProcess process) {
fProcess = process;
}
/**
* Returns the process being viewed, or <code>null</code>
*
* @return process
*/
public IProcess getProcess() {
return fProcess;
}
/**
* @see ISelectionListener#selectionChanged(IWorkbenchPart, ISelection)
*/
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (getMode() == MODE_CURRENT_PROCESS) {
setViewerInput(DebugUITools.getCurrentProcess());
}
}
/**
* @see org.eclipse.debug.ui.AbstractDebugView#becomesHidden()
*/
protected void becomesHidden() {
super.becomesHidden();
getConsoleViewer().setVisible(false);
}
/**
* @see org.eclipse.debug.ui.AbstractDebugView#becomesVisible()
*/
protected void becomesVisible() {
super.becomesVisible();
getConsoleViewer().setVisible(true);
}
/**
* Returns this view's mode.
*/
protected int getMode() {
return fMode;
}
/**
* Sets this view's mode
*/
protected void setMode(int mode) {
if (getMode() != mode) {
fMode = mode;
if (mode == MODE_SPECIFIC_PROCESS) {
fLaunchListener = new LaunchListener();
DebugPlugin.getDefault().getLaunchManager().addLaunchListener(fLaunchListener);
} else {
if (fLaunchListener != null) {
DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(fLaunchListener);
fLaunchListener = null;
}
}
}
}
/**
* Save scroll lock.
*
* @see org.eclipse.ui.IViewPart#saveState(org.eclipse.ui.IMemento)
*/
public void saveState(IMemento memento) {
super.saveState(memento);
if (fScrollLockAction != null) {
memento.putString(getViewSite().getId() + ".scrollLock", new Boolean(fScrollLockAction.isChecked()).toString()); //$NON-NLS-1$
}
}
/**
* Restore scroll lock.
*
* @see org.eclipse.ui.IViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento)
*/
public void init(IViewSite site, IMemento memento) throws PartInitException {
super.init(site, memento);
if (memento != null) {
String lock = memento.getString(site.getId() + ".scrollLock"); //$NON-NLS-1$
if (lock != null) {
fIsLocked = new Boolean(lock).booleanValue();
}
}
}
/**
* @see IShowInSource#getShowInContext()
*/
public ShowInContext getShowInContext() {
IProcess process = getProcess();
if (process == null) {
return null;
} else {
IDebugTarget target = (IDebugTarget)process.getAdapter(IDebugTarget.class);
ISelection selection = null;
if (target == null) {
selection = new StructuredSelection(process);
} else {
selection = new StructuredSelection(target);
}
return new ShowInContext(null, selection);
}
}
/**
* @see IShowInTargetList#getShowInTargetIds()
*/
public String[] getShowInTargetIds() {
return new String[] {IDebugUIConstants.ID_DEBUG_VIEW};
}
}