mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-11 10:15:39 +02:00
Bug 486955 - Add "Stop on startup" option to "Debug New Executable"
dialog Change-Id: I3f29453e999e19d1e045fe73bc09fd9deb164ac7
This commit is contained in:
parent
eb5ac1a56b
commit
f3faebccce
4 changed files with 157 additions and 34 deletions
|
@ -16,7 +16,6 @@ import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
|
||||||
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
|
|
||||||
import org.eclipse.cdt.debug.core.model.IDebugNewExecutableHandler;
|
import org.eclipse.cdt.debug.core.model.IDebugNewExecutableHandler;
|
||||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
|
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
|
||||||
|
@ -27,7 +26,6 @@ import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IProcesses;
|
import org.eclipse.cdt.dsf.debug.service.IProcesses;
|
||||||
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
|
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
|
||||||
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
|
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
|
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.ui.launching.NewExecutableDialog;
|
import org.eclipse.cdt.dsf.gdb.internal.ui.launching.NewExecutableDialog;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.ui.launching.NewExecutableInfo;
|
import org.eclipse.cdt.dsf.gdb.internal.ui.launching.NewExecutableInfo;
|
||||||
|
@ -53,20 +51,19 @@ public class GdbDebugNewExecutableCommand extends RefreshableDebugCommand implem
|
||||||
private class PromptJob extends UIJob {
|
private class PromptJob extends UIJob {
|
||||||
|
|
||||||
private DataRequestMonitor<NewExecutableInfo> fRequestMonitor;
|
private DataRequestMonitor<NewExecutableInfo> fRequestMonitor;
|
||||||
private boolean fRemote = false;
|
final private SessionType fSessionType;
|
||||||
|
|
||||||
private PromptJob( boolean remote, DataRequestMonitor<NewExecutableInfo> rm ) {
|
private PromptJob( SessionType sessionType, DataRequestMonitor<NewExecutableInfo> rm ) {
|
||||||
super( Messages.GdbDebugNewExecutableCommand_New_Executable_Prompt_Job );
|
super( Messages.GdbDebugNewExecutableCommand_New_Executable_Prompt_Job );
|
||||||
fRemote = remote;
|
fSessionType = sessionType;
|
||||||
fRequestMonitor = rm;
|
fRequestMonitor = rm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IStatus runInUIThread( IProgressMonitor monitor ) {
|
public IStatus runInUIThread( IProgressMonitor monitor ) {
|
||||||
int flags = ( fRemote ) ? NewExecutableDialog.REMOTE : 0;
|
final NewExecutableInfo info = new NewExecutableInfo(fSessionType);
|
||||||
NewExecutableDialog dialog = new NewExecutableDialog( GdbUIPlugin.getShell(), flags );
|
NewExecutableDialog dialog = new NewExecutableDialog(GdbUIPlugin.getShell(), info);
|
||||||
final boolean canceled = dialog.open() == Window.CANCEL;
|
final boolean canceled = dialog.open() == Window.CANCEL;
|
||||||
final NewExecutableInfo info = dialog.getExecutableInfo();
|
|
||||||
fExecutor.execute( new DsfRunnable() {
|
fExecutor.execute( new DsfRunnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -134,7 +131,7 @@ public class GdbDebugNewExecutableCommand extends RefreshableDebugCommand implem
|
||||||
}
|
}
|
||||||
|
|
||||||
PromptJob job = new PromptJob(
|
PromptJob job = new PromptJob(
|
||||||
backend.getSessionType() == SessionType.REMOTE,
|
backend.getSessionType(),
|
||||||
new DataRequestMonitor<NewExecutableInfo>( fExecutor, rm ){
|
new DataRequestMonitor<NewExecutableInfo>( fExecutor, rm ){
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -147,8 +144,7 @@ public class GdbDebugNewExecutableCommand extends RefreshableDebugCommand implem
|
||||||
protected void handleSuccess() {
|
protected void handleSuccess() {
|
||||||
try {
|
try {
|
||||||
Map<String, Object> attributes = getLaunchConfiguration().getAttributes();
|
Map<String, Object> attributes = getLaunchConfiguration().getAttributes();
|
||||||
attributes.put( IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REMOTE_BINARY, getData().getTargetPath() );
|
attributes.putAll(getData().getAttributes());
|
||||||
attributes.put( ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, getData().getArguments() );
|
|
||||||
procService.debugNewProcess(
|
procService.debugNewProcess(
|
||||||
commandControl.getContext(),
|
commandControl.getContext(),
|
||||||
getData().getHostPath(),
|
getData().getHostPath(),
|
||||||
|
|
|
@ -190,6 +190,8 @@ public class CDebuggerTab extends CLaunchConfigurationTab {
|
||||||
IPreferenceStore preferences = GdbUIPlugin.getDefault().getPreferenceStore();
|
IPreferenceStore preferences = GdbUIPlugin.getDefault().getPreferenceStore();
|
||||||
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN,
|
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN,
|
||||||
preferences.getBoolean(IGdbDebugPreferenceConstants.PREF_DEFAULT_STOP_AT_MAIN));
|
preferences.getBoolean(IGdbDebugPreferenceConstants.PREF_DEFAULT_STOP_AT_MAIN));
|
||||||
|
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL,
|
||||||
|
preferences.getString(IGdbDebugPreferenceConstants.PREF_DEFAULT_STOP_AT_MAIN_SYMBOL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,17 @@ package org.eclipse.cdt.dsf.gdb.internal.ui.launching;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
|
||||||
|
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.ui.commands.Messages;
|
import org.eclipse.cdt.dsf.gdb.internal.ui.commands.Messages;
|
||||||
|
import org.eclipse.cdt.dsf.gdb.launching.LaunchMessages;
|
||||||
|
import org.eclipse.cdt.dsf.gdb.service.SessionType;
|
||||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||||
import org.eclipse.jface.dialogs.TitleAreaDialog;
|
import org.eclipse.jface.dialogs.TitleAreaDialog;
|
||||||
import org.eclipse.jface.resource.JFaceResources;
|
import org.eclipse.jface.resource.JFaceResources;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.accessibility.AccessibleAdapter;
|
||||||
|
import org.eclipse.swt.accessibility.AccessibleEvent;
|
||||||
import org.eclipse.swt.events.ModifyEvent;
|
import org.eclipse.swt.events.ModifyEvent;
|
||||||
import org.eclipse.swt.events.ModifyListener;
|
import org.eclipse.swt.events.ModifyListener;
|
||||||
import org.eclipse.swt.events.SelectionAdapter;
|
import org.eclipse.swt.events.SelectionAdapter;
|
||||||
|
@ -34,31 +40,33 @@ import org.eclipse.swt.widgets.Text;
|
||||||
|
|
||||||
public class NewExecutableDialog extends TitleAreaDialog {
|
public class NewExecutableDialog extends TitleAreaDialog {
|
||||||
|
|
||||||
public static final int REMOTE = 0x1;
|
|
||||||
|
|
||||||
private int fFlags = 0;
|
|
||||||
private NewExecutableInfo fInfo = null;
|
private NewExecutableInfo fInfo = null;
|
||||||
|
|
||||||
private Text fHostBinaryText;
|
private Text fHostBinaryText;
|
||||||
private Text fTargetBinaryText;
|
private Text fTargetBinaryText;
|
||||||
private Text fArgumentsText;
|
private Text fArgumentsText;
|
||||||
|
|
||||||
public NewExecutableDialog( Shell parentShell, int flags ) {
|
private Button fStopInMain;
|
||||||
|
private Text fStopInMainSymbol;
|
||||||
|
|
||||||
|
public NewExecutableDialog( Shell parentShell, NewExecutableInfo info ) {
|
||||||
super( parentShell );
|
super( parentShell );
|
||||||
|
assert info != null;
|
||||||
setShellStyle( getShellStyle() | SWT.RESIZE );
|
setShellStyle( getShellStyle() | SWT.RESIZE );
|
||||||
fFlags = flags;
|
fInfo = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Control createContents( Composite parent ) {
|
protected Control createContents( Composite parent ) {
|
||||||
Control control = super.createContents( parent );
|
Control control = super.createContents( parent );
|
||||||
|
initialize();
|
||||||
validate();
|
validate();
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Control createDialogArea( Composite parent ) {
|
protected Control createDialogArea( Composite parent ) {
|
||||||
boolean remote = (fFlags & REMOTE) > 0;
|
boolean remote = fInfo.getSessionType() == SessionType.REMOTE;
|
||||||
|
|
||||||
getShell().setText( Messages.GdbDebugNewExecutableCommand_Debug_New_Executable );
|
getShell().setText( Messages.GdbDebugNewExecutableCommand_Debug_New_Executable );
|
||||||
setTitle( Messages.GdbDebugNewExecutableCommand_Select_Binary );
|
setTitle( Messages.GdbDebugNewExecutableCommand_Select_Binary );
|
||||||
|
@ -118,23 +126,74 @@ public class NewExecutableDialog extends TitleAreaDialog {
|
||||||
fArgumentsText = new Text( comp, SWT.BORDER );
|
fArgumentsText = new Text( comp, SWT.BORDER );
|
||||||
fArgumentsText.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false, 2, 1 ) );
|
fArgumentsText.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false, 2, 1 ) );
|
||||||
|
|
||||||
|
createOptionsArea(comp);
|
||||||
|
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void createOptionsArea(Composite parent) {
|
||||||
|
Composite optionsComp = new Composite(parent, SWT.NONE);
|
||||||
|
GridLayout layout = new GridLayout(3, false);
|
||||||
|
layout.marginWidth = layout.marginHeight = 0;
|
||||||
|
optionsComp.setLayout(layout);
|
||||||
|
optionsComp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
|
||||||
|
|
||||||
|
fStopInMain = new Button(optionsComp, SWT.CHECK);
|
||||||
|
fStopInMain.setText(LaunchMessages.getString("CDebuggerTab.Stop_at_main_on_startup")); //$NON-NLS-1$
|
||||||
|
fStopInMain.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
fStopInMainSymbol.setEnabled(fStopInMain.getSelection());
|
||||||
|
validate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fStopInMainSymbol = new Text(optionsComp, SWT.SINGLE | SWT.BORDER);
|
||||||
|
GridData gridData = new GridData(SWT.FILL, SWT.CENTER, false, false);
|
||||||
|
gridData.widthHint = 100;
|
||||||
|
fStopInMainSymbol.setLayoutData(gridData);
|
||||||
|
fStopInMainSymbol.addModifyListener(new ModifyListener() {
|
||||||
|
@Override
|
||||||
|
public void modifyText(ModifyEvent evt) {
|
||||||
|
validate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fStopInMainSymbol.getAccessible().addAccessibleListener(
|
||||||
|
new AccessibleAdapter() {
|
||||||
|
@Override
|
||||||
|
public void getName(AccessibleEvent e) {
|
||||||
|
e.result = LaunchMessages.getString("CDebuggerTab.Stop_at_main_on_startup"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void okPressed() {
|
protected void okPressed() {
|
||||||
String targetPath = ( fTargetBinaryText != null ) ? fTargetBinaryText.getText().trim() : null;
|
fInfo.setHostPath(fHostBinaryText.getText().trim());
|
||||||
|
String targetPath = fTargetBinaryText != null ? fTargetBinaryText.getText().trim() : null;
|
||||||
|
fInfo.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REMOTE_BINARY, targetPath);
|
||||||
String args = fArgumentsText.getText().trim();
|
String args = fArgumentsText.getText().trim();
|
||||||
fInfo = new NewExecutableInfo( fHostBinaryText.getText().trim(), targetPath, args );
|
fInfo.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, args);
|
||||||
|
saveOptions();
|
||||||
super.okPressed();
|
super.okPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public NewExecutableInfo getExecutableInfo() {
|
protected void initialize() {
|
||||||
return fInfo;
|
fHostBinaryText.setText(fInfo.getHostPath());
|
||||||
|
if (fTargetBinaryText != null) {
|
||||||
|
String targetPath = fInfo.getTargetPath();
|
||||||
|
fTargetBinaryText.setText(targetPath != null ? targetPath : ""); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
fArgumentsText.setText(fInfo.getArguments());
|
||||||
|
if (fStopInMain != null && fStopInMainSymbol != null) {
|
||||||
|
fStopInMain.setSelection((Boolean)fInfo.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN));
|
||||||
|
fStopInMainSymbol.setText((String)fInfo.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validate() {
|
protected void validate() {
|
||||||
boolean remote = (fFlags & REMOTE) > 0;
|
boolean remote = fInfo.getSessionType() == SessionType.REMOTE;
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
String hostBinary = fHostBinaryText.getText().trim();
|
String hostBinary = fHostBinaryText.getText().trim();
|
||||||
if ( hostBinary.isEmpty() ) {
|
if ( hostBinary.isEmpty() ) {
|
||||||
|
@ -163,7 +222,25 @@ public class NewExecutableDialog extends TitleAreaDialog {
|
||||||
sb.append( Messages.GdbDebugNewExecutableCommand_Binary_on_target_must_be_specified );
|
sb.append( Messages.GdbDebugNewExecutableCommand_Binary_on_target_must_be_specified );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (fStopInMain != null && fStopInMainSymbol != null) {
|
||||||
|
// The "Stop on startup at" field must not be empty
|
||||||
|
String mainSymbol = fStopInMainSymbol.getText().trim();
|
||||||
|
if (fStopInMain.getSelection() && mainSymbol.length() == 0) {
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.append("\n "); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
sb.append(LaunchMessages.getString("CDebuggerTab.Stop_on_startup_at_can_not_be_empty")); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setErrorMessage( ( sb.length() != 0 ) ? sb.toString() : null );
|
setErrorMessage( ( sb.length() != 0 ) ? sb.toString() : null );
|
||||||
getButton( IDialogConstants.OK_ID ).setEnabled( getErrorMessage() == null );
|
getButton( IDialogConstants.OK_ID ).setEnabled( getErrorMessage() == null );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void saveOptions() {
|
||||||
|
if (fStopInMain != null && fStopInMainSymbol != null) {
|
||||||
|
fInfo.setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, Boolean.valueOf(fStopInMain.getSelection()));
|
||||||
|
fInfo.setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, fStopInMainSymbol.getText().trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -11,20 +11,39 @@
|
||||||
|
|
||||||
package org.eclipse.cdt.dsf.gdb.internal.ui.launching;
|
package org.eclipse.cdt.dsf.gdb.internal.ui.launching;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
|
||||||
|
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
|
||||||
|
import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
|
||||||
|
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
|
||||||
|
import org.eclipse.cdt.dsf.gdb.service.SessionType;
|
||||||
|
import org.eclipse.jface.preference.IPreferenceStore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides information required to start
|
* This class provides information required to start
|
||||||
* debugging an executable.
|
* debugging an executable.
|
||||||
*/
|
*/
|
||||||
public class NewExecutableInfo {
|
public class NewExecutableInfo {
|
||||||
private String fHostPath;
|
|
||||||
private String fTargetPath;
|
|
||||||
private String fArguments;
|
|
||||||
|
|
||||||
public NewExecutableInfo(String hostPath, String targetPath, String args) {
|
public static final String ATTR_SESSION_TYPE = "sessionType"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
final private SessionType fSessionType;
|
||||||
|
private String fHostPath = ""; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private Map<String, Object> fAttributes = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
public NewExecutableInfo(SessionType sessionType) {
|
||||||
super();
|
super();
|
||||||
fHostPath = hostPath;
|
fSessionType = sessionType;
|
||||||
fTargetPath = targetPath;
|
setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REMOTE_BINARY, ""); //$NON-NLS-1$
|
||||||
fArguments = args;
|
setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, ""); //$NON-NLS-1$
|
||||||
|
IPreferenceStore preferences = GdbUIPlugin.getDefault().getPreferenceStore();
|
||||||
|
setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN,
|
||||||
|
preferences.getBoolean(IGdbDebugPreferenceConstants.PREF_DEFAULT_STOP_AT_MAIN));
|
||||||
|
setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL,
|
||||||
|
preferences.getString(IGdbDebugPreferenceConstants.PREF_DEFAULT_STOP_AT_MAIN_SYMBOL));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,18 +53,47 @@ public class NewExecutableInfo {
|
||||||
return fHostPath;
|
return fHostPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the host path
|
||||||
|
*/
|
||||||
|
public void setHostPath(String hostPath) {
|
||||||
|
fHostPath = hostPath;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For remote sessions returns the path of the executable
|
* For remote sessions returns the path of the executable
|
||||||
* on the target. Otherwise returns null.
|
* on the target. Otherwise returns null.
|
||||||
*/
|
*/
|
||||||
public String getTargetPath() {
|
public String getTargetPath() {
|
||||||
return fTargetPath;
|
return (String)fAttributes.get(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REMOTE_BINARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the arguments to pass to the executable, or null
|
* Returns the arguments to pass to the executable, or null
|
||||||
*/
|
*/
|
||||||
public String getArguments() {
|
public String getArguments() {
|
||||||
return fArguments;
|
return (String)fAttributes.get(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the attribute map
|
||||||
|
*/
|
||||||
|
public Map<String, Object> getAttributes() {
|
||||||
|
return fAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the session type
|
||||||
|
*/
|
||||||
|
public SessionType getSessionType() {
|
||||||
|
return fSessionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getAttribute(String name) {
|
||||||
|
return fAttributes.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttribute(String name, Object value) {
|
||||||
|
fAttributes.put(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue