diff options
8 files changed, 522 insertions, 21 deletions
diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java index 19840592824..0338a2376d8 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java @@ -209,20 +209,32 @@ public class CDebugUtils { * Serializes a XML document into a string - encoded in UTF8 format, with platform line separators. * * @param doc document to serialize + * @param indent if the xml text should be indented. + * * @return the document as a string */ - public static String serializeDocument( Document doc ) throws IOException, TransformerException { + public static String serializeDocument( Document doc, boolean indent ) throws IOException, TransformerException { ByteArrayOutputStream s = new ByteArrayOutputStream(); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); transformer.setOutputProperty( OutputKeys.METHOD, "xml" ); //$NON-NLS-1$ - transformer.setOutputProperty( OutputKeys.INDENT, "yes" ); //$NON-NLS-1$ + transformer.setOutputProperty( OutputKeys.INDENT, indent ? "yes" : "no" ); //$NON-NLS-1$ DOMSource source = new DOMSource( doc ); StreamResult outputTarget = new StreamResult( s ); transformer.transform( source, outputTarget ); return s.toString( "UTF8" ); //$NON-NLS-1$ } + /** + * Serializes a XML document into a string - encoded in UTF8 format, with platform line separators. + * + * @param doc document to serialize + * @return the document as a string + */ + public static String serializeDocument( Document doc ) throws IOException, TransformerException { + return serializeDocument(doc, true); + } + public static Number getFloatingPointValue( ICValue value ) { if ( value instanceof CFloatingPointValue ) { try { diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java index d75f9160a80..c7b5de6b93b 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java @@ -174,6 +174,12 @@ public interface ICDTLaunchConfigurationConstants { * memento. */ public static final String ATTR_DEBUGGER_GLOBAL_VARIABLES = CDT_LAUNCH_ID + ".GLOBAL_VARIABLES"; //$NON-NLS-1$ + + /** + * Launch configuration attribute key. The value is a format list' + * memento. + */ + public static final String ATTR_DEBUGGER_FORMAT = CDT_LAUNCH_ID + ".FORMAT"; //$NON-NLS-1$ /** * Launch configuration attribute key. The value is a memory blocks' memento. diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/CVariableFormat.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/CVariableFormat.java index 553ea295687..12f8dc7d592 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/CVariableFormat.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/CVariableFormat.java @@ -16,35 +16,41 @@ package org.eclipse.cdt.debug.core.model; public class CVariableFormat { private final String fName; + private final int fNum; - private CVariableFormat( String name ) { + private CVariableFormat( String name, int num ) { this.fName = name; + this.fNum= num; } public String toString() { return this.fName; } + + public int getFormatNumber() { + return this.fNum; + } public static CVariableFormat getFormat( int code ) { - switch( code ) { - case 0: - return NATURAL; - case 1: - return DECIMAL; - case 2: - return BINARY; - case 3: - return OCTAL; - case 4: - return HEXADECIMAL; - default: - return NATURAL; + if ( code == NATURAL.getFormatNumber() ) { + return NATURAL; + } else if ( code == DECIMAL.getFormatNumber() ) { + return DECIMAL; + } else if ( code == BINARY.getFormatNumber() ) { + return BINARY; + } else if ( code == OCTAL.getFormatNumber() ) { + return OCTAL; + } else if ( code == HEXADECIMAL.getFormatNumber() ) { + return HEXADECIMAL; + } else { + // unexpected value, mapping to NATURAL + return NATURAL; } } - public static final CVariableFormat NATURAL = new CVariableFormat( "natural" ); //$NON-NLS-1$ - public static final CVariableFormat DECIMAL = new CVariableFormat( "decimal" ); //$NON-NLS-1$ - public static final CVariableFormat BINARY = new CVariableFormat( "binary" ); //$NON-NLS-1$ - public static final CVariableFormat OCTAL = new CVariableFormat( "octal" ); //$NON-NLS-1$ - public static final CVariableFormat HEXADECIMAL = new CVariableFormat( "hexadecimal" ); //$NON-NLS-1$ + public static final CVariableFormat NATURAL = new CVariableFormat( "natural", 0 ); //$NON-NLS-1$ + public static final CVariableFormat DECIMAL = new CVariableFormat( "decimal", 1 ); //$NON-NLS-1$ + public static final CVariableFormat BINARY = new CVariableFormat( "binary", 2 ); //$NON-NLS-1$ + public static final CVariableFormat OCTAL = new CVariableFormat( "octal", 3 ); //$NON-NLS-1$ + public static final CVariableFormat HEXADECIMAL = new CVariableFormat( "hexadecimal", 4 ); //$NON-NLS-1$ } diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CSettingsManager.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CSettingsManager.java new file mode 100644 index 00000000000..96ee541ef12 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CSettingsManager.java @@ -0,0 +1,267 @@ +/******************************************************************************* + * Copyright (c) 2007 Freescale Semiconductor 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: + * Freescale Semiconductor - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.core; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.eclipse.cdt.debug.core.CDebugUtils; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.debug.internal.core.model.CDebugTarget; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.core.model.IDebugTarget; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Settings manager + * + * The settings manager stores a set of settings, + * (key/value) pairs in the launch configuration so they exist across debug sessions. + * + * All active settings are stored together in a single configuration entry + * (ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_FORMAT). + * + * Every setting is identified by a string identifier. That string identifier can be used to + * store an additional setting, to remove an exiting one or to retrieve a previously stored setting. + * + * The setting value consists of a String. + * + * Settings fade out automatically so clients do not necessarily need to delete old settings. This makes it + * possible to build the string identifiers with names out of the user application, like function names or + * variable names, without the danger of a constantly growing launch configuration. + * However it also causes that the settings manager must only be used for configurations and customizations for which + * always reasonable defaults exist. + * + * As cleanup policy the settings manager only keeps a certain number of settings and drops the + * least recently used one when more settings are added. The least recently used order is maintained + * across debug sessions. + * + */ + +public class CSettingsManager { + + /** + * the name of the XML node for the list + */ + private static final String CONTENT_LIST = "contentList"; //$NON-NLS-1$ + + /** + * the name of the XML node for every format entry + */ + private static final String CONTENT = "content"; //$NON-NLS-1$ + + /** + * the attribute name used to identify the object to store the content for. + */ + private static final String ATTR_CONTENT_ID = "id"; //$NON-NLS-1$ + + /** + * the attribute name of the actual content + */ + private static final String ATTR_CONTENT_VALUE = "val"; //$NON-NLS-1$ + + /** + * Number defining how many settings are stored. + * Whenever an additional setting is added when there are already MAX_USED_COUNT settings, the + * least recently used setting is dropped. + * + * The actual value is chosen to be high enough for normal use cases, but still low enough to avoid that the launch configuration + * gets arbitrarily large + */ + private static int MAX_ELEMENT_COUNT = 100; + + /** + * the map used to actually store the format information + * as key String are used, values are of type String too. + * + * The map automatically is limited to MAX_ELEMENT_COUNT + * elements, dropping the least recently used one + * when more elements are added. + */ + private Map fContentMap = new LinkedHashMap(MAX_ELEMENT_COUNT, 0.75f, true) { + private static final long serialVersionUID = 1; + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > MAX_ELEMENT_COUNT; + } + }; + + /** + * the debug target we store the values for + */ + private CDebugTarget fDebugTarget; + + /** + * Store the value for the given id. + * @param id used to identify the information. Different objects/topics should use different identifiers. + * @param value content to be stored + */ + public synchronized void putValue( String id, String value ) { + fContentMap.put(id, value); + } + /** + * remove the stored format for the given id. + * @param id used to identify the formatting information. Different objects/topics should use different identifiers. + */ + public synchronized void removeValue( String id ) { + fContentMap.remove( id ); + } + + /** Retrieve the value for the given id. + * @param id used to identify the formatting information. Different objects/topics should use different identifiers. + * @return returns the entry information for the given id, or null if no such information is available. + */ + public synchronized String getValue( String id ) { + String entry= (String) fContentMap.get( id ); + return entry; + } + + /** constructor. + * @param debugTarget + */ + public CSettingsManager( CDebugTarget debugTarget ) { + fDebugTarget = debugTarget; + initialize(); + } + + /** get the string format of the current content. + * Only stores entries which have been used in the last MAX_USED_COUNT debug sessions. + * @return + */ + private String getMemento() { + Document document = null; + try { + document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + Element node = document.createElement( CONTENT_LIST ); + document.appendChild( node ); + Set entrySet = fContentMap.entrySet(); + Iterator it = entrySet.iterator(); + while ( it.hasNext() ) { + Map.Entry entry= (Map.Entry) it.next(); + String id= (String)entry.getKey(); + String value= (String)entry.getValue(); + Element child = document.createElement( CONTENT ); + child.setAttribute( ATTR_CONTENT_ID, id ); + child.setAttribute( ATTR_CONTENT_VALUE, value ); + node.appendChild( child ); + } + return CDebugUtils.serializeDocument( document, false ); + } + catch( ParserConfigurationException e ) { + DebugPlugin.log( e ); + } + catch( IOException e ) { + DebugPlugin.log( e ); + } + catch( TransformerException e ) { + DebugPlugin.log( e ); + } + return null; + } + + /** set the current state to the one given by the memento. + * @param memento a string representation of the state to be loaded. + * @throws CoreException + */ + private void initializeFromMemento( String memento ) throws CoreException { + try { + fContentMap.clear(); + DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + StringReader reader = new StringReader( memento ); + InputSource source = new InputSource( reader ); + Element root = parser.parse( source ).getDocumentElement(); + if ( root.getNodeName().equalsIgnoreCase( CONTENT_LIST ) ) { + NodeList list = root.getChildNodes(); + int i = list.getLength() - 1; // backwards to keep least recent access order. + for( ; i >= 0; i-- ) { + Node node = list.item( i ); + short type = node.getNodeType(); + if ( type == Node.ELEMENT_NODE ) { + Element elem = (Element)node; + if ( elem.getNodeName().equalsIgnoreCase( CONTENT ) ) { + String id = elem.getAttribute( ATTR_CONTENT_ID ); + String value= elem.getAttribute( ATTR_CONTENT_VALUE ); + if ( id == null || id.length() == 0 ) { + DebugPlugin.logMessage( "unexpected entry in CSettingsManager.initializeFromMemento", null ); //$NON-NLS-1$ + continue; + } + putValue( id, value ); + } + } + } + return; + } + DebugPlugin.logMessage( "unexpected content", null ); //$NON-NLS-1$ + } + catch( ParserConfigurationException e ) { + DebugPlugin.log( e ); + } + catch( SAXException e ) { + DebugPlugin.log( e ); + } + catch( IOException e ) { + DebugPlugin.log( e ); + } + } + + /** + * read the stored format from the launch configuration + */ + private void initialize() { + ILaunchConfiguration config = getDebugTarget().getLaunch().getLaunchConfiguration(); + try { + String memento = config.getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_FORMAT, "" ); //$NON-NLS-1$ + if ( memento != null && memento.trim().length() != 0 ) + initializeFromMemento( memento ); + } + catch( CoreException e ) { + DebugPlugin.log( e ); + } + } + + /** + * store the current content in the launch configuration. + */ + public synchronized void save() { + ILaunchConfiguration config = getDebugTarget().getLaunch().getLaunchConfiguration(); + try { + ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy(); + wc.setAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_FORMAT, getMemento() ); + wc.doSave(); + } + catch( CoreException e ) { + DebugPlugin.log( e ); + } + } + + /** + * accessor to the debug target + */ + IDebugTarget getDebugTarget() { + return fDebugTarget; + } +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CDebugTarget.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CDebugTarget.java index 81ad1d14d6a..5ba6634c0a1 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CDebugTarget.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CDebugTarget.java @@ -85,6 +85,7 @@ import org.eclipse.cdt.debug.core.model.IRegisterDescriptor; import org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocator; import org.eclipse.cdt.debug.core.sourcelookup.ISourceLookupChangeListener; import org.eclipse.cdt.debug.internal.core.CBreakpointManager; +import org.eclipse.cdt.debug.internal.core.CSettingsManager; import org.eclipse.cdt.debug.internal.core.CGlobalVariableManager; import org.eclipse.cdt.debug.internal.core.CMemoryBlockRetrievalExtension; import org.eclipse.cdt.debug.internal.core.CRegisterManager; @@ -198,6 +199,11 @@ public class CDebugTarget extends CDebugElement implements ICDebugTarget, ICDIEv private CGlobalVariableManager fGlobalVariableManager; /** + * container for Default format information + */ + private CSettingsManager fFormatManager; + + /** * The executable binary file associated with this target. */ private IBinaryObject fBinaryFile; @@ -256,6 +262,7 @@ public class CDebugTarget extends CDebugElement implements ICDebugTarget, ICDIEv setRegisterManager( new CRegisterManager( this ) ); setBreakpointManager( new CBreakpointManager( this ) ); setGlobalVariableManager( new CGlobalVariableManager( this ) ); + setFormatManager( new CSettingsManager( this ) ); setMemoryBlockRetrieval( new CMemoryBlockRetrievalExtension( this ) ); initialize(); DebugPlugin.getDefault().getLaunchManager().addLaunchListener( this ); @@ -997,6 +1004,7 @@ public class CDebugTarget extends CDebugElement implements ICDebugTarget, ICDIEv getCDISession().getEventManager().removeEventListener( this ); DebugPlugin.getDefault().getExpressionManager().removeExpressionListener( this ); DebugPlugin.getDefault().getLaunchManager().removeLaunchListener( this ); + saveFormats(); saveGlobalVariables(); disposeGlobalVariableManager(); disposeModuleManager(); @@ -1436,6 +1444,10 @@ public class CDebugTarget extends CDebugElement implements ICDebugTarget, ICDIEv fGlobalVariableManager.save(); } + protected void saveFormats() { + fFormatManager.save(); + } + protected void disposeGlobalVariableManager() { fGlobalVariableManager.dispose(); } @@ -1635,6 +1647,14 @@ public class CDebugTarget extends CDebugElement implements ICDebugTarget, ICDIEv fGlobalVariableManager = globalVariableManager; } + protected CSettingsManager getFormatManager() { + return fFormatManager; + } + + private void setFormatManager( CSettingsManager formatManager ) { + fFormatManager = formatManager; + } + /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICDebugTarget#isPostMortem() */ diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CExpression.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CExpression.java index 4df54a7cdea..a13fc022f4f 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CExpression.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CExpression.java @@ -55,6 +55,7 @@ public class CExpression extends CLocalVariable implements IExpression { fText = cdiExpression.getExpressionText(); fCDIExpression = cdiExpression; fStackFrame = frame; + setInitialFormat(); } /* (non-Javadoc) diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CRegister.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CRegister.java index 856493c6c74..a9a12036865 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CRegister.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CRegister.java @@ -326,6 +326,7 @@ public class CRegister extends CVariable implements ICRegister { protected CRegister( CRegisterGroup parent, IRegisterDescriptor descriptor ) { super( parent, ((CRegisterDescriptor)descriptor).getCDIDescriptor() ); setFormat( CVariableFormat.getFormat( CDebugCorePlugin.getDefault().getPluginPreferences().getInt( ICDebugConstants.PREF_DEFAULT_REGISTER_FORMAT ) ) ); + setInitialFormat(); } /** @@ -334,6 +335,7 @@ public class CRegister extends CVariable implements ICRegister { protected CRegister( CRegisterGroup parent, IRegisterDescriptor descriptor, String message ) { super( parent, ((CRegisterDescriptor)descriptor).getCDIDescriptor(), message ); setFormat( CVariableFormat.getFormat( CDebugCorePlugin.getDefault().getPluginPreferences().getInt( ICDebugConstants.PREF_DEFAULT_REGISTER_FORMAT ) ) ); + setInitialFormat(); } /* (non-Javadoc) diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CVariable.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CVariable.java index 4c1ab6f4fd0..6f72d51ee1b 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CVariable.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CVariable.java @@ -11,6 +11,7 @@ package org.eclipse.cdt.debug.internal.core.model; import java.text.MessageFormat; + import org.eclipse.cdt.debug.core.CDebugCorePlugin; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.debug.core.ICDebugConstants; @@ -30,9 +31,11 @@ import org.eclipse.cdt.debug.core.model.CVariableFormat; import org.eclipse.cdt.debug.core.model.ICDebugElementStatus; import org.eclipse.cdt.debug.core.model.ICType; import org.eclipse.cdt.debug.core.model.ICValue; +import org.eclipse.cdt.debug.internal.core.CSettingsManager; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.model.IValue; /** @@ -101,6 +104,7 @@ public abstract class CVariable extends AbstractCVariable implements ICDIEventLi } fIsEnabled = ( parent instanceof AbstractCValue ) ? ((AbstractCValue)parent).getParentVariable().isEnabled() : !isBookkeepingEnabled(); getCDISession().getEventManager().addEventListener( this ); + setInitialFormat(); } /** @@ -115,6 +119,7 @@ public abstract class CVariable extends AbstractCVariable implements ICDIEventLi fIsEnabled = !isBookkeepingEnabled(); setStatus( ICDebugElementStatus.ERROR, MessageFormat.format( CoreModelMessages.getString( "CVariable.1" ), new String[]{ errorMessage } ) ); //$NON-NLS-1$ getCDISession().getEventManager().addEventListener( this ); + setInitialFormat(); } /* @@ -262,6 +267,7 @@ public abstract class CVariable extends AbstractCVariable implements ICDIEventLi */ public void changeFormat( CVariableFormat format ) throws DebugException { setFormat( format ); + storeFormat( format ); resetValue(); } @@ -297,6 +303,7 @@ public abstract class CVariable extends AbstractCVariable implements ICDIEventLi // If casting of variable to a type or array causes an error, the status // of the variable is set to "error" and it can't be reset by subsequent castings. resetValue(); + storeCastToArray( startIndex, length ); } } @@ -393,6 +400,7 @@ public abstract class CVariable extends AbstractCVariable implements ICDIEventLi // If casting of variable to a type or array causes an error, the status // of the variable is set to "error" and it can't be reset by subsequent castings. resetValue(); + storeCast(type); } } @@ -412,6 +420,8 @@ public abstract class CVariable extends AbstractCVariable implements ICDIEventLi // If casting of variable to a type or array causes an error, the status // of the variable is set to "error" and it can't be reset by subsequent castings. resetValue(); + forgetCast(); + forgetCastToArray(); } /* @@ -621,4 +631,181 @@ public abstract class CVariable extends AbstractCVariable implements ICDIEventLi protected void setName( String name ) { fName = name; } + + protected CSettingsManager getFormatManager() { + return ((CDebugTarget) getDebugTarget()).getFormatManager(); + } + + /** + * used to concatenate multiple names to a single identifier + */ + private final static String NAME_PART_SEPARATOR = "-"; //$NON-NLS-1$ + + /** + * suffix used to identify format informations + */ + private final static String FORMAT_SUFFIX = NAME_PART_SEPARATOR + "(format)"; //$NON-NLS-1$ + + /** + * suffix used to identify cast settings + */ + private final static String CAST_SUFFIX = NAME_PART_SEPARATOR + "(cast)"; //$NON-NLS-1$ + + /** + * suffix used to identify cast to array settings + */ + private final static String CAST_TO_ARRAY_SUFFIX = NAME_PART_SEPARATOR + "(cast_to_array)"; + + /** retrieve the identification for this variable. + * @return a string identifying this variable, to be used to store settings + * @throws DebugException + */ + String getVariableID() throws DebugException { + return getName(); // TODO: better identification if multiple variables have the same name + } + + /** helper to generate a string id used to persist the settings. + * @param next_obj next object to encode into the id + * @param buf contains the id of the part encoded so far. + * @throws DebugException + */ + static private void buildPesistID( CDebugElement next_obj, StringBuffer buf ) throws DebugException { + if ( next_obj instanceof CVariable ) { + CVariable cVariableParent = (CVariable) next_obj; + buf.append( NAME_PART_SEPARATOR ); + buf.append( cVariableParent.getVariableID() ); + buildPesistID( cVariableParent.getParent(), buf ); + } else if ( next_obj instanceof CStackFrame ) { + buf.append(NAME_PART_SEPARATOR); + // TODO: better identification if multiple functions have the same name (say for static functions) + buf.append( ((CStackFrame)next_obj ).getFunction() ); + } else if ( next_obj instanceof CDebugTarget ) { + // global, we use a root NAME_PART_SEPARATOR as indicator of that + buf.append( NAME_PART_SEPARATOR ); + } else if ( next_obj instanceof AbstractCValue ) { + // index or indirection. + AbstractCValue av = (AbstractCValue) next_obj; + buildPesistID( av.getParentVariable(), buf ); + } + } + + /** returns an string used to identify this variable + * @return + * @throws DebugException + */ + private final String getPersistID() throws DebugException { + StringBuffer id = new StringBuffer(); + id.append( getVariableID() ); + buildPesistID( getParent(), id ); + return id.toString(); + } + + /** stores the given format + * @param format the format to be used for this variable + */ + protected void storeFormat( CVariableFormat format ) { + try { + String formatString = Integer.toString( format.getFormatNumber() ); + + getFormatManager().putValue( getPersistID() + FORMAT_SUFFIX, formatString ); + } catch ( DebugException e ) { + // if we do not get the name, we use the default format, no reason for the creation to fail too. + DebugPlugin.log( e ); + } + } + + /** stores the cast information. + * @param type the type to be displayed instead + */ + protected void storeCast( String type ) { + try { + String id = getPersistID() + CAST_SUFFIX; + getFormatManager().putValue( id, type ); + } catch ( DebugException e ) { + DebugPlugin.log( e ); + } + } + + /** drops the cast information. + */ + protected void forgetCast() { + try { + String id = getPersistID() + CAST_SUFFIX; + getFormatManager().removeValue( id ); + } catch ( DebugException e ) { + DebugPlugin.log( e ); + } + } + + /** stores the cast array information. + * @param startIndex the first item to be displayed in the cast array operation + * @param length the number of elements to display + */ + protected void storeCastToArray(int startIndex, int length) { + try { + // we persist the information in a (startIndex):(Length) format. + String content = Integer.toString( startIndex ) + ":" + Integer.toString( length ); //$NON-NLS-1$ + getFormatManager().putValue( getPersistID() + CAST_TO_ARRAY_SUFFIX, content ); + } catch ( DebugException e ) { + DebugPlugin.log( e ); + } + } + + /** drops previously stored cast array information. + */ + protected void forgetCastToArray() { + try { + String id = getPersistID() + CAST_TO_ARRAY_SUFFIX; + getFormatManager().removeValue( id ); + } catch ( DebugException e ) { + DebugPlugin.log( e ); + } + } + + /** + * restore the format stored previously for this variable. + * Only sets explictly retrieved formats in order to maintain defaults. + */ + protected void setInitialFormat() { + try { + String persistID= getPersistID(); + String stringFormat = getFormatManager().getValue( persistID + FORMAT_SUFFIX ); + if ( stringFormat != null ) { + try { + CVariableFormat format = CVariableFormat.getFormat( Integer.parseInt( stringFormat ) ); + setFormat( format ); + } catch ( NumberFormatException e ) { + DebugPlugin.log( e ); + } + } + + if ( canCast() ) { + String castString = getFormatManager().getValue( persistID + CAST_SUFFIX ); + if ( castString != null ) { + cast( castString ); + } + } + if ( canCastToArray() ) { + String castToArrayString = getFormatManager().getValue( persistID + CAST_TO_ARRAY_SUFFIX ); + if (castToArrayString != null) { + int index = castToArrayString.indexOf( ':' ); + if ( index > 0 ) { + try { + int beg = Integer.parseInt( castToArrayString.substring( 0, index ) ); + int num = Integer.parseInt( castToArrayString.substring( index + 1 ) ); + castToArray( beg, num ); + } catch ( NumberFormatException e ) { + DebugPlugin.log( e ); + } + } else { + DebugPlugin.logMessage( "did not find expected : for cast to array", null ); //$NON-NLS-1$ + } + } + } + } catch ( DebugException e ) { + DebugPlugin.log( e ); + // we drop (and log) the exception here. + // even if the initial setup fails, we still want the complete creation to be successful + } + } } |