blob: 2377f73960e73096781b8697ed9eb556094ff569 [file] [log] [blame]
package org.eclipse.debug.internal.ui.views.variables;
/**********************************************************************
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.ResourceBundle;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.core.model.IValue;
import org.eclipse.debug.core.model.IVariable;
import org.eclipse.debug.internal.ui.DebugPluginImages;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.DelegatingModelPresentation;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.debug.internal.ui.LazyModelPresentation;
import org.eclipse.debug.internal.ui.VariablesViewModelPresentation;
import org.eclipse.debug.internal.ui.actions.ChangeVariableValueAction;
import org.eclipse.debug.internal.ui.actions.ShowDetailPaneAction;
import org.eclipse.debug.internal.ui.actions.ShowTypesAction;
import org.eclipse.debug.internal.ui.actions.TextViewerAction;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
import org.eclipse.debug.internal.ui.views.AbstractDebugEventHandler;
import org.eclipse.debug.internal.ui.views.AbstractDebugEventHandlerView;
import org.eclipse.debug.internal.ui.views.DebugUIViewsMessages;
import org.eclipse.debug.internal.ui.views.IDebugExceptionHandler;
import org.eclipse.debug.internal.ui.views.ViewerState;
import org.eclipse.debug.ui.IDebugModelPresentation;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.IValueDetailListener;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
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.preference.IPreferenceStore;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
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.ITextOperationTarget;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.ListenerList;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.INullSelectionListener;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.texteditor.FindReplaceAction;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.IUpdate;
/**
* This view shows variables and their values for a particular stack frame
*/
public class VariablesView extends AbstractDebugEventHandlerView implements ISelectionListener,
IPropertyChangeListener,
IValueDetailListener,
IDebugExceptionHandler,
INullSelectionListener {
/**
* A label provider that delegates to a debug model
* presentation and adds coloring to variables to
* reflect their changed state
*/
class VariablesViewLabelProvider implements ILabelProvider, IColorProvider {
private IDebugModelPresentation presentation;
public VariablesViewLabelProvider(IDebugModelPresentation presentation) {
this.presentation= presentation;
}
public IDebugModelPresentation getPresentation() {
return presentation;
}
public Image getImage(Object element) {
return presentation.getImage(element);
}
public String getText(Object element) {
return presentation.getText(element);
}
public void addListener(ILabelProviderListener listener) {
presentation.addListener(listener);
}
public void dispose() {
presentation.dispose();
}
public boolean isLabelProperty(Object element, String property) {
return presentation.isLabelProperty(element, property);
}
public void removeListener(ILabelProviderListener listener) {
presentation.removeListener(listener);
}
public Color getForeground(Object element) {
if (element instanceof IVariable) {
IVariable variable = (IVariable) element;
try {
if (variable.hasValueChanged()) {
return DebugUIPlugin.getPreferenceColor(IDebugPreferenceConstants.CHANGED_VARIABLE_RGB);
}
} catch (DebugException e) {
DebugUIPlugin.log(e);
}
}
return null;
}
public Color getBackground(Object element) {
return null;
}
}
/**
* The selection provider for the variables view changes depending on whether
* the variables viewer or detail pane source viewer have focus. This "super"
* provider ensures the correct selection is sent to all listeners.
*/
class VariablesViewSelectionProvider implements ISelectionProvider {
private ListenerList fListeners= new ListenerList();
private ISelectionProvider fUnderlyingSelectionProvider;
/**
* @see ISelectionProvider#addSelectionChangedListener(ISelectionChangedListener)
*/
public void addSelectionChangedListener(ISelectionChangedListener listener) {
fListeners.add(listener);
}
/**
* @see ISelectionProvider#getSelection()
*/
public ISelection getSelection() {
return getUnderlyingSelectionProvider().getSelection();
}
/**
* @see ISelectionProvider#removeSelectionChangedListener(ISelectionChangedListener)
*/
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
fListeners.remove(listener);
}
/**
* @see ISelectionProvider#setSelection(ISelection)
*/
public void setSelection(ISelection selection) {
getUnderlyingSelectionProvider().setSelection(selection);
}
protected ISelectionProvider getUnderlyingSelectionProvider() {
return fUnderlyingSelectionProvider;
}
protected void setUnderlyingSelectionProvider(ISelectionProvider underlyingSelectionProvider) {
fUnderlyingSelectionProvider = underlyingSelectionProvider;
}
protected void fireSelectionChanged(SelectionChangedEvent event) {
Object[] listeners= fListeners.getListeners();
for (int i = 0; i < listeners.length; i++) {
ISelectionChangedListener listener = (ISelectionChangedListener)listeners[i];
listener.selectionChanged(event);
}
}
}
/**
* The model presentation used as the label provider for the tree viewer,
* and also as the detail information provider for the detail pane.
*/
private VariablesViewModelPresentation fModelPresentation;
/**
* The UI construct that provides a sliding sash between the variables tree
* and the detail pane.
*/
private SashForm fSashForm;
/**
* The detail pane viewer and its associated document.
*/
private ISourceViewer fDetailViewer;
private IDocument fDetailDocument;
/**
* The identifier of the debug model that is/was being displayed
* in this view. When the type of model being displayed changes,
* the details area needs to be reconfigured.
*/
private String fDebugModelIdentifier;
/**
* The configuration being used in the details area
*/
private SourceViewerConfiguration fSourceViewerConfiguration;
/**
* Selection currently computing details for
* (workaround for bug 12938)
*/
private IStructuredSelection fValueSelection = null;
/**
* The last value for which the detail has been requested. */
private IValue fLastValueDetail= null;
/**
* Iterator for multi-selection details computation
*/
private Iterator fSelectionIterator = null;
/**
* Various listeners used to update the enabled state of actions and also to
* populate the detail pane.
*/
private ISelectionChangedListener fTreeSelectionChangedListener;
private ISelectionChangedListener fDetailSelectionChangedListener;
private IDocumentListener fDetailDocumentListener;
/**
* Selection provider for this view.
*/
private VariablesViewSelectionProvider fSelectionProvider= new VariablesViewSelectionProvider();
/**
* Collections for tracking actions.
*/
private List fSelectionActions = new ArrayList(3);
/**
* A map of stack frames to <code>ViewerState</code>s.
* Used to restore the expanded state of the variables view on
* re-selection of the same stack frame. The cache is cleared on
* a frame by frame basis when a thread/target is terminated.
*/
private HashMap fExpandedVariables = new HashMap(10);
/**
* Remembers which viewer (tree viewer or details viewer) had focus, so we
* can reset the focus properly when re-activated.
*/
private Viewer fFocusViewer = null;
/**
* These are used to initialize and persist the position of the sash that
* separates the tree viewer from the detail pane.
*/
private static final int[] DEFAULT_SASH_WEIGHTS = {6, 2};
private int[] fLastSashWeights;
private boolean fToggledDetailOnce;
protected static final String DETAIL_SELECT_ALL_ACTION = SELECT_ALL_ACTION + ".Detail"; //$NON-NLS-1$
protected static final String VARIABLES_SELECT_ALL_ACTION= SELECT_ALL_ACTION + ".Variables"; //$NON-NLS-1$
protected static final String DETAIL_COPY_ACTION = ITextEditorActionConstants.COPY + ".Detail"; //$NON-NLS-1$
protected static final String VARIABLES_COPY_ACTION= ITextEditorActionConstants.COPY + ".Variables"; //$NON-NLS-1$
/**
* Remove myself as a selection listener
* and preference change listener.
*
* @see IWorkbenchPart#dispose()
*/
public void dispose() {
getSite().getPage().removeSelectionListener(IDebugUIConstants.ID_DEBUG_VIEW, this);
DebugUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
JFaceResources.getFontRegistry().removeListener(this);
Viewer viewer = getViewer();
if (viewer != null) {
getDetailDocument().removeDocumentListener(getDetailDocumentListener());
}
super.dispose();
}
protected void setViewerInput(IStructuredSelection ssel) {
IStackFrame frame= null;
if (ssel.size() == 1) {
Object input= ssel.getFirstElement();
if (input instanceof IStackFrame) {
frame= (IStackFrame)input;
}
}
getDetailViewer().setEditable(frame != null);
Object current= getViewer().getInput();
if (current == null && frame == null) {
return;
}
if (current != null && current.equals(frame)) {
return;
}
if (current != null) {
// save state
ViewerState state = new ViewerState(getVariablesViewer());
fExpandedVariables.put(current, state);
}
if (frame != null) {
setDebugModel(frame.getModelIdentifier());
}
showViewer();
getViewer().setInput(frame);
// restore state
if (frame != null) {
ViewerState state = (ViewerState)fExpandedVariables.get(frame);
if (state != null) {
state.restoreState(getVariablesViewer());
}
}
}
/**
* Returns the variables viewer for this view
*/
protected VariablesViewer getVariablesViewer() {
return (VariablesViewer)getViewer();
}
/**
* Clears expanded state for stack frames which are
* a child of the given thread or debug target.
*/
protected void clearExpandedVariables(Object parent) {
List list = null;
if (parent instanceof IThread) {
list = getCachedFrames((IThread)parent);
} else if (parent instanceof IDebugTarget) {
list = getCachedFrames((IDebugTarget)parent);
}
if (list != null) {
Iterator frames = list.iterator();
while (frames.hasNext()) {
Object frame = frames.next();
fExpandedVariables.remove(frame);
}
}
}
/**
* Returns a list of stack frames in the specified
* thread that have cached an expansion state.
*
* @return a list of stack frames in the specified
* thread that have cached an expansion state
*/
protected List getCachedFrames(IThread thread) {
List list = null;
Iterator frames = fExpandedVariables.keySet().iterator();
while (frames.hasNext()) {
IStackFrame frame = (IStackFrame)frames.next();
if (frame.getThread().equals(thread)) {
if (list == null) {
list = new ArrayList();
}
list.add(frame);
}
}
return list;
}
/**
* Returns a list of stack frames in the specified
* thread that have cached an expansion state.
*
* @return a list of stack frames in the specified
* thread that have cached an expansion state
*/
protected List getCachedFrames(IDebugTarget target) {
List list = null;
Iterator frames = fExpandedVariables.keySet().iterator();
while (frames.hasNext()) {
IStackFrame frame = (IStackFrame)frames.next();
if (frame.getDebugTarget().equals(target)) {
if (list == null) {
list = new ArrayList();
}
list.add(frame);
}
}
return list;
}
/**
* Configures the details viewer for the debug model
* currently being displayed
*/
protected void configureDetailsViewer() {
LazyModelPresentation mp = (LazyModelPresentation)fModelPresentation.getPresentation(getDebugModel());
SourceViewerConfiguration svc = null;
if (mp != null) {
try {
svc = mp.newDetailsViewerConfiguration();
} catch (CoreException e) {
DebugUIPlugin.errorDialog(getSite().getShell(), DebugUIViewsMessages.getString("VariablesView.Error_1"), DebugUIViewsMessages.getString("VariablesView.Unable_to_configure_variable_details_area._2"), e); //$NON-NLS-1$ //$NON-NLS-2$
}
}
if (svc == null) {
svc = new SourceViewerConfiguration();
getDetailViewer().setEditable(false);
}
getDetailViewer().configure(svc);
//update actions that depend on the configuration of the details viewer
updateAction("ContentAssist"); //$NON-NLS-1$
setDetailViewerConfiguration(svc);
}
/**
* @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
String propertyName= event.getProperty();
if (propertyName.equals(IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_ORIENTATION)) {
setDetailPaneOrientation(DebugUIPlugin.getDefault().getPreferenceStore().getString(IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_ORIENTATION));
} else if (propertyName.equals(IDebugPreferenceConstants.CHANGED_VARIABLE_RGB)) {
getEventHandler().refresh();
} else if (propertyName.equals(IDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP)) {
toggleDetailPaneWordWrap(DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP));
} else if (propertyName.equals(IInternalDebugUIConstants.DETAIL_PANE_FONT)) {
getDetailViewer().getTextWidget().setFont(JFaceResources.getFont(IInternalDebugUIConstants.DETAIL_PANE_FONT));
}
}
/**
* @see AbstractDebugView#createViewer(Composite)
*/
public Viewer createViewer(Composite parent) {
fModelPresentation = new VariablesViewModelPresentation();
DebugUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
JFaceResources.getFontRegistry().addListener(this);
// create the sash form that will contain the tree viewer & text viewer
fSashForm = new SashForm(parent, SWT.NONE);
IPreferenceStore prefStore = DebugUIPlugin.getDefault().getPreferenceStore();
String orientString = prefStore.getString(IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_ORIENTATION);
setDetailPaneOrientation(orientString);
// add tree viewer
final TreeViewer variablesViewer = new VariablesViewer(getSashForm(), SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
variablesViewer.setContentProvider(createContentProvider());
variablesViewer.setLabelProvider(new VariablesViewLabelProvider(getModelPresentation()));
variablesViewer.setUseHashlookup(true);
variablesViewer.getControl().addFocusListener(new FocusAdapter() {
/**
* @see FocusListener#focusGained(FocusEvent)
*/
public void focusGained(FocusEvent e) {
getVariablesViewSelectionProvider().setUnderlyingSelectionProvider(variablesViewer);
setAction(SELECT_ALL_ACTION, getAction(VARIABLES_SELECT_ALL_ACTION));
setAction(COPY_ACTION, getAction(VARIABLES_COPY_ACTION));
getViewSite().getActionBars().updateActionBars();
setFocusViewer(getVariablesViewer());
}
});
variablesViewer.addSelectionChangedListener(getTreeSelectionChangedListener());
getVariablesViewSelectionProvider().setUnderlyingSelectionProvider(variablesViewer);
getSite().setSelectionProvider(getVariablesViewSelectionProvider());
// add text viewer
SourceViewer detailsViewer= new SourceViewer(getSashForm(), null, SWT.V_SCROLL | SWT.H_SCROLL);
setDetailViewer(detailsViewer);
detailsViewer.setDocument(getDetailDocument());
detailsViewer.getTextWidget().setFont(JFaceResources.getFont(IInternalDebugUIConstants.DETAIL_PANE_FONT));
getDetailDocument().addDocumentListener(getDetailDocumentListener());
detailsViewer.setEditable(false);
getSashForm().setMaximizedControl(variablesViewer.getControl());
toggleDetailPaneWordWrap(DebugUIPlugin.getDefault().getPluginPreferences().getBoolean(IDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP));
detailsViewer.getSelectionProvider().addSelectionChangedListener(getDetailSelectionChangedListener());
detailsViewer.getControl().addFocusListener(new FocusAdapter() {
/**
* @see FocusListener#focusGained(FocusEvent)
*/
public void focusGained(FocusEvent e) {
getVariablesViewSelectionProvider().setUnderlyingSelectionProvider(getDetailViewer().getSelectionProvider());
setAction(SELECT_ALL_ACTION, getAction(DETAIL_SELECT_ALL_ACTION));
setAction(COPY_ACTION, getAction(DETAIL_COPY_ACTION));
getViewSite().getActionBars().updateActionBars();
setFocusViewer((Viewer)getDetailViewer());
}
});
// add a context menu to the detail area
createDetailContextMenu(detailsViewer.getTextWidget());
// listen to selection in debug view
getSite().getPage().addSelectionListener(IDebugUIConstants.ID_DEBUG_VIEW, this);
setEventHandler(createEventHandler(variablesViewer));
return variablesViewer;
}
/**
* Creates this view's content provider.
*
* @return a content provider
*/
protected IContentProvider createContentProvider() {
VariablesViewContentProvider cp = new VariablesViewContentProvider();
cp.setExceptionHandler(this);
return cp;
}
/**
* Creates this view's event handler.
*
* @param viewer the viewer associated with this view
* @return an event handler
*/
protected AbstractDebugEventHandler createEventHandler(Viewer viewer) {
return new VariablesViewEventHandler(this);
}
/**
* @see AbstractDebugView#getHelpContextId()
*/
protected String getHelpContextId() {
return IDebugHelpContextIds.VARIABLE_VIEW;
}
/**
* Set the orientation of the sash form to display its controls according to the value
* of <code>value</code>. 'VARIABLES_DETAIL_PANE_UNDERNEATH' means that the detail
* pane appears underneath the tree viewer, 'VARIABLES_DETAIL_PANE_RIGHT' means the
* detail pane appears to the right of the tree viewer.
*/
protected void setDetailPaneOrientation(String value) {
int orientation = value.equals(IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_UNDERNEATH) ? SWT.VERTICAL : SWT.HORIZONTAL;
getSashForm().setOrientation(orientation);
}
/**
* Show or hide the detail pane, based on the value of <code>on</code>.
* If showing, reset the sash form to use the relative weights that were
* in effect the last time the detail pane was visible, and populate it with
* details for the current selection. If hiding, save the current relative
* weights, unless the detail pane hasn't yet been shown.
*/
public void toggleDetailPane(boolean on) {
if (on) {
getSashForm().setMaximizedControl(null);
getSashForm().setWeights(getLastSashWeights());
populateDetailPane();
fToggledDetailOnce = true;
} else {
if (fToggledDetailOnce) {
setLastSashWeights(getSashForm().getWeights());
}
getSashForm().setMaximizedControl(getViewer().getControl());
}
}
/**
* Set on or off the word wrap flag for the detail pane.
*/
public void toggleDetailPaneWordWrap(boolean on) {
fDetailViewer.getTextWidget().setWordWrap(on);
}
/**
* Ask the variables tree for its current selection, and use this to populate
* the detail pane.
*/
public void populateDetailPane() {
if (isDetailPaneVisible()) {
IStructuredSelection selection = (IStructuredSelection) getViewer().getSelection();
populateDetailPaneFromSelection(selection);
}
}
/**
* Return the relative weights that were in effect the last time both panes were
* visible in the sash form, or the default weights if both panes have not yet been
* made visible.
*/
protected int[] getLastSashWeights() {
if (fLastSashWeights == null) {
fLastSashWeights = DEFAULT_SASH_WEIGHTS;
}
return fLastSashWeights;
}
/**
* Set the current relative weights of the controls in the sash form, so that
* the sash form can be reset to this layout at a later time.
*/
protected void setLastSashWeights(int[] weights) {
fLastSashWeights = weights;
}
/**
* Initializes the viewer input on creation
*/
protected void setInitialContent() {
ISelection selection= getSite().getPage().getSelection(IDebugUIConstants.ID_DEBUG_VIEW);
if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
setViewerInput((IStructuredSelection) selection);
}
}
/**
* Create the context menu particular to the detail pane. Note that anyone
* wishing to contribute an action to this menu must use
* <code>IDebugUIConstants.VARIABLE_VIEW_DETAIL_ID</code> as the
* <code>targetID</code> in the extension XML.
*/
protected void createDetailContextMenu(Control menuControl) {
MenuManager menuMgr= new MenuManager(); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager mgr) {
fillDetailContextMenu(mgr);
}
});
Menu menu= menuMgr.createContextMenu(menuControl);
menuControl.setMenu(menu);
// register the context menu such that other plugins may contribute to it
getSite().registerContextMenu(IDebugUIConstants.VARIABLE_VIEW_DETAIL_ID, menuMgr, getDetailViewer().getSelectionProvider());
addContextMenuManager(menuMgr);
}
/**
* @see AbstractDebugView#createActions()
*/
protected void createActions() {
IAction action = new ShowTypesAction(getStructuredViewer());
action.setChecked(DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IDebugUIConstants.PREF_SHOW_TYPE_NAMES));
setAction("ShowTypeNames",action); //$NON-NLS-1$
action = new ChangeVariableValueAction(getViewer());
action.setEnabled(false);
setAction("ChangeVariableValue", action); //$NON-NLS-1$
setAction(DOUBLE_CLICK_ACTION, action);
action = new ShowDetailPaneAction(this);
action.setChecked(DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IDebugUIConstants.PREF_SHOW_DETAIL_PANE));
setAction("ShowDetailPane", action); //$NON-NLS-1$
//detail specific actions
TextViewerAction textAction= new TextViewerAction(getDetailViewer(), ISourceViewer.CONTENTASSIST_PROPOSALS);
textAction.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
textAction.configureAction(DebugUIViewsMessages.getString("VariablesView.Co&ntent_Assist_3"), "",""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
textAction.setImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_ELCL_CONTENT_ASSIST));
textAction.setHoverImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_LCL_CONTENT_ASSIST));
textAction.setDisabledImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_DLCL_CONTENT_ASSIST));
setAction("ContentAssist", textAction); //$NON-NLS-1$
getSite().getKeyBindingService().registerAction(textAction);
textAction= new TextViewerAction(getDetailViewer(), ITextOperationTarget.SELECT_ALL);
textAction.configureAction(DebugUIViewsMessages.getString("VariablesView.Select_&All_5"), "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
setAction(DETAIL_SELECT_ALL_ACTION, textAction);
textAction= new TextViewerAction(getDetailViewer(), ITextOperationTarget.COPY);
textAction.configureAction(DebugUIViewsMessages.getString("VariablesView.&Copy_8"), "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
setAction(DETAIL_COPY_ACTION, textAction);
textAction= new TextViewerAction(getDetailViewer(), ITextOperationTarget.CUT);
textAction.configureAction(DebugUIViewsMessages.getString("VariablesView.Cu&t_11"), "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
setAction(ITextEditorActionConstants.CUT, textAction);
textAction= new TextViewerAction(getDetailViewer(), ITextOperationTarget.PASTE);
textAction.configureAction(DebugUIViewsMessages.getString("VariablesView.&Paste_14"), "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
setAction(ITextEditorActionConstants.PASTE, textAction);
//XXX Still using "old" resource access
ResourceBundle bundle= ResourceBundle.getBundle("org.eclipse.debug.internal.ui.views.DebugUIViewsMessages"); //$NON-NLS-1$
setAction(ITextEditorActionConstants.FIND, new FindReplaceAction(bundle, "find_replace_action.", this)); //$NON-NLS-1$
fSelectionActions.add(ITextEditorActionConstants.COPY);
fSelectionActions.add(ITextEditorActionConstants.CUT);
fSelectionActions.add(ITextEditorActionConstants.PASTE);
updateAction(ITextEditorActionConstants.FIND);
// set initial content here, as viewer has to be set
setInitialContent();
}
/**
* Configures the toolBar.
*
* @param tbm The toolbar that will be configured
*/
protected void configureToolBar(IToolBarManager tbm) {
tbm.add(new Separator(this.getClass().getName()));
tbm.add(new Separator(IDebugUIConstants.RENDER_GROUP));
tbm.add(getAction("ShowTypeNames")); //$NON-NLS-1$
tbm.add(new Separator("TOGGLE_VIEW")); //$NON-NLS-1$
tbm.add(getAction("ShowDetailPane")); //$NON-NLS-1$
}
/**
* Adds items to the tree viewer's context menu including any extension defined
* actions.
*
* @param menu The menu to add the item to.
*/
protected void fillContextMenu(IMenuManager menu) {
menu.add(new Separator(IDebugUIConstants.EMPTY_VARIABLE_GROUP));
menu.add(new Separator(IDebugUIConstants.VARIABLE_GROUP));
menu.add(getAction("ChangeVariableValue")); //$NON-NLS-1$
menu.add(new Separator(IDebugUIConstants.EMPTY_RENDER_GROUP));
menu.add(new Separator(IDebugUIConstants.EMPTY_NAVIGATION_GROUP));
menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
/**
* Adds items to the detail area's context menu including any extension defined
* actions.
*
* @param menu The menu to add the item to.
*/
protected void fillDetailContextMenu(IMenuManager menu) {
menu.add(new Separator(IDebugUIConstants.VARIABLE_GROUP));
menu.add(getAction("ContentAssist")); //$NON-NLS-1$
menu.add(new Separator());
menu.add(getAction(ITextEditorActionConstants.CUT));
menu.add(getAction(ITextEditorActionConstants.COPY + ".Detail")); //$NON-NLS-1$
menu.add(getAction(ITextEditorActionConstants.PASTE));
menu.add(getAction(DETAIL_SELECT_ALL_ACTION));
menu.add(new Separator("FIND")); //$NON-NLS-1$
menu.add(getAction(ITextEditorActionConstants.FIND));
menu.add(new Separator("TOGGLE_VIEW")); //$NON-NLS-1$
menu.add(getAction("ShowDetailPane")); //$NON-NLS-1$
menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
/**
* Lazily instantiate and return a selection listener that populates the detail pane,
* but only if the detail is currently visible.
*/
protected ISelectionChangedListener getTreeSelectionChangedListener() {
if (fTreeSelectionChangedListener == null) {
fTreeSelectionChangedListener = new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
if (event.getSelectionProvider().equals(getVariablesViewer())) {
getVariablesViewSelectionProvider().fireSelectionChanged(event);
// if the detail pane is not visible, don't waste time retrieving details
if (getSashForm().getMaximizedControl() == getViewer().getControl()) {
return;
}
IStructuredSelection selection = (IStructuredSelection)event.getSelection();
populateDetailPaneFromSelection(selection);
}
}
};
}
return fTreeSelectionChangedListener;
}
/**
* Show the details associated with the first of the selected variables in the
* detail pane.
*/
protected void populateDetailPaneFromSelection(IStructuredSelection selection) {
try {
getDetailDocument().set(""); //$NON-NLS-1$
if (!selection.isEmpty()) {
IValue val = null;
Object obj = selection.getFirstElement();
if (obj instanceof IVariable) {
val = ((IVariable)obj).getValue();
} else if (obj instanceof IExpression) {
val = ((IExpression)obj).getValue();
if (val == null) {
return;
}
}
// workaroud for bug 12938
if (fValueSelection != null && fValueSelection.equals(selection)) {
return;
}
setDebugModel(val.getModelIdentifier());
fValueSelection = selection;
fSelectionIterator = selection.iterator();
fSelectionIterator.next();
fLastValueDetail= val;
getModelPresentation().computeDetail(val, this);
}
} catch (DebugException de) {
DebugUIPlugin.log(de);
getDetailDocument().set(DebugUIViewsMessages.getString("VariablesView.<error_occurred_retrieving_value>_18")); //$NON-NLS-1$
}
}
/**
* @see IValueDetailListener#detailComputed(IValue, String)
*/
public void detailComputed(final IValue value, final String result) {
Runnable runnable = new Runnable() {
public void run() {
if (isAvailable()) {
// bug 24862
// don't display the result if an other detail has been
// requested
if (value == fLastValueDetail) {
String insert = result;
int length = getDetailDocument().get().length();
if (length > 0) {
insert = "\n" + result; //$NON-NLS-1$
}
try {
getDetailDocument().replace(length, 0,insert);
} catch (BadLocationException e) {
DebugUIPlugin.log(e);
}
fLastValueDetail= null;
}
if (fSelectionIterator != null && fSelectionIterator.hasNext()) {
Object obj = fSelectionIterator.next();
IValue val = null;
try {
if (obj instanceof IVariable) {
val = ((IVariable)obj).getValue();
} else if (obj instanceof IExpression) {
val = ((IExpression)obj).getValue();
}
fLastValueDetail= val;
getModelPresentation().computeDetail(val, VariablesView.this);
} catch (DebugException e) {
DebugUIPlugin.log(e);
getDetailDocument().set(DebugUIViewsMessages.getString("VariablesView.<error_occurred_retrieving_value>_18")); //$NON-NLS-1$
}
} else {
fValueSelection = null;
fSelectionIterator = null;
}
}
}
};
asyncExec(runnable);
}
/**
* Lazily instantiate and return a selection listener that updates the enabled
* state of the selection oriented actions in this view.
*/
protected ISelectionChangedListener getDetailSelectionChangedListener() {
if (fDetailSelectionChangedListener == null) {
fDetailSelectionChangedListener = new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
if (event.getSelectionProvider().equals(getVariablesViewSelectionProvider().getUnderlyingSelectionProvider())) {
getVariablesViewSelectionProvider().fireSelectionChanged(event);
updateSelectionDependentActions();
}
}
};
}
return fDetailSelectionChangedListener;
}
/**
* Lazily instantiate and return a document listener that updates the enabled state
* of the 'Find/Replace' action.
*/
protected IDocumentListener getDetailDocumentListener() {
if (fDetailDocumentListener == null) {
fDetailDocumentListener = new IDocumentListener() {
public void documentAboutToBeChanged(DocumentEvent event) {
}
public void documentChanged(DocumentEvent event) {
updateAction(ITextEditorActionConstants.FIND);
}
};
}
return fDetailDocumentListener;
}
/**
* Lazily instantiate and return a Document for the detail pane text viewer.
*/
protected IDocument getDetailDocument() {
if (fDetailDocument == null) {
fDetailDocument = new Document();
}
return fDetailDocument;
}
protected IDebugModelPresentation getModelPresentation() {
if (fModelPresentation == null) {
fModelPresentation = new VariablesViewModelPresentation();
}
return fModelPresentation;
}
/**
* Sets the viewer used to display value details.
*
* @param viewer source viewer
*/
private void setDetailViewer(ISourceViewer viewer) {
fDetailViewer = viewer;
}
/**
* Returns the viewer used to display value details
*
* @return source viewer
*/
protected ISourceViewer getDetailViewer() {
return fDetailViewer;
}
protected SashForm getSashForm() {
return fSashForm;
}
/**
* @see WorkbenchPart#getAdapter(Class)
*/
public Object getAdapter(Class required) {
if (IFindReplaceTarget.class.equals(required)) {
return getDetailViewer().getFindReplaceTarget();
}
if (ITextViewer.class.equals(required)) {
return getDetailViewer();
}
return super.getAdapter(required);
}
protected void updateSelectionDependentActions() {
Iterator iterator= fSelectionActions.iterator();
while (iterator.hasNext()) {
updateAction((String)iterator.next());
}
}
protected void updateAction(String actionId) {
IAction action= getAction(actionId);
if (action instanceof IUpdate) {
((IUpdate) action).update();
}
}
protected boolean isDetailPaneVisible() {
IAction action = getAction("ShowDetailPane"); //$NON-NLS-1$
return action != null && action.isChecked();
}
/**
* Sets the identifier of the debug model being displayed
* in this view, or <code>null</code> if none.
*
* @param id debug model identifier of the type of debug
* elements being displayed in this view
*/
protected void setDebugModel(String id) {
if (id != fDebugModelIdentifier) {
fDebugModelIdentifier = id;
configureDetailsViewer();
} else {
updateAction("ContentAssist"); //$NON-NLS-1$
}
}
/**
* Returns the identifier of the debug model being displayed
* in this view, or <code>null</code> if none.
*
* @return debug model identifier
*/
protected String getDebugModel() {
return fDebugModelIdentifier;
}
/**
* Sets the current configuration being used in the
* details area.
*
* @param config source viewer configuration
*/
private void setDetailViewerConfiguration(SourceViewerConfiguration config) {
fSourceViewerConfiguration = config;
}
/**
* Returns the current configuration being used in the
* details area.
*
* @return source viewer configuration
*/
protected SourceViewerConfiguration getDetailViewerConfiguration() {
return fSourceViewerConfiguration;
}
/**
* @see AbstractDebugView#getDefaultControl()
*/
protected Control getDefaultControl() {
return getSashForm();
}
/**
* @see IDebugExceptionHandler#handleException(DebugException)
*/
public void handleException(DebugException e) {
showMessage(e.getMessage());
}
protected VariablesViewSelectionProvider getVariablesViewSelectionProvider() {
return fSelectionProvider;
}
/**
* The <code>VariablesView</code> listens for selection changes in the <code>LaunchView</code>
*
* @see ISelectionListener#selectionChanged(IWorkbenchPart, ISelection)
*/
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (!isAvailable()) {
return;
}
if (selection == null) {
setViewerInput(new StructuredSelection());
} else if (selection instanceof IStructuredSelection) {
setViewerInput((IStructuredSelection) selection);
} else {
getDetailViewer().setEditable(false);
}
updateAction("ContentAssist"); //$NON-NLS-1$
}
/**
* Delegate to the <code>DOUBLE_CLICK_ACTION</code>,
* if any.
*
* @see IDoubleClickListener#doubleClick(DoubleClickEvent)
*/
public void doubleClick(DoubleClickEvent event) {
IAction action = getAction(DOUBLE_CLICK_ACTION);
if (action != null && action.isEnabled()) {
action.run();
} else {
ISelection selection= event.getSelection();
if (!(selection instanceof IStructuredSelection)) {
return;
}
IStructuredSelection ss= (IStructuredSelection)selection;
Object o= ss.getFirstElement();
TreeViewer tViewer= (TreeViewer)getViewer();
boolean expanded= tViewer.getExpandedState(o);
tViewer.setExpandedState(o, !expanded);
}
}
/**
* @see org.eclipse.ui.IWorkbenchPart#setFocus()
*/
public void setFocus() {
if (getFocusViewer() == null) {
super.setFocus();
} else {
getFocusViewer().getControl().setFocus();
}
}
/**
* Sets the viewer that has focus.
*
* @param viewer
*/
protected void setFocusViewer(Viewer viewer) {
fFocusViewer = viewer;
}
/**
* Returns the viewer that has focus, or <code>null</code>.
*
* @return Viewer
*/
protected Viewer getFocusViewer() {
return fFocusViewer;
}
/**
* @see IDebugView#getPresentation(String)
*/
public IDebugModelPresentation getPresentation(String id) {
if (getViewer() instanceof StructuredViewer) {
VariablesViewLabelProvider vvlp = (VariablesViewLabelProvider)((StructuredViewer)getViewer()).getLabelProvider();
IDebugModelPresentation lp = vvlp.getPresentation();
if (lp instanceof DelegatingModelPresentation) {
return ((DelegatingModelPresentation)lp).getPresentation(id);
}
if (lp instanceof LazyModelPresentation) {
if (((LazyModelPresentation)lp).getDebugModelIdentifier().equals(id)) {
return (IDebugModelPresentation)lp;
}
}
}
return null;
}
}