1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 22:22:11 +02:00

Bug 337881: [Memory Browser] Persist the Go To Address history in the launch configuration. (Changes resulting from code review.)

This commit is contained in:
John Cortell 2011-03-04 16:45:30 +00:00
parent 38f65aca63
commit d71b3a2ce7
4 changed files with 192 additions and 101 deletions

View file

@ -27,7 +27,7 @@ public class ClearExpressionsListAction implements IViewActionDelegate {
public void run(IAction action) {
if ( fView instanceof MemoryBrowser ) {
MemoryBrowser browser = (MemoryBrowser) fView;
browser.clearExpressionsFromList(null);
browser.clearExpressionHistoryForActiveTab();
}
}

View file

@ -14,10 +14,9 @@ package org.eclipse.cdt.debug.ui.memory.memorybrowser;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.cdt.debug.core.model.provisional.ITargetLabelProvider;
import org.eclipse.cdt.debug.core.model.provisional.IRecurringDebugContext;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
@ -43,8 +42,19 @@ import org.eclipse.ui.PlatformUI;
public class GoToAddressBarWidget {
private static String SEPARATOR = "<sperator>";
private static String UNKNOWN_TARGET_NAME = "Unknown";
/**
* Character sequence that is unlikely to appear naturally in a recurring
* debug context ID or memory space ID
*/
private static String SEPARATOR = "<seperator>";
/**
* At a minimum, the expression history is kept on a per launch
* configuration basis. Where debug contexts (processes, in practice) can
* provide a recurring ID, we further divide the history by those IDs. This
* constant is used when no recurring context ID is available.
*/
private static String UNKNOWN_CONTEXT_ID = "Unknown";
private Combo fExpression;
private ControlDecoration fEmptyExpression;
private ControlDecoration fWrongExpression;
@ -87,10 +97,12 @@ public class GoToAddressBarWidget {
return fComposite;
}
/** The launch configuration attribute prefix used to persist expression history */
private final static String SAVED_EXPRESSIONS = "saved_expressions"; //$NON-NLS-1$
private final static int MAX_SAVED_EXPRESSIONS = 15 ;
private void saveExpression( String memorySpace, Object context, String expr ) {
private void addExpressionToHistoryPersistence( Object context, String expr, String memorySpace ) {
/*
* Get the saved expressions if any.
*
@ -104,7 +116,7 @@ public class GoToAddressBarWidget {
return;
}
String targetName = getTargetName(context);
String contextID = getRecurringContextID(context);
ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
String currentExpressions = "";
@ -112,7 +124,7 @@ public class GoToAddressBarWidget {
try {
ILaunchConfigurationWorkingCopy wc = launchConfiguration.getWorkingCopy();
if (wc != null) {
currentExpressions = wc.getAttribute(getSaveExpressionKey(targetName,memorySpace), "");
currentExpressions = wc.getAttribute(getSaveExpressionKey(contextID,memorySpace), "");
StringTokenizer st = new StringTokenizer(currentExpressions, ","); //$NON-NLS-1$
/*
@ -141,7 +153,7 @@ public class GoToAddressBarWidget {
}
currentExpressions += list.get(idx);
}
wc.setAttribute(getSaveExpressionKey(targetName,memorySpace), currentExpressions);
wc.setAttribute(getSaveExpressionKey(contextID,memorySpace), currentExpressions);
wc.doSave();
}
}
@ -151,47 +163,67 @@ public class GoToAddressBarWidget {
}
}
public void deleteExpressions(Object context) {
if(context == null)
{
/**
* Clear all expression history persisted in the launch configuration that
* created the given debug context
*
* @param context
* the debug context. In practice, this will always be a process
* context
*/
public void clearExpressionHistoryPersistence(Object context) {
if(context == null) {
return;
}
ILaunch launch = getLaunch(context);
if(launch == null)
{
if(launch == null) {
return;
}
// We maintain history for every process this launch configuration has
// launched. And where memory spaces are involved, each space has its
// own history. Here we just wipe out the persistence of all processes
// and memory spaces stored in the launch configuration that created the
// given processes.
ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
if (launchConfiguration != null) {
try {
ILaunchConfigurationWorkingCopy wc = launchConfiguration.getWorkingCopy();
if (wc != null) {
@SuppressWarnings("unchecked")
Map<String,Object> attributes = (Map<String,Object>)wc.getAttributes();
if (attributes != null && !attributes.isEmpty()) {
Iterator<String> iterator = attributes.keySet().iterator();
while(iterator.hasNext())
{
String key = iterator.next();
if(key.startsWith(SAVED_EXPRESSIONS))
{
wc.removeAttribute(key);
}
Map<?,?> attributes = wc.getAttributes();
Iterator<?> iterator = attributes.keySet().iterator();
while (iterator.hasNext()) {
String key = (String)iterator.next();
if (key.startsWith(SAVED_EXPRESSIONS)) {
wc.removeAttribute(key);
}
wc.doSave();
}
}
wc.doSave();
}
}
catch(CoreException e) {
// Some unexpected snag working with the launch configuration
MemoryBrowserPlugin.log(e);
}
}
}
private String[] getSavedExpressions(String memorySpace, Object context) {
/**
* Get the expression history persisted in the launch configuration for the
* given debug context and memory space (where applicable)
*
* @param context
* the debug context. In practice, this will always be a process
* context
* @param memorySpace
* memory space ID or null if not applicable
* @return a list of expressions, or empty collection if no history
* available (never null)
* @throws CoreException
* if there's a problem working with the launch configuration
*/
private String[] getSavedExpressions(Object context, String memorySpace) throws CoreException {
/*
* Get the saved expressions if any.
*
@ -201,19 +233,14 @@ public class GoToAddressBarWidget {
*/
ILaunch launch = getLaunch(context);
if(launch == null)
{
if(launch == null) {
return new String[0];
}
ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
String expressions = "";
if (launchConfiguration != null) {
try {
expressions = launchConfiguration.getAttribute(getSaveExpressionKey(getTargetName(context),memorySpace), "");
}
catch(CoreException e) {
}
expressions = launchConfiguration.getAttribute(getSaveExpressionKey(getRecurringContextID(context),memorySpace), "");
}
StringTokenizer st = new StringTokenizer(expressions, ","); //$NON-NLS-1$
@ -221,30 +248,43 @@ public class GoToAddressBarWidget {
* Parse through the list creating an ordered array for display.
*/
ArrayList<String> list = new ArrayList<String>();
while(st.hasMoreElements())
{
String expr = (String) st.nextElement();
list.add(expr);
while(st.hasMoreElements()) {
list.add(st.nextToken());
}
return list.toArray(new String[list.size()]);
}
public void loadSavedExpressions(String memorySpace, Object context)
/**
* Populate the expression history combobox based on the history persisted
* in the launch configuration for the given context and memory space (where
* applicable)
*
* @param context
* the debug context. In practice, this will always be a process
* context
* @param memorySpace
* memory space ID; null if not applicable
*/
public void loadSavedExpressions(Object context, String memorySpace)
{
String[] expressions = getSavedExpressions(memorySpace, context);
String text = fExpression.getText();
fExpression.removeAll();
for(int idx=0; idx < expressions.length; idx++)
{
fExpression.add(expressions[idx]);
}
if(text != null)
{
fExpression.setText(text);
try {
String[] expressions = getSavedExpressions(context, memorySpace);
String currentExpression = fExpression.getText();
fExpression.removeAll();
for (String expression : expressions) {
fExpression.add(expression);
}
if (currentExpression != null) {
fExpression.setText(currentExpression);
}
} catch (CoreException e) {
// Unexpected snag dealing with launch configuration
MemoryBrowserPlugin.log(e);
}
}
public void addExpressionToList( String memorySpace, Object context, String expr ) {
public void addExpressionToHistory(Object context, String expr, String memorySpace) {
/*
* Make sure it does not already exist, we do not want to show duplicates.
*/
@ -257,7 +297,7 @@ public class GoToAddressBarWidget {
}
/*
* Add the new expression to the dropdown.
* Add the new expression to the combobox
*/
fExpression.add(expr);
@ -265,20 +305,28 @@ public class GoToAddressBarWidget {
/*
* Add it to the persistense database.
*/
saveExpression(memorySpace, context, expr);
addExpressionToHistoryPersistence(context, expr, memorySpace);
}
public void clearExpressionsFromList(String[] memorySpaces, Object context) {
/**
* Clears the history of expressions for the given debug context, both in
* the GUI and the persistence data
*
* @param context
* the debug context. In practice, this will always be a process
* context.
*/
public void clearExpressionHistory(Object context) {
/*
* Clean up the combo list.
* Clear the combobox
*/
fExpression.removeAll();
fExpression.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
/*
* Clean out the expression persistense.
* Clear the history persisted in the launch configuration
*/
deleteExpressions(context);
clearExpressionHistoryPersistence(context);
/*
* Make sure the status image indicator shows OK.
@ -407,38 +455,52 @@ public class GoToAddressBarWidget {
}
private String getTargetName(Object context)
/**
* Get the identifier for the given context if it is a recurring one. See
* {@link IRecurringDebugContext}
*
* @param context
* the debug context
* @return the ID or UNKNOWN_CONTEXT_ID if the context is non-recurring or
* can't provide us its ID
*/
private String getRecurringContextID(Object context)
{
String targetName = null;
if(context instanceof IAdaptable)
{
String id = UNKNOWN_CONTEXT_ID;
if (context instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) context;
ITargetLabelProvider labelProvider = (ITargetLabelProvider)adaptable.getAdapter(ITargetLabelProvider.class);
if(labelProvider != null)
{
try
{
targetName = labelProvider.getLabel();
IRecurringDebugContext recurringDebugContext = (IRecurringDebugContext)adaptable.getAdapter(IRecurringDebugContext.class);
if (recurringDebugContext != null) {
try {
id = recurringDebugContext.getContextID();
}
catch(DebugException e)
{
catch(DebugException e) {
// If the context can't give us the ID, just treat it as a
// non-recurring context
}
}
}
if(targetName == null || targetName.trim().length() == 0)
{
targetName = UNKNOWN_TARGET_NAME;
}
return targetName;
return id;
}
private String getSaveExpressionKey(String targetName, String memorySpace)
{
String key = SAVED_EXPRESSIONS + SEPARATOR + targetName.trim();
if(memorySpace != null && memorySpace.trim().length() > 0)
{
key += SEPARATOR + memorySpace.trim();
/**
* Get a key that we can use to persist the expression history for the given
* debug context and memory space (where applicable). The key is used within
* the scope of a launch configuration.
*
* @param contextID
* a recurring debug context ID; see
* {@link IRecurringDebugContext}
* @param memorySpace
* a memory space identifier, or null if not applicable
* @return they key which will be used to persist the expression history
*/
private String getSaveExpressionKey(String contextID, String memorySpace) {
assert contextID.length() > 0;
String key = SAVED_EXPRESSIONS + SEPARATOR + contextID;
if (memorySpace != null && memorySpace.length() > 0) {
key += SEPARATOR + memorySpace;
}
return key;
}

View file

@ -23,7 +23,6 @@ import java.util.Map;
import org.eclipse.cdt.debug.core.model.provisional.IMemoryRenderingViewportProvider;
import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlockRetrieval;
import org.eclipse.cdt.debug.core.model.provisional.ITargetLabelProvider;
import org.eclipse.cdt.debug.internal.core.CRequest;
import org.eclipse.cdt.debug.ui.provisional.IRepositionableMemoryRendering2;
import org.eclipse.core.runtime.CoreException;
@ -84,6 +83,7 @@ import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
@ -241,36 +241,31 @@ public class MemoryBrowser extends ViewPart implements IDebugContextListener, IM
fGotoAddressBar = new GoToAddressBarWidget();
fGotoAddressBarControl = fGotoAddressBar.createControl(fMainComposite);
fGotoAddressBar.getButton(IDialogConstants.OK_ID).addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {}
fGotoAddressBar.getButton(IDialogConstants.OK_ID).addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
performGo(false);
}
});
fGotoAddressBar.getButton(GoToAddressBarWidget.ID_GO_NEW_TAB).addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {}
fGotoAddressBar.getButton(GoToAddressBarWidget.ID_GO_NEW_TAB).addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
performGo(true);
}
});
fGotoAddressBar.getExpressionWidget().addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {}
fGotoAddressBar.getExpressionWidget().addSelectionListener(new SelectionAdapter() {
public void widgetDefaultSelected(SelectionEvent e) {
performGo(false);
}
});
fGotoMemorySpaceControl.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {}
fGotoMemorySpaceControl.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if(fGotoMemorySpaceControl.getItemCount() >= 2)
{
if(fGotoMemorySpaceControl.getItemCount() >= 2) {
final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl;
if (activeFolder != null) {
final Object context = activeFolder.getData(KEY_CONTEXT);
fGotoAddressBar.loadSavedExpressions(fGotoMemorySpaceControl.getText(), context);
fGotoAddressBar.loadSavedExpressions(context, fGotoMemorySpaceControl.getText());
}
}
}
@ -336,11 +331,14 @@ public class MemoryBrowser extends ViewPart implements IDebugContextListener, IM
return false;
}
public void clearExpressionsFromList(String memorySpace) {
/**
* Clears the expression history for the active tab
*/
public void clearExpressionHistoryForActiveTab() {
final CTabFolder activeFolder = (CTabFolder) fStackLayout.topControl;
if (activeFolder != null) {
final Object context = activeFolder.getData(KEY_CONTEXT);
fGotoAddressBar.clearExpressionsFromList(fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getItems() : new String[]{""}, context);
fGotoAddressBar.clearExpressionHistory(context);
}
}
@ -422,7 +420,7 @@ public class MemoryBrowser extends ViewPart implements IDebugContextListener, IM
if (activeFolder != null) {
context = activeFolder.getData(KEY_CONTEXT);
}
fGotoAddressBar.addExpressionToList(memorySpace, context, expression);
fGotoAddressBar.addExpressionToHistory(context, expression, memorySpace);
performGo(inNewTab, expression, memorySpace);
}
}
@ -909,7 +907,7 @@ public class MemoryBrowser extends ViewPart implements IDebugContextListener, IM
CTabItem tabItem = (CTabItem)e.item;
updateExpression(tabItem);
updateMemorySpaceControlSelection(tabItem);
fGotoAddressBar.loadSavedExpressions(fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getText() : "", context);
fGotoAddressBar.loadSavedExpressions(context, fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getText() : null);
getSite().getSelectionProvider().setSelection(new StructuredSelection(tabItem.getData(KEY_RENDERING)));
handleTabActivated(tabItem);
}
@ -920,7 +918,7 @@ public class MemoryBrowser extends ViewPart implements IDebugContextListener, IM
fStackLayout.topControl = tabFolder;
// set empty initial expression
fGotoAddressBar.setExpressionText(""); //$NON-NLS-1$
fGotoAddressBar.loadSavedExpressions(fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getText() : "", context);
fGotoAddressBar.loadSavedExpressions(context, fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getText() : null);
}
// update debug context to the new selection
tabFolder.setData(KEY_CONTEXT, context);
@ -955,7 +953,7 @@ public class MemoryBrowser extends ViewPart implements IDebugContextListener, IM
updateExpression(activeFolder.getSelection());
updateMemorySpaceControlSelection(activeFolder.getSelection());
fGotoAddressBar.loadSavedExpressions(fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getText() : "", context);
fGotoAddressBar.loadSavedExpressions(context, fGotoMemorySpaceControl.isVisible() ? fGotoMemorySpaceControl.getText() : null);
fStackLayout.topControl.getParent().layout(true);
}

View file

@ -11,6 +11,9 @@
package org.eclipse.cdt.debug.ui.memory.memorybrowser;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
@ -69,4 +72,32 @@ public class MemoryBrowserPlugin extends AbstractUIPlugin {
public static ImageDescriptor getImageDescriptor(String path) {
return imageDescriptorFromPlugin(PLUGIN_ID, path);
}
/**
* Logs the specified status with this plug-in's log.
*
* @param status status to log
*/
public static void log(IStatus status) {
getDefault().getLog().log(status);
}
/**
* Logs the specified throwable with this plug-in's log.
*
* @param t throwable to log
*/
public static void log(Throwable t) {
log(newErrorStatus("Error logged from Debug UI: ", t)); //$NON-NLS-1$
}
/**
* Returns a new error status for this plug-in with the given message
* @param message the message to be included in the status
* @param exception the exception to be included in the status or <code>null</code> if none
* @return a new error status
*/
public static IStatus newErrorStatus(String message, Throwable exception) {
return new Status(IStatus.ERROR, PLUGIN_ID, IDebugUIConstants.INTERNAL_ERROR, message, exception);
}
}