diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/modules/ModuleDetailPane.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/modules/ModuleDetailPane.java new file mode 100644 index 00000000000..2bac45e2e28 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/modules/ModuleDetailPane.java @@ -0,0 +1,557 @@ +/******************************************************************************* + * Copyright (c) 2006, 2007 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) + * Wind River Systems - adopted to use with Modules view + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.viewmodel.modules; + + +import java.util.concurrent.ExecutionException; + +import org.eclipse.cdt.debug.internal.ui.views.modules.ModulesMessages; +import org.eclipse.cdt.debug.ui.ICDebugUIConstants; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IModules; +import org.eclipse.dd.dsf.debug.service.IModules.IModuleDMContext; +import org.eclipse.dd.dsf.debug.service.IModules.IModuleDMData; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.debug.ui.viewmodel.numberformat.detail.TextViewerAction; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode; +import org.eclipse.debug.core.model.IDebugElement; +import org.eclipse.debug.internal.ui.DebugUIPlugin; +import org.eclipse.debug.internal.ui.IDebugHelpContextIds; +import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; +import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants; +import org.eclipse.debug.internal.ui.views.variables.details.AbstractDetailPane; +import org.eclipse.debug.internal.ui.views.variables.details.DetailMessages; +import org.eclipse.debug.ui.IDebugView; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.resource.JFaceResources; +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.ITextOperationTarget; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.FocusAdapter; +import org.eclipse.swt.events.FocusEvent; +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.IWorkbenchActionConstants; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.progress.WorkbenchJob; +import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds; + + +/** + * + */ +public class ModuleDetailPane extends AbstractDetailPane implements IAdaptable, IPropertyChangeListener { + + /** + * These are the IDs for the actions in the context menu + */ + protected static final String DETAIL_COPY_ACTION = ActionFactory.COPY.getId() + ".SourceDetailPane"; //$NON-NLS-1$ + protected static final String DETAIL_SELECT_ALL_ACTION = IDebugView.SELECT_ALL_ACTION + ".SourceDetailPane"; //$NON-NLS-1$ + + /** + * The ID, name and description of this pane are stored in constants so that the class + * does not have to be instantiated to access them. + */ + public static final String ID = "ModuleDetailPane"; //$NON-NLS-1$ + public static final String NAME = "Module Viewer"; //$NON-NLS-1$ + public static final String DESCRIPTION = "A detail pane that is based on a source viewer. Displays as text and has actions for assigning values, content assist and text modifications."; //$NON-NLS-1$ + + + /** + * The source viewer in which the computed string detail + * of selected modules will be displayed. + */ + private SourceViewer fSourceViewer; + public Control createControl(Composite parent) { + createSourceViewer(parent); + + if (isInView()){ + createViewSpecificComponents(); + createActions(); + DebugUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this); + JFaceResources.getFontRegistry().addListener(this); + } + return fSourceViewer.getControl(); + } + + private DetailJob fDetailJob = null; + public void display(IStructuredSelection selection) { + if (selection == null){ + clearSourceViewer(); + return; + } + + if (isInView()){ + fSourceViewer.setEditable(true); + } + + if (selection.isEmpty()){ + clearSourceViewer(); + return; + } + + Object firstElement = selection.getFirstElement(); + if (firstElement != null && firstElement instanceof IDebugElement) { + String modelID = ((IDebugElement)firstElement).getModelIdentifier(); + } + + synchronized (this) { + if (fDetailJob != null) { + fDetailJob.cancel(); + } + fDetailJob = new DetailJob(selection.getFirstElement()); + fDetailJob.schedule(); + } + + } + + /** + * Clears the source viewer, removes all text. + */ + protected void clearSourceViewer(){ + if (fDetailJob != null) { + fDetailJob.cancel(); + } + fDetailDocument.set(""); + fSourceViewer.setEditable(false); + } + + public void dispose() { + super.dispose(); + if (fDetailJob != null) fDetailJob.cancel(); + if (fSourceViewer != null && fSourceViewer.getControl() != null) fSourceViewer.getControl().dispose(); + + if (isInView()){ + DebugUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this); + JFaceResources.getFontRegistry().removeListener(this); + } + + } + public String getDescription() { + return DESCRIPTION; + } + public String getID() { + return ID; + } + public String getName() { + return NAME; + } + + public boolean setFocus() { + if (fSourceViewer != null){ + fSourceViewer.getTextWidget().setFocus(); + return true; + } + return false; + } + public Object getAdapter(Class adapter) { + if (ITextViewer.class.equals(adapter)) { + return fSourceViewer; + } + return null; + } + + public void propertyChange(PropertyChangeEvent event) { + String propertyName= event.getProperty(); + if (propertyName.equals(IInternalDebugUIConstants.DETAIL_PANE_FONT)) { + fSourceViewer.getTextWidget().setFont(JFaceResources.getFont(IInternalDebugUIConstants.DETAIL_PANE_FONT)); + } + } + + + /** + * Creates the source viewer in the given parent composite + * + * @param parent Parent composite to create the source viewer in + */ + private void createSourceViewer(Composite parent) { + + // Create & configure a SourceViewer + fSourceViewer = new SourceViewer(parent, null, SWT.V_SCROLL | SWT.H_SCROLL); + fSourceViewer.setDocument(getDetailDocument()); + fSourceViewer.getTextWidget().setFont(JFaceResources.getFont(IInternalDebugUIConstants.DETAIL_PANE_FONT)); + fSourceViewer.getTextWidget().setWordWrap(DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IDebugPreferenceConstants.PREF_DETAIL_PANE_WORD_WRAP)); + fSourceViewer.setEditable(false); + PlatformUI.getWorkbench().getHelpSystem().setHelp(fSourceViewer.getTextWidget(), IDebugHelpContextIds.DETAIL_PANE); + Control control = fSourceViewer.getControl(); + GridData gd = new GridData(GridData.FILL_BOTH); + control.setLayoutData(gd); + } + + /** + * Variables used to create the detailed information for a selection + */ + private IDocument fDetailDocument; + + /** + * Lazily instantiate and return a Document for the detail pane text viewer. + */ + protected IDocument getDetailDocument() { + if (fDetailDocument == null) { + fDetailDocument = new Document(); + } + return fDetailDocument; + } + + /** + * Creates listeners and other components that should only be added to the + * source viewer when this detail pane is inside a view. + */ + private void createViewSpecificComponents(){ + + // Add a document listener so actions get updated when the document changes + getDetailDocument().addDocumentListener(new IDocumentListener() { + public void documentAboutToBeChanged(DocumentEvent event) {} + public void documentChanged(DocumentEvent event) { + updateSelectionDependentActions(); + } + }); + + // Add the selection listener so selection dependent actions get updated. + fSourceViewer.getSelectionProvider().addSelectionChangedListener(new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + updateSelectionDependentActions(); + } + }); + + // Add a focus listener to update actions when details area gains focus + fSourceViewer.getControl().addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + + getViewSite().setSelectionProvider(fSourceViewer.getSelectionProvider()); + + setGlobalAction(IDebugView.SELECT_ALL_ACTION, getAction(DETAIL_SELECT_ALL_ACTION)); + setGlobalAction(IDebugView.COPY_ACTION, getAction(DETAIL_COPY_ACTION)); + + getViewSite().getActionBars().updateActionBars(); + } + + public void focusLost(FocusEvent e) { + + getViewSite().setSelectionProvider(null); + + setGlobalAction(IDebugView.SELECT_ALL_ACTION, null); + setGlobalAction(IDebugView.COPY_ACTION, null); + getViewSite().getActionBars().updateActionBars(); + + } + }); + + // Add a context menu to the detail area + createDetailContextMenu(fSourceViewer.getTextWidget()); + } + + /** + * Create the context menu particular to the detail pane. Note that anyone + * wishing to contribute an action to this menu must use + * ICDebugUIConstants.MODULES_VIEW_DETAIL_ID as the + * targetID 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); + + getViewSite().registerContextMenu(ICDebugUIConstants.MODULES_VIEW_DETAIL_ID, menuMgr, fSourceViewer.getSelectionProvider()); + + } + /** + * Adds items to the detail pane'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(ICDebugUIConstants.MODULES_GROUP)); + menu.add(new Separator()); + menu.add(getAction(DETAIL_COPY_ACTION)); + menu.add(getAction(DETAIL_SELECT_ALL_ACTION)); + menu.add(new Separator()); + menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + + } + /** + * Creates the actions to add to the context menu + */ + private void createActions() { + TextViewerAction textAction= new TextViewerAction(fSourceViewer, ITextOperationTarget.SELECT_ALL); + textAction.configureAction(DetailMessages.DefaultDetailPane_Select__All_5, "", ""); //$NON-NLS-1$ //$NON-NLS-2$ + textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.SELECT_ALL); + PlatformUI.getWorkbench().getHelpSystem().setHelp(textAction, IDebugHelpContextIds.DETAIL_PANE_SELECT_ALL_ACTION); + setAction(DETAIL_SELECT_ALL_ACTION, textAction); + + textAction= new TextViewerAction(fSourceViewer, ITextOperationTarget.COPY); + textAction.configureAction(DetailMessages.DefaultDetailPane__Copy_8, "", ""); //$NON-NLS-1$ //$NON-NLS-2$ + textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY); + PlatformUI.getWorkbench().getHelpSystem().setHelp(textAction, IDebugHelpContextIds.DETAIL_PANE_COPY_ACTION); + setAction(DETAIL_COPY_ACTION, textAction); + + setSelectionDependantAction(DETAIL_COPY_ACTION); + + updateSelectionDependentActions(); + } + + + /** + * Job to compute the details for a selection + */ + class DetailJob extends Job { + + private Object fElement; + // whether a result was collected + private IProgressMonitor fMonitor; + + public DetailJob(Object element) { + super("compute module details"); //$NON-NLS-1$ + setSystem(true); + fElement = element; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + protected IStatus run(IProgressMonitor monitor) { + fMonitor = monitor; + /* + * Make sure this is an element we want to deal with. + */ +// if ( fElement instanceof DMVMContext) { +// IModules service = null; +// IModuleDMContext dmc = null ; +// +// IModuleDMContext modDmc = DMContexts.getAncestorOfType(((DMVMContext) fElement).getDMC(), IModuleDMContext.class); +// DsfServicesTracker tracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), ((DMVMContext) fElement).getDMC().getSessionId()); +// +// if ( modDmc != null ) { +// dmc = modDmc ; +// service = tracker.getService(IModules.class); +// } +// +// /* +// * If the desired Data Model Context is null then we are not going to +// * process this data. +// */ +// if ( dmc == null ) return Status.OK_STATUS; +// +// final DataRequestMonitor modData = +// new DataRequestMonitor(service.getSession().getExecutor(), null) { +// @Override +// protected void handleOK() { +// detailComputed(getModuleDetail(getData())); +// } +// }; +// service.getModuleData(modDmc, modData); +// } + IModuleDMContext dmc = null; + if (fElement instanceof AbstractDMVMLayoutNode.DMVMContext) { + IDMContext vmcdmc = ((AbstractDMVMLayoutNode.DMVMContext)fElement).getDMC(); + dmc = DMContexts.getAncestorOfType(vmcdmc, IModuleDMContext.class); + } + + if (dmc == null) return null; + DsfSession session = DsfSession.getSession(dmc.getSessionId()); + if (session == null) return null; + + /* + * Create the query to write the value to the service. Note: no need to + * guard agains RejectedExecutionException, because + * DsfSession.getSession() above would only return an active session. + */ + GetModuleDetailsQuery query = new GetModuleDetailsQuery(dmc); + session.getExecutor().execute(query); + + /* + * Now we have the data, go and get it. Since the call is completed now + * the ".get()" will not suspend it will immediately return with the + * data. + */ + try { + detailComputed(getModuleDetail((IModuleDMData) query.get())); + } catch (InterruptedException e) { + assert false; + return null; + } catch (ExecutionException e) { + return null; + } + return Status.OK_STATUS; + } + + /** + * Set the module details in the detail pane view + * @param result + */ + private void detailComputed(final String result) { + if (!fMonitor.isCanceled()) { + WorkbenchJob setDetail = new WorkbenchJob("set details") { //$NON-NLS-1$ + @Override + public IStatus runInUIThread(IProgressMonitor monitor) { + if (!fMonitor.isCanceled()) { + getDetailDocument().set(result); + } + return Status.OK_STATUS; + } + }; + setDetail.setSystem(true); + setDetail.schedule(); + } + } + + } + + /** + * To get the details of the given module selected in Modules View + * @param module + * @return + */ + private String getModuleDetail( IModuleDMData module ) { + StringBuffer sb = new StringBuffer(); + + // Type + String type = null; +// switch( module.getType() ) { +// case ICModule.EXECUTABLE: +// type = ModulesMessages.getString( "ModulesView.1" ); //$NON-NLS-1$ +// break; +// case ICModule.SHARED_LIBRARY: +// type = ModulesMessages.getString( "ModulesView.2" ); //$NON-NLS-1$ +// break; +// } + type = ModulesMessages.getString( "ModulesView.2" ); //$NON-NLS-1$ + if ( type != null ) { + sb.append( ModulesMessages.getString( "ModulesView.3" ) ); //$NON-NLS-1$ + sb.append( type ); + sb.append( '\n' ); + } + + // Symbols flag + sb.append( ModulesMessages.getString( "ModulesView.4" ) ); //$NON-NLS-1$ + sb.append( ( module.isSymbolsLoaded()) ? ModulesMessages.getString( "ModulesView.5" ) : ModulesMessages.getString( "ModulesView.6" ) ); //$NON-NLS-1$ //$NON-NLS-2$ + sb.append( '\n' ); + + // Symbols file + sb.append( ModulesMessages.getString( "ModulesView.7" ) ); //$NON-NLS-1$ + sb.append( module.getFile()); + sb.append( '\n' ); + // Base address + String baseAddress = module.getBaseAddress(); + sb.append( ModulesMessages.getString( "ModulesView.9" ) ); //$NON-NLS-1$ + sb.append( baseAddress ); +// sb.append( baseAddress.toHexAddressString() ); + sb.append( '\n' ); +// } +// + // Size + long size = module.getSize(); + if ( size > 0 ) { + sb.append( ModulesMessages.getString( "ModulesView.10" ) ); //$NON-NLS-1$ + sb.append( size ); + sb.append( '\n' ); + } + + return sb.toString(); + } + + + public class GetModuleDetailsQuery extends Query { + + private IModuleDMContext fDmc; + + public GetModuleDetailsQuery(IModuleDMContext dmc) { + super(); + fDmc = dmc; + } + + @Override + protected void execute(final DataRequestMonitor rm) { + /* + * We're in another dispatch, so we must guard against executor + * shutdown again. + */ + final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); + if (session == null) { + cancel(false); + return; + } + + /* + * Guard against a disposed service + */ + DsfServicesTracker tracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), fDmc.getSessionId()); + IModules service = tracker.getService(IModules.class); + if (service == null) { + rm .setStatus(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + service.getModuleData(fDmc, new DataRequestMonitor( session.getExecutor(), rm) { + @Override + protected void handleCompleted() { + /* + * We're in another dispatch, so we must guard against executor shutdown again. + */ + if (!DsfSession.isSessionActive(session.getId())) { + GetModuleDetailsQuery.this.cancel(false); + return; + } + super.handleCompleted(); + } + + @Override + protected void handleOK() { + /* + * All good set return value. + */ + rm.setData(getData()); + rm.done(); + } + }); + } + } +} + diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/modules/ModuleDetailPaneFactory.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/modules/ModuleDetailPaneFactory.java new file mode 100644 index 00000000000..311d9c858bc --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/viewmodel/modules/ModuleDetailPaneFactory.java @@ -0,0 +1,40 @@ +package org.eclipse.dd.dsf.debug.ui.viewmodel.modules; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.debug.ui.IDetailPane; +import org.eclipse.debug.ui.IDetailPaneFactory; +import org.eclipse.jface.viewers.IStructuredSelection; + +public class ModuleDetailPaneFactory implements IDetailPaneFactory { + public static final String MODULE_DETAIL_PANE_ID = ModuleDetailPane.ID; + public IDetailPane createDetailPane(String paneID) { + return new ModuleDetailPane(); + } + + public String getDefaultDetailPane(IStructuredSelection selection) { + return null; + } + + public String getDetailPaneDescription(String paneID) { + if (paneID.equals(ModuleDetailPane.ID)){ + return ModuleDetailPane.DESCRIPTION; + } + return null; + } + + public String getDetailPaneName(String paneID) { + if (paneID.equals(ModuleDetailPane.ID)){ + return ModuleDetailPane.NAME; + } + return null; + } + + public Set getDetailPaneTypes(IStructuredSelection selection) { + Set possibleIDs = new HashSet(1); + possibleIDs.add(ModuleDetailPane.ID); + return possibleIDs; + } + +}