| /******************************************************************************* |
| * Copyright (c) 2000, 2006 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * QNX Software Systems - Mikhail Khodjaiants - Registers View (Bug 53640) |
| *******************************************************************************/ |
| package org.eclipse.debug.internal.ui.views.variables; |
| |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.OutputStreamWriter; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.ResourceBundle; |
| |
| import org.eclipse.core.commands.operations.IUndoContext; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.debug.core.DebugException; |
| import org.eclipse.debug.core.model.IDebugElement; |
| import org.eclipse.debug.core.model.IExpression; |
| 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.CollapseAllAction; |
| import org.eclipse.debug.internal.ui.actions.ConfigureColumnsAction; |
| import org.eclipse.debug.internal.ui.actions.FindElementAction; |
| import org.eclipse.debug.internal.ui.actions.variables.AssignValueAction; |
| import org.eclipse.debug.internal.ui.actions.variables.ChangeVariableValueAction; |
| import org.eclipse.debug.internal.ui.actions.variables.ShowTypesAction; |
| import org.eclipse.debug.internal.ui.actions.variables.ToggleDetailPaneAction; |
| import org.eclipse.debug.internal.ui.contexts.DebugContextManager; |
| import org.eclipse.debug.internal.ui.contexts.provisional.IDebugContextListener; |
| import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants; |
| import org.eclipse.debug.internal.ui.viewers.AsynchronousTreeViewer; |
| import org.eclipse.debug.internal.ui.viewers.PresentationContext; |
| import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext; |
| import org.eclipse.debug.internal.ui.views.AbstractViewerState; |
| import org.eclipse.debug.internal.ui.views.IDebugExceptionHandler; |
| import org.eclipse.debug.ui.AbstractDebugView; |
| import org.eclipse.debug.ui.IDebugModelPresentation; |
| import org.eclipse.debug.ui.IDebugUIConstants; |
| import org.eclipse.debug.ui.IDebugView; |
| import org.eclipse.debug.ui.IValueDetailListener; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.action.IMenuListener; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.IStatusLineManager; |
| 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.Assert; |
| 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.IUndoManager; |
| import org.eclipse.jface.text.IUndoManagerExtension; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.jface.text.source.ISourceViewerExtension2; |
| 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.PropertyChangeEvent; |
| import org.eclipse.jface.viewers.DoubleClickEvent; |
| 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.StructuredViewer; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.SashForm; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.events.FocusAdapter; |
| import org.eclipse.swt.events.FocusEvent; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.KeyListener; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.MouseListener; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.ui.IActionBars; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.IPerspectiveDescriptor; |
| import org.eclipse.ui.IPerspectiveListener; |
| import org.eclipse.ui.IViewSite; |
| import org.eclipse.ui.IWorkbenchActionConstants; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.WorkbenchException; |
| import org.eclipse.ui.XMLMemento; |
| import org.eclipse.ui.actions.ActionFactory; |
| import org.eclipse.ui.console.actions.TextViewerAction; |
| import org.eclipse.ui.operations.OperationHistoryActionHandler; |
| import org.eclipse.ui.operations.RedoActionHandler; |
| import org.eclipse.ui.operations.UndoActionHandler; |
| import org.eclipse.ui.progress.WorkbenchJob; |
| import org.eclipse.ui.texteditor.FindReplaceAction; |
| import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds; |
| import org.eclipse.ui.texteditor.ITextEditorActionConstants; |
| import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; |
| import org.eclipse.ui.texteditor.IUpdate; |
| import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds; |
| |
| import com.ibm.icu.text.MessageFormat; |
| |
| /** |
| * This view shows variables and their values for a particular stack frame |
| */ |
| public class VariablesView extends AbstractDebugView implements IDebugContextListener, |
| IPropertyChangeListener, |
| IValueDetailListener, |
| IDebugExceptionHandler, |
| IPerspectiveListener { |
| |
| /** |
| * Internal interface for a cursor listener. I.e. aggregation |
| * of mouse and key listener. |
| * @since 3.0 |
| */ |
| interface ICursorListener extends MouseListener, KeyListener { |
| } |
| |
| /** |
| * Most recently used variant with capped size that only counts |
| * {@linkplain #put(Object, Object) put} as access. This is implemented by always removing an |
| * element before it gets put back. |
| * |
| * @since 3.2 |
| */ |
| private static final class MRUMap extends LinkedHashMap { |
| private static final long serialVersionUID= 1L; |
| private final int fMaxSize; |
| |
| /** |
| * Creates a new <code>MRUMap</code> with the given size. |
| * |
| * @param maxSize the maximum size of the cache, must be > 0 |
| */ |
| public MRUMap(int maxSize) { |
| Assert.isLegal(maxSize > 0); |
| fMaxSize= maxSize; |
| } |
| |
| /* |
| * @see java.util.HashMap#put(java.lang.Object, java.lang.Object) |
| */ |
| public Object put(Object key, Object value) { |
| Object object= remove(key); |
| super.put(key, value); |
| return object; |
| } |
| |
| /* |
| * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry) |
| */ |
| protected boolean removeEldestEntry(java.util.Map.Entry eldest) { |
| return size() > fMaxSize; |
| } |
| } |
| |
| /** |
| * 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); |
| } |
| } |
| } |
| |
| /** |
| * Retargets the find action to the details area or tree viewer. |
| * |
| * @since 3.2 |
| */ |
| class DelegatingFindAction extends Action implements IUpdate { |
| private IAction getFindAction() { |
| if (getDetailViewer().getTextWidget().isFocusControl()) { |
| return getAction("FindReplaceText"); //$NON-NLS-1$ |
| } else { |
| return getAction(FIND_ELEMENT); |
| } |
| } |
| public void run() { |
| getFindAction().run(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.texteditor.IUpdate#update() |
| */ |
| public void update() { |
| setEnabled(getFindAction().isEnabled()); |
| } |
| } |
| |
| /** |
| * 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 SourceViewer 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); |
| |
| /** |
| * An MRU cache of stack frame hash codes 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 limited |
| * to twenty entries. |
| */ |
| private HashMap fSelectionStates = new MRUMap(20); |
| |
| /** |
| * The last known viewer state. Used to init the expansion/selection |
| * in the variables view when there is no state to go on for the |
| * current stack frame being displayed. |
| */ |
| private AbstractViewerState fLastState = null; |
| |
| /** |
| * 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 = {13, 6}; |
| private int[] fLastSashWeights; |
| private boolean fToggledDetailOnce; |
| private String fCurrentDetailPaneOrientation = IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_HIDDEN; |
| private ToggleDetailPaneAction[] fToggleDetailPaneActions; |
| private ConfigureColumnsAction fConfigureColumnsAction; |
| |
| protected String PREF_STATE_MEMENTO = "pref_state_memento."; //$NON-NLS-1$ |
| |
| 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 = ActionFactory.COPY.getId() + ".Detail"; //$NON-NLS-1$ |
| |
| public static final String LOGICAL_STRUCTURE_TYPE_PREFIX = "VAR_LS_"; //$NON-NLS-1$ |
| |
| /** |
| * the pref name for the view part of the sashform |
| * @since 3.2 |
| */ |
| protected static final String SASH_VIEW_PART = DebugUIPlugin.getUniqueIdentifier() + ".SASH_VIEW_PART"; //$NON-NLS-1$ |
| /** |
| * thepref name for the details part of the sashform |
| * @since 3.2 |
| */ |
| protected static final String SASH_DETAILS_PART = DebugUIPlugin.getUniqueIdentifier() + ".SASH_DETAILS_PART"; //$NON-NLS-1$ |
| |
| /** |
| * Key for "Find..." action. |
| */ |
| protected static final String FIND_ELEMENT = "FindElement"; //$NON-NLS-1$ |
| |
| private StatusLineContributionItem fStatusLineItem; |
| private ICursorListener fCursorListener; |
| /** |
| * Data structure for the position label value. |
| */ |
| private static class PositionLabelValue { |
| |
| public int fValue; |
| |
| public String toString() { |
| return String.valueOf(fValue); |
| } |
| } |
| /** The pattern used to show the position label in the status line. */ |
| private final String fPositionLabelPattern= VariablesViewMessages.VariablesView_56; |
| /** The position label value of the current line. */ |
| private final PositionLabelValue fLineLabel= new PositionLabelValue(); |
| /** The position label value of the current column. */ |
| private final PositionLabelValue fColumnLabel= new PositionLabelValue(); |
| /** The arguments for the position label pattern. */ |
| private final Object[] fPositionLabelPatternArguments= new Object[] { fLineLabel, fColumnLabel }; |
| /** Whether logical structuers are showing */ |
| private boolean fShowLogical; |
| |
| /** |
| * Remove myself as a selection listener |
| * and preference change listener. |
| * |
| * @see IWorkbenchPart#dispose() |
| */ |
| public void dispose() { |
| getViewSite().getActionBars().getStatusLineManager().remove(fStatusLineItem); |
| DebugContextManager.getDefault().removeDebugContextListener(this, getSite().getWorkbenchWindow()); |
| getSite().getWorkbenchWindow().removePerspectiveListener(this); |
| DebugUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this); |
| JFaceResources.getFontRegistry().removeListener(this); |
| Viewer viewer = getViewer(); |
| if (viewer != null) { |
| getDetailDocument().removeDocumentListener(getDetailDocumentListener()); |
| if (viewer instanceof AsynchronousTreeViewer) { |
| AsynchronousTreeViewer asyncTreeViewer = (AsynchronousTreeViewer) viewer; |
| asyncTreeViewer.dispose(); |
| } |
| } |
| fSelectionStates.clear(); |
| super.dispose(); |
| } |
| |
| protected void setViewerInput(Object context) { |
| |
| getDetailViewer().setEditable(context != null); |
| |
| Object current= getViewer().getInput(); |
| |
| if (current == null && context == null) { |
| return; |
| } |
| |
| if (current != null && current.equals(context)) { |
| return; |
| } |
| |
| if (current != null) { |
| // save state |
| AbstractViewerState state = getViewerState(); |
| cacheViewerState(current, state); |
| fLastState = (AbstractViewerState) state.clone(); |
| } |
| |
| if (context instanceof IDebugElement) { |
| setDebugModel(((IDebugElement)context).getModelIdentifier()); |
| } |
| showViewer(); |
| getViewer().setInput(context); |
| restoreState(); |
| } |
| |
| /** |
| * Caches the given viewer state for the given viewer input. |
| * |
| * @param input viewer input |
| * @param state viewer state |
| */ |
| protected void cacheViewerState(Object input, AbstractViewerState state) { |
| // generate a key for the input based on its hashcode, we don't |
| // want to maintain reference real model objects preventing GCs. |
| fSelectionStates.put(generateKey(input), state); |
| } |
| |
| /** |
| * Generate a key for an input object. |
| * |
| * @param input |
| * @return key |
| */ |
| protected Object generateKey(Object input) { |
| return new Integer(input.hashCode()); |
| } |
| |
| /** |
| * Returns the cached viewer state for the given viewer input or |
| * <code>null</code> if none. |
| * |
| * @param input viewer input |
| * @return viewer state or <code>null</code> |
| */ |
| protected AbstractViewerState getCachedViewerState(Object input) { |
| return (AbstractViewerState) fSelectionStates.get(generateKey(input)); |
| } |
| |
| protected void restoreState() { |
| VariablesViewer viewer = (VariablesViewer) getViewer(); |
| if (viewer != null) { |
| Object context = viewer.getInput(); |
| if (context != null) { |
| AbstractViewerState state = getCachedViewerState(context); |
| if (state == null) { |
| // attempt to restore selection/expansion based on last |
| // frame |
| if (fLastState != null) { |
| state = fLastState; |
| } |
| } |
| if (state != null) { |
| state.restoreState(viewer); |
| } |
| } |
| } |
| } |
| |
| /** |
| * 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(), VariablesViewMessages.VariablesView_Error_1, VariablesViewMessages.VariablesView_Unable_to_configure_variable_details_area__2, e); |
| } |
| } |
| ISourceViewer detailViewer = getDetailViewer(); |
| if (svc == null) { |
| svc = new SourceViewerConfiguration(); |
| detailViewer.setEditable(false); |
| } |
| if (detailViewer instanceof ISourceViewerExtension2) { |
| ISourceViewerExtension2 sourceViewer = (ISourceViewerExtension2) detailViewer; |
| sourceViewer.unconfigure(); |
| } |
| detailViewer.configure(svc); |
| //update actions that depend on the configuration of the details viewer |
| updateAction("ContentAssist"); //$NON-NLS-1$ |
| setDetailViewerConfiguration(svc); |
| createUndoRedoActions(); |
| } |
| |
| /** |
| * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) |
| */ |
| public void propertyChange(PropertyChangeEvent event) { |
| String propertyName= event.getProperty(); |
| if (propertyName.equals(IDebugUIConstants.PREF_CHANGED_DEBUG_ELEMENT_COLOR) || |
| propertyName.equals(IInternalDebugUIConstants.PREF_CHANGED_VALUE_BACKGROUND)) { |
| getViewer().refresh(); |
| } else if (propertyName.equals(IInternalDebugUIConstants.DETAIL_PANE_FONT)) { |
| getDetailViewer().getTextWidget().setFont(JFaceResources.getFont(IInternalDebugUIConstants.DETAIL_PANE_FONT)); |
| } else if (propertyName.equals(IInternalDebugUIConstants.PREF_MAX_DETAIL_LENGTH)) { |
| populateDetailPane(); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.AbstractDebugView#createViewer(Composite) |
| */ |
| public Viewer createViewer(Composite parent) { |
| VariablesViewer variablesViewer = (VariablesViewer) createTreeViewer(parent); |
| variablesViewer.setContext(new PresentationContext(this)); |
| variablesViewer.getPresentationContext().addPropertyChangeListener( |
| new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| if (IPresentationContext.PROPERTY_COLUMNS.equals(event.getProperty())) { |
| IAction action = getAction("ShowTypeNames"); //$NON-NLS-1$ |
| if (action != null) { |
| action.setEnabled(event.getNewValue() == null); |
| } |
| } |
| } |
| }); |
| |
| createDetailsViewer(); |
| fSashForm.setMaximizedControl(variablesViewer.getControl()); |
| |
| createOrientationActions(variablesViewer); |
| IPreferenceStore prefStore = DebugUIPlugin.getDefault().getPreferenceStore(); |
| String orientation = prefStore.getString(getDetailPanePreferenceKey()); |
| for (int i = 0; i < fToggleDetailPaneActions.length; i++) { |
| fToggleDetailPaneActions[i].setChecked(fToggleDetailPaneActions[i].getOrientation().equals(orientation)); |
| } |
| setDetailPaneOrientation(orientation); |
| IMemento memento = getMemento(); |
| if (memento != null) { |
| variablesViewer.initState(memento); |
| } |
| return variablesViewer; |
| } |
| |
| /* (non-Javadoc) |
| * @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); |
| PREF_STATE_MEMENTO = PREF_STATE_MEMENTO + site.getId(); |
| IPreferenceStore store = DebugUIPlugin.getDefault().getPreferenceStore(); |
| String string = store.getString(PREF_STATE_MEMENTO); |
| if(string.length() > 0) { |
| ByteArrayInputStream bin = new ByteArrayInputStream(string.getBytes()); |
| InputStreamReader reader = new InputStreamReader(bin); |
| try { |
| XMLMemento stateMemento = XMLMemento.createReadRoot(reader); |
| setMemento(stateMemento); |
| } catch (WorkbenchException e) { |
| } finally { |
| try { |
| reader.close(); |
| bin.close(); |
| } catch (IOException e){} |
| } |
| } |
| IMemento mem = getMemento(); |
| if (mem != null) { |
| Integer sw = mem.getInteger(SASH_VIEW_PART); |
| if(sw != null) { |
| setLastSashWeights(new int[] {sw.intValue(), mem.getInteger(SASH_DETAILS_PART).intValue()}); |
| } |
| else { |
| setLastSashWeights(DEFAULT_SASH_WEIGHTS); |
| } |
| } |
| site.getWorkbenchWindow().addPerspectiveListener(this); |
| } |
| |
| |
| public void partDeactivated(IWorkbenchPart part) { |
| String id = part.getSite().getId(); |
| if (id.equals(getSite().getId())) { |
| ByteArrayOutputStream bout = new ByteArrayOutputStream(); |
| OutputStreamWriter writer = new OutputStreamWriter(bout); |
| |
| try { |
| XMLMemento memento = XMLMemento.createWriteRoot("VariablesViewMemento"); //$NON-NLS-1$ |
| saveViewerState(memento); |
| memento.save(writer); |
| |
| IPreferenceStore store = DebugUIPlugin.getDefault().getPreferenceStore(); |
| String xmlString = bout.toString(); |
| store.putValue(PREF_STATE_MEMENTO, xmlString); |
| } catch (IOException e) { |
| } finally { |
| try { |
| writer.close(); |
| bout.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| super.partDeactivated(part); |
| } |
| |
| public void saveViewerState(IMemento memento) { |
| if (fSashForm != null && !fSashForm.isDisposed()) { |
| int[] weights = fSashForm.getWeights(); |
| memento.putInteger(SASH_VIEW_PART, weights[0]); |
| memento.putInteger(SASH_DETAILS_PART, weights[1]); |
| } |
| getVariablesViewer().saveState(memento); |
| } |
| |
| protected String getDetailPanePreferenceKey() { |
| return IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_ORIENTATION; |
| } |
| |
| /** |
| * Create and return the main tree viewer that displays variable. |
| */ |
| protected Viewer createTreeViewer(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); |
| |
| // add tree viewer |
| final VariablesViewer variablesViewer = createVariablesViewer(fSashForm); |
| variablesViewer.getControl().addFocusListener(new FocusAdapter() { |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.events.FocusListener#focusGained(FocusEvent) |
| */ |
| public void focusGained(FocusEvent e) { |
| getVariablesViewSelectionProvider().setUnderlyingSelectionProvider(variablesViewer); |
| setAction(SELECT_ALL_ACTION, getAction(VARIABLES_SELECT_ALL_ACTION)); |
| setAction(COPY_ACTION, getAction(IDebugView.COPY_ACTION)); |
| getViewSite().getActionBars().updateActionBars(); |
| setFocusViewer(getViewer()); |
| } |
| }); |
| variablesViewer.addPostSelectionChangedListener(getTreeSelectionChangedListener()); |
| getVariablesViewSelectionProvider().setUnderlyingSelectionProvider(variablesViewer); |
| getSite().setSelectionProvider(getVariablesViewSelectionProvider()); |
| |
| // listen to debug context |
| DebugContextManager.getDefault().addDebugContextListener(this, getSite().getWorkbenchWindow()); |
| return variablesViewer; |
| } |
| |
| /** |
| * Creates and returns a variables viewer in the given composite. |
| * |
| * @param parent |
| * @return variables viewer |
| */ |
| protected VariablesViewer createVariablesViewer(Composite parent) { |
| return new VariablesViewer(parent, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL | SWT.FULL_SELECTION, this); |
| } |
| |
| /** |
| * Create the widgetry for the details viewer. |
| */ |
| protected void createDetailsViewer() { |
| // Create & configure a SourceViewer |
| SourceViewer detailsViewer= new SourceViewer(fSashForm, null, SWT.V_SCROLL | SWT.H_SCROLL); |
| fDetailViewer = detailsViewer; |
| detailsViewer.setDocument(getDetailDocument()); |
| detailsViewer.getTextWidget().setFont(JFaceResources.getFont(IInternalDebugUIConstants.DETAIL_PANE_FONT)); |
| getDetailDocument().addDocumentListener(getDetailDocumentListener()); |
| detailsViewer.setEditable(false); |
| Control control = detailsViewer.getControl(); |
| GridData gd = new GridData(GridData.FILL_BOTH); |
| control.setLayoutData(gd); |
| |
| detailsViewer.getSelectionProvider().addSelectionChangedListener(getDetailSelectionChangedListener()); |
| detailsViewer.getControl().addFocusListener(new FocusAdapter() { |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.events.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()); |
| |
| detailsViewer.getTextWidget().addMouseListener(getCursorListener()); |
| detailsViewer.getTextWidget().addKeyListener(getCursorListener()); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.AbstractDebugView#getHelpContextId() |
| */ |
| protected String getHelpContextId() { |
| return IDebugHelpContextIds.VARIABLE_VIEW; |
| } |
| |
| /** |
| * Set the orientation of the details pane so that is one of: |
| * - underneath the main tree view |
| * - to the right of the main tree view |
| * - not visible |
| */ |
| public void setDetailPaneOrientation(String orientation) { |
| if (orientation.equals(fCurrentDetailPaneOrientation)) { |
| return; |
| } |
| if (orientation.equals(IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_HIDDEN)) { |
| hideDetailPane(); |
| } else { |
| int vertOrHoriz = orientation.equals(IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_UNDERNEATH) ? SWT.VERTICAL : SWT.HORIZONTAL; |
| fSashForm.setOrientation(vertOrHoriz); |
| if (IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_HIDDEN.equals(fCurrentDetailPaneOrientation)) { |
| showDetailPane(); |
| } |
| } |
| fCurrentDetailPaneOrientation = orientation; |
| DebugUIPlugin.getDefault().getPreferenceStore().setValue(getDetailPanePreferenceKey(), orientation); |
| } |
| |
| private void hideDetailPane() { |
| if (fToggledDetailOnce) { |
| setLastSashWeights(fSashForm.getWeights()); |
| } |
| fSashForm.setMaximizedControl(getViewer().getControl()); |
| } |
| |
| private void showDetailPane() { |
| fSashForm.setMaximizedControl(null); |
| fSashForm.setWeights(getLastSashWeights()); |
| populateDetailPane(); |
| revealTreeSelection(); |
| fToggledDetailOnce = true; |
| } |
| |
| /** |
| * Make sure the currently selected item in the tree is visible. |
| */ |
| protected void revealTreeSelection() { |
| StructuredViewer viewer = (StructuredViewer) getViewer(); |
| if (viewer != null) { |
| ISelection selection = viewer.getSelection(); |
| if (selection instanceof IStructuredSelection) { |
| Object selected = ((IStructuredSelection)selection).getFirstElement(); |
| if (selected != null) { |
| viewer.reveal(selected); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Set on or off the word wrap flag for the detail pane. |
| */ |
| public void toggleDetailPaneWordWrap(boolean on) { |
| fDetailViewer.getTextWidget().setWordWrap(on); |
| } |
| |
| /** |
| * 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; |
| } |
| |
| /** |
| * 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(); |
| 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); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.AbstractDebugView#createActions() |
| */ |
| protected void createActions() { |
| IAction action = new ShowTypesAction(this); |
| setAction("ShowTypeNames",action); //$NON-NLS-1$ |
| |
| action = new ToggleLogicalStructureAction(this); |
| setAction("ToggleContentProviders", action); //$NON-NLS-1$ |
| |
| action = new CollapseAllAction((AsynchronousTreeViewer)getViewer()); |
| setAction("CollapseAll", action); //$NON-NLS-1$ |
| |
| action = new ChangeVariableValueAction(this); |
| action.setEnabled(false); |
| setAction("ChangeVariableValue", action); //$NON-NLS-1$ |
| |
| TextViewerAction textAction= new TextViewerAction(getDetailViewer(), ISourceViewer.CONTENTASSIST_PROPOSALS); |
| textAction.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); |
| textAction.configureAction(VariablesViewMessages.VariablesView_Co_ntent_Assist_3, "",""); //$NON-NLS-1$ //$NON-NLS-2$ |
| 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(VariablesViewMessages.VariablesView_Select__All_5, "", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.SELECT_ALL); |
| setAction(DETAIL_SELECT_ALL_ACTION, textAction); |
| |
| textAction= new TextViewerAction(getDetailViewer(), ITextOperationTarget.COPY); |
| textAction.configureAction(VariablesViewMessages.VariablesView__Copy_8, "", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY); |
| setAction(DETAIL_COPY_ACTION, textAction); |
| |
| textAction= new TextViewerAction(getDetailViewer(), ITextOperationTarget.CUT); |
| textAction.configureAction(VariablesViewMessages.VariablesView_Cu_t_11, "", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.CUT); |
| setAction(ActionFactory.CUT.getId(), textAction); |
| |
| textAction= new TextViewerAction(getDetailViewer(), ITextOperationTarget.PASTE); |
| textAction.configureAction(VariablesViewMessages.VariablesView__Paste_14, "", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.PASTE); |
| setAction(ActionFactory.PASTE.getId(), textAction); |
| |
| action= new FindElementAction(this, getVariablesViewer()); |
| setAction(FIND_ELEMENT, action); |
| |
| // TODO: Still using "old" resource access |
| ResourceBundle bundle= ResourceBundle.getBundle("org.eclipse.debug.internal.ui.views.variables.VariablesViewMessages"); //$NON-NLS-1$ |
| action = new FindReplaceAction(bundle, "find_replace_action_", VariablesView.this); //$NON-NLS-1$ |
| action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_REPLACE); |
| setAction("FindReplaceText", action); //$NON-NLS-1$ |
| |
| setAction(FIND_ACTION, new DelegatingFindAction()); |
| |
| fSelectionActions.add(ActionFactory.COPY.getId()); |
| fSelectionActions.add(ActionFactory.CUT.getId()); |
| fSelectionActions.add(ActionFactory.PASTE.getId()); |
| fSelectionActions.add("FindReplaceText"); //$NON-NLS-1$ |
| updateAction("FindReplaceText"); //$NON-NLS-1$ |
| |
| action = new AssignValueAction(this, fDetailViewer); |
| setAction("AssignValue", action); //$NON-NLS-1$ |
| |
| fStatusLineItem = new StatusLineContributionItem("ModeContributionItem"); //$NON-NLS-1$ |
| IActionBars actionBars = getViewSite().getActionBars(); |
| IStatusLineManager manager= actionBars.getStatusLineManager(); |
| manager.add(fStatusLineItem); |
| } |
| |
| /** |
| * Creates this editor's undo/redo actions. |
| * <p> |
| * Subclasses may override or extend.</p> |
| * |
| * @since 3.2 |
| */ |
| protected void createUndoRedoActions() { |
| disposeUndoRedoAction(ITextEditorActionConstants.UNDO); |
| disposeUndoRedoAction(ITextEditorActionConstants.REDO); |
| IUndoContext undoContext= getUndoContext(); |
| if (undoContext != null) { |
| // Use actions provided by global undo/redo |
| |
| // Create the undo action |
| OperationHistoryActionHandler undoAction= new UndoActionHandler(getSite(), undoContext); |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(undoAction, IAbstractTextEditorHelpContextIds.UNDO_ACTION); |
| undoAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.UNDO); |
| setAction(ITextEditorActionConstants.UNDO, undoAction); |
| |
| // Create the redo action. |
| OperationHistoryActionHandler redoAction= new RedoActionHandler(getSite(), undoContext); |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(redoAction, IAbstractTextEditorHelpContextIds.REDO_ACTION); |
| redoAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.REDO); |
| setAction(ITextEditorActionConstants.REDO, redoAction); |
| } |
| } |
| |
| private void disposeUndoRedoAction(String actionId) { |
| OperationHistoryActionHandler action = (OperationHistoryActionHandler) getAction(actionId); |
| if (action != null) { |
| action.dispose(); |
| setAction(actionId, null); |
| } |
| } |
| /** |
| * Returns this editor's viewer's undo manager undo context. |
| * |
| * @return the undo context or <code>null</code> if not available |
| * @since 3.2 |
| */ |
| private IUndoContext getUndoContext() { |
| IUndoManager undoManager= fDetailViewer.getUndoManager(); |
| if (undoManager instanceof IUndoManagerExtension) |
| return ((IUndoManagerExtension)undoManager).getUndoContext(); |
| return null; |
| } |
| |
| private void createOrientationActions(VariablesViewer viewer) { |
| IActionBars actionBars = getViewSite().getActionBars(); |
| IMenuManager viewMenu = actionBars.getMenuManager(); |
| |
| fToggleDetailPaneActions = new ToggleDetailPaneAction[3]; |
| fToggleDetailPaneActions[0] = new ToggleDetailPaneAction(this, IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_UNDERNEATH, null); |
| fToggleDetailPaneActions[1] = new ToggleDetailPaneAction(this, IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_RIGHT, null); |
| fToggleDetailPaneActions[2] = new ToggleDetailPaneAction(this, IDebugPreferenceConstants.VARIABLES_DETAIL_PANE_HIDDEN, getToggleActionLabel()); |
| viewMenu.add(new Separator()); |
| final MenuManager layoutSubMenu = new MenuManager(VariablesViewMessages.VariablesView_40); |
| layoutSubMenu.setRemoveAllWhenShown(true); |
| layoutSubMenu.add(fToggleDetailPaneActions[0]); |
| layoutSubMenu.add(fToggleDetailPaneActions[1]); |
| layoutSubMenu.add(fToggleDetailPaneActions[2]); |
| viewMenu.add(layoutSubMenu); |
| viewMenu.add(new Separator()); |
| |
| fConfigureColumnsAction = new ConfigureColumnsAction(viewer); |
| setAction("ToggleColmns", new ToggleShowColumnsAction(viewer)); //$NON-NLS-1$ |
| |
| layoutSubMenu.addMenuListener(new IMenuListener() { |
| public void menuAboutToShow(IMenuManager manager) { |
| layoutSubMenu.add(fToggleDetailPaneActions[0]); |
| layoutSubMenu.add(fToggleDetailPaneActions[1]); |
| layoutSubMenu.add(fToggleDetailPaneActions[2]); |
| IAction action = getAction("ToggleColmns"); //$NON-NLS-1$ |
| ((IUpdate)action).update(); |
| if (action.isEnabled()) { |
| layoutSubMenu.add(action); |
| } |
| fConfigureColumnsAction.update(); |
| if (fConfigureColumnsAction.isEnabled()) { |
| layoutSubMenu.add(fConfigureColumnsAction); |
| } |
| } |
| }); |
| } |
| |
| protected String getToggleActionLabel() { |
| return VariablesViewMessages.VariablesView_41; |
| } |
| |
| /** |
| * 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(getAction("ToggleContentProviders")); //$NON-NLS-1$ |
| tbm.add(getAction("CollapseAll")); //$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(FIND_ELEMENT)); |
| menu.add(getAction("ChangeVariableValue")); //$NON-NLS-1$ |
| IAction action = new AvailableLogicalStructuresAction(this); |
| if (action.isEnabled()) { |
| menu.add(action); |
| } |
| 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("AssignValue")); //$NON-NLS-1$ |
| menu.add(getAction("ContentAssist")); //$NON-NLS-1$ |
| menu.add(new Separator()); |
| menu.add(getAction(ActionFactory.CUT.getId())); |
| menu.add(getAction(ActionFactory.COPY.getId() + ".Detail")); //$NON-NLS-1$ |
| menu.add(getAction(ActionFactory.PASTE.getId())); |
| menu.add(getAction(DETAIL_SELECT_ALL_ACTION)); |
| menu.add(new Separator("FIND")); //$NON-NLS-1$ |
| menu.add(getAction("FindReplaceText")); //$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(final SelectionChangedEvent event) { |
| if (event.getSelectionProvider().equals(getViewer())) { |
| clearStatusLine(); |
| getVariablesViewSelectionProvider().fireSelectionChanged(event); |
| // if the detail pane is not visible, don't waste time retrieving details |
| if (fSashForm.getMaximizedControl() == getViewer().getControl()) { |
| return; |
| } |
| |
| Job job = new Job("Detail Pane Populate Job") {//$NON-NLS-1$ |
| protected IStatus run(IProgressMonitor monitor) { |
| IStructuredSelection selection = (IStructuredSelection)event.getSelection(); |
| populateDetailPaneFromSelection(selection); |
| return Status.OK_STATUS; |
| } |
| }; |
| job.setSystem(true); |
| job.schedule(); |
| |
| treeSelectionChanged(event); |
| } |
| } |
| }; |
| } |
| return fTreeSelectionChangedListener; |
| } |
| |
| /** |
| * Selection in the variable tree changed. Perform any updates. |
| * |
| * @param event |
| */ |
| protected void treeSelectionChanged(SelectionChangedEvent event) {} |
| |
| /** |
| * Ask the variables tree for its current selection, and use this to populate |
| * the detail pane. |
| */ |
| public void populateDetailPane() { |
| if (isDetailPaneVisible()) { |
| Viewer viewer = getViewer(); |
| if (viewer != null) { |
| final IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); |
| Job job = new Job("Populate Detail Pane") {//$NON-NLS-1$ |
| protected IStatus run(IProgressMonitor monitor) { |
| populateDetailPaneFromSelection(selection); |
| return Status.OK_STATUS; |
| } |
| }; |
| job.setSystem(true); |
| job.schedule(); |
| } |
| } |
| } |
| |
| /** |
| * Show the details associated with the first of the selected variables in the |
| * detail pane. |
| */ |
| protected void populateDetailPaneFromSelection(final IStructuredSelection selection) { |
| WorkbenchJob wJob = new WorkbenchJob("Populate Details Pane") { //$NON-NLS-1$ |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| getDetailDocument().set(""); //$NON-NLS-1$ |
| return Status.OK_STATUS; |
| } |
| }; |
| wJob.setSystem(true); |
| wJob.schedule(); |
| |
| try { |
| if (!selection.isEmpty()) { |
| IValue val = null; |
| Object obj = selection.getFirstElement(); |
| if (obj instanceof IndexedVariablePartition) { |
| // no details for parititions |
| return; |
| } |
| |
| 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; |
| } |
| |
| final IValue finalVal = val; |
| |
| wJob = new WorkbenchJob("Populate Details Pane"){ //$NON-NLS-1$ |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| getDetailDocument().set(""); //$NON-NLS-1$ |
| setDebugModel(finalVal.getModelIdentifier()); |
| fValueSelection = selection; |
| fSelectionIterator = selection.iterator(); |
| fSelectionIterator.next(); |
| fLastValueDetail= finalVal; |
| getModelPresentation().computeDetail(finalVal, VariablesView.this); |
| return Status.OK_STATUS; |
| } |
| }; |
| wJob.setSystem(true); |
| wJob.schedule(); |
| } |
| } catch (DebugException de) { |
| wJob = new WorkbenchJob("Populate Details Pane") { //$NON-NLS-1$ |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| getDetailDocument().set(VariablesViewMessages.VariablesView__error_occurred_retrieving_value__18); |
| return Status.OK_STATUS; |
| } |
| |
| }; |
| wJob.setSystem(true); |
| wJob.schedule(); |
| } |
| } |
| |
| /** |
| * @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().getLength(); |
| if (length > 0) { |
| insert = "\n" + result; //$NON-NLS-1$ |
| } |
| try { |
| int max = DebugUIPlugin.getDefault().getPreferenceStore().getInt(IInternalDebugUIConstants.PREF_MAX_DETAIL_LENGTH); |
| if (max > 0 && insert.length() > max) { |
| insert = insert.substring(0, max) + "..."; //$NON-NLS-1$ |
| } |
| 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(VariablesViewMessages.VariablesView__error_occurred_retrieving_value__18); |
| } |
| } 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(ActionFactory.FIND.getId()); |
| } |
| }; |
| } |
| 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; |
| } |
| |
| /** |
| * Returns the viewer used to display value details |
| * |
| * @return source viewer |
| */ |
| protected ISourceViewer getDetailViewer() { |
| return fDetailViewer; |
| } |
| |
| /** |
| * Returns the sashform |
| * @return the current sashform |
| */ |
| protected SashForm getSashForm() { |
| return fSashForm; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(Class) |
| */ |
| public Object getAdapter(Class required) { |
| if (IFindReplaceTarget.class.equals(required)) { |
| return getDetailViewer().getFindReplaceTarget(); |
| } |
| if (ITextViewer.class.equals(required)) { |
| return getDetailViewer(); |
| } |
| if (IDebugModelPresentation.class.equals(required)) { |
| return getModelPresentation(); |
| } |
| 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() { |
| return !fToggleDetailPaneActions[2].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; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.AbstractDebugView#getDefaultControl() |
| */ |
| protected Control getDefaultControl() { |
| return fSashForm; |
| } |
| |
| /** |
| * @see IDebugExceptionHandler#handleException(DebugException) |
| */ |
| public void handleException(DebugException e) { |
| showMessage(e.getMessage()); |
| } |
| |
| protected VariablesViewSelectionProvider getVariablesViewSelectionProvider() { |
| return fSelectionProvider; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.contexts.IDebugContextListener#contextActivated(java.lang.Object, org.eclipse.ui.IWorkbenchPart) |
| */ |
| public void contextActivated(ISelection selection, IWorkbenchPart part) { |
| if (!isAvailable() || !isVisible()) { |
| return; |
| } |
| |
| if (selection instanceof IStructuredSelection) { |
| setViewerInput(((IStructuredSelection)selection).getFirstElement()); |
| } |
| showViewer(); |
| |
| updateAction("ContentAssist"); //$NON-NLS-1$ |
| updateAction(FIND_ELEMENT); |
| updateAction(FIND_ACTION); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.contexts.IDebugContextListener#contextChanged(org.eclipse.jface.viewers.ISelection, org.eclipse.ui.IWorkbenchPart) |
| */ |
| public void contextChanged(ISelection selection, IWorkbenchPart part) { |
| } |
| |
| /** |
| * Delegate to the <code>DOUBLE_CLICK_ACTION</code>, |
| * if any. |
| * |
| * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(DoubleClickEvent) |
| */ |
| public void doubleClick(DoubleClickEvent event) { |
| IAction action = getAction(DOUBLE_CLICK_ACTION); |
| if (action != null && action.isEnabled()) { |
| action.run(); |
| } |
| } |
| /** |
| * @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; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IDebugView#getPresentation(String) |
| */ |
| public IDebugModelPresentation getPresentation(String id) { |
| if (getViewer() instanceof StructuredViewer) { |
| IDebugModelPresentation lp = getModelPresentation(); |
| if (lp instanceof DelegatingModelPresentation) { |
| return ((DelegatingModelPresentation)lp).getPresentation(id); |
| } |
| if (lp instanceof LazyModelPresentation) { |
| if (((LazyModelPresentation)lp).getDebugModelIdentifier().equals(id)) { |
| return lp; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IDetailSite#getDetailViewerParent() |
| */ |
| public Composite getDetailViewerParent() { |
| return fSashForm; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.IDetailSite#isMainViewerAvailable() |
| */ |
| public boolean isMainViewerAvailable() { |
| return isAvailable(); |
| } |
| |
| /** |
| * Sets whether logical structures are being displayed |
| */ |
| public void setShowLogicalStructure(boolean flag) { |
| fShowLogical = flag; |
| } |
| |
| /** |
| * Returns whether logical structures are being displayed |
| */ |
| public boolean isShowLogicalStructure() { |
| return fShowLogical; |
| } |
| |
| /** |
| * Returns the number of entries that should be displayed in each |
| * partition of an indexed collection. |
| * |
| * @return the number of entries that should be displayed in each |
| * partition of an indexed collection |
| */ |
| protected int getArrayPartitionSize() { |
| // TODO: this should be a view setting |
| return 100; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.AbstractDebugView#becomesHidden() |
| */ |
| protected void becomesHidden() { |
| setViewerInput(null); |
| super.becomesHidden(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.AbstractDebugView#becomesVisible() |
| */ |
| protected void becomesVisible() { |
| super.becomesVisible(); |
| ISelection selection = DebugContextManager.getDefault().getActiveContext(getSite().getWorkbenchWindow()); |
| contextActivated(selection, null); |
| } |
| |
| /** |
| * Returns the memento of the expanded and selected items in the viewer. |
| * |
| * @return the memento of the expanded and selected items in the viewer |
| */ |
| protected AbstractViewerState getViewerState() { |
| return new ViewerState(getVariablesViewer()); |
| } |
| |
| protected VariablesViewer getVariablesViewer() { |
| return (VariablesViewer) getViewer(); |
| } |
| |
| /** |
| * Returns this view's "cursor" listener to be installed on the view's |
| * associated details viewer. This listener is listening to key and mouse button events. |
| * It triggers the updating of the status line. |
| * |
| * @return the listener |
| */ |
| private ICursorListener getCursorListener() { |
| if (fCursorListener == null) { |
| fCursorListener= new ICursorListener() { |
| |
| public void keyPressed(KeyEvent e) { |
| fStatusLineItem.setText(getCursorPosition()); |
| } |
| |
| public void keyReleased(KeyEvent e) { |
| } |
| |
| public void mouseDoubleClick(MouseEvent e) { |
| } |
| |
| public void mouseDown(MouseEvent e) { |
| } |
| |
| public void mouseUp(MouseEvent e) { |
| fStatusLineItem.setText(getCursorPosition()); |
| } |
| }; |
| } |
| return fCursorListener; |
| } |
| |
| protected String getCursorPosition() { |
| |
| if (getDetailViewer() == null) { |
| return ""; //$NON-NLS-1$ |
| } |
| |
| StyledText styledText= getDetailViewer().getTextWidget(); |
| int caret= styledText.getCaretOffset(); |
| IDocument document= getDetailViewer().getDocument(); |
| |
| if (document == null) { |
| return ""; //$NON-NLS-1$ |
| } |
| |
| try { |
| |
| int line= document.getLineOfOffset(caret); |
| |
| int lineOffset= document.getLineOffset(line); |
| int tabWidth= styledText.getTabs(); |
| int column= 0; |
| for (int i= lineOffset; i < caret; i++) |
| if ('\t' == document.getChar(i)) { |
| column += tabWidth - (tabWidth == 0 ? 0 : column % tabWidth); |
| } else { |
| column++; |
| } |
| |
| fLineLabel.fValue= line + 1; |
| fColumnLabel.fValue= column + 1; |
| return MessageFormat.format(fPositionLabelPattern, fPositionLabelPatternArguments); |
| |
| } catch (BadLocationException x) { |
| return ""; //$NON-NLS-1$ |
| } |
| } |
| |
| protected void clearStatusLine() { |
| IStatusLineManager manager = getViewSite().getActionBars().getStatusLineManager(); |
| manager.setErrorMessage(null); |
| manager.setMessage(null); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.IPerspectiveListener#perspectiveActivated(org.eclipse.ui.IWorkbenchPage, org.eclipse.ui.IPerspectiveDescriptor) |
| */ |
| public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {} |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.IPerspectiveListener#perspectiveChanged(org.eclipse.ui.IWorkbenchPage, org.eclipse.ui.IPerspectiveDescriptor, java.lang.String) |
| */ |
| public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, String changeId) { |
| if(changeId.equals(IWorkbenchPage.CHANGE_RESET)) { |
| setLastSashWeights(DEFAULT_SASH_WEIGHTS); |
| fSashForm.setWeights(DEFAULT_SASH_WEIGHTS); |
| } |
| } |
| } |