/*******************************************************************************
* Copyright (c) 2000, 2008 QNX Software Systems 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:
* QNX Software Systems - Initial API and implementation
* Vadimir Prus (vladimir@codesourcery.com) - bug 156114: GDB options layout
* problem
*******************************************************************************/
package org.eclipse.cdt.debug.mi.internal.ui;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Observable;
import java.util.Observer;
import org.eclipse.cdt.debug.mi.core.IMILaunchConfigurationConstants;
import org.eclipse.cdt.debug.mi.core.MIPlugin;
import org.eclipse.cdt.debug.mi.core.command.factories.CommandFactoryDescriptor;
import org.eclipse.cdt.debug.mi.ui.IMILaunchConfigurationComponent;
import org.eclipse.cdt.debug.mi.ui.MIUIUtils;
import org.eclipse.cdt.debug.ui.AbstractCDebuggerPage;
import org.eclipse.cdt.utils.ui.controls.ControlFactory;
import org.eclipse.cdt.utils.Platform;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
/**
* The dynamic tab for gdb-based debugger implementations.
*/
public class StandardGDBDebuggerPage extends AbstractCDebuggerPage implements Observer {
private final static String DEFAULT_MI_VERSION = "mi"; //$NON-NLS-1$
protected TabFolder fTabFolder;
protected Text fGDBCommandText;
protected Text fGDBInitText;
protected Combo fCommandFactoryCombo;
protected Combo fProtocolCombo;
protected Button fVerboseModeButton;
protected Button fBreakpointsFullPath;
private IMILaunchConfigurationComponent fSolibBlock;
private CommandFactoryDescriptor[] fCommandFactoryDescriptors;
private boolean fIsInitializing = false;
private static boolean gdb64ExistsIsCached = false;
private static boolean cachedGdb64Exists;
public void createControl( Composite parent ) {
Composite comp = new Composite( parent, SWT.NONE );
comp.setLayout( new GridLayout() );
comp.setLayoutData( new GridData( GridData.FILL_BOTH ) );
fTabFolder = new TabFolder( comp, SWT.NONE );
fTabFolder.setLayoutData( new GridData( GridData.FILL_BOTH | GridData.GRAB_VERTICAL ) );
createTabs( fTabFolder );
fTabFolder.setSelection( 0 );
setControl( parent );
}
public void setDefaults( ILaunchConfigurationWorkingCopy configuration ) {
configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUG_NAME, defaultGdbCommand(configuration));
configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_GDB_INIT, IMILaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT );
configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_COMMAND_FACTORY, MIPlugin.getDefault().getCommandFactoryManager().getDefaultDescriptor( getDebuggerIdentifier() ).getIdentifier() );
configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_VERBOSE_MODE, IMILaunchConfigurationConstants.DEBUGGER_VERBOSE_MODE_DEFAULT );
if ( fSolibBlock != null )
fSolibBlock.setDefaults( configuration );
}
protected String defaultGdbCommand(ILaunchConfiguration configuration) {
String gdbCommand = null;
if (Platform.getOS().equals(Platform.OS_LINUX) &&
Platform.getOSArch().equals("ppc64")) { //$NON-NLS-1$
// On SLES 9 and 10 for ppc64 arch, there is a separate
// 64-bit capable gdb called gdb64. It can
// also debug 32-bit executables, so let's see if it exists.
if (!gdb64ExistsIsCached) {
Process unameProcess;
int interruptedRetryCount = 5;
String cmd[] = {"gdb64", "--version"}; //$NON-NLS-1$ //$NON-NLS-2$
gdb64ExistsIsCached = true;
while (interruptedRetryCount >= 0) {
try {
unameProcess = Runtime.getRuntime().exec(cmd);
int exitStatus = unameProcess.waitFor();
cachedGdb64Exists = (exitStatus == 0);
break;
} catch (IOException e) {
cachedGdb64Exists = false;
break;
} catch (InterruptedException e) {
// Never should get here, really. The chances of the command being interrupted
// are very small
cachedGdb64Exists = false;
interruptedRetryCount--;
}
}
}
if (cachedGdb64Exists) {
gdbCommand = "gdb64"; //$NON-NLS-1$
} else {
gdbCommand = IMILaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT;
}
} else {
gdbCommand = IMILaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT;
}
return gdbCommand;
}
public boolean isValid( ILaunchConfiguration launchConfig ) {
boolean valid = fGDBCommandText.getText().length() != 0;
if ( valid ) {
setErrorMessage( null );
setMessage( null );
}
else {
setErrorMessage( MIUIMessages.getString( "StandardGDBDebuggerPage.0" ) ); //$NON-NLS-1$
setMessage( null );
}
return valid;
}
public void initializeFrom( ILaunchConfiguration configuration ) {
setInitializing( true );
String gdbCommand = defaultGdbCommand(configuration);
String gdbInit = IMILaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT;
try {
gdbCommand = configuration.getAttribute( IMILaunchConfigurationConstants.ATTR_DEBUG_NAME, defaultGdbCommand(configuration));
}
catch( CoreException e ) {
}
try {
gdbInit = configuration.getAttribute( IMILaunchConfigurationConstants.ATTR_GDB_INIT, IMILaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT );
}
catch( CoreException e ) {
}
if ( fSolibBlock != null )
fSolibBlock.initializeFrom( configuration );
fGDBCommandText.setText( gdbCommand );
fGDBInitText.setText( gdbInit );
String debuggerID = getDebuggerIdentifier();
fCommandFactoryDescriptors = MIPlugin.getDefault().getCommandFactoryManager().getDescriptors( debuggerID );
Arrays.sort( fCommandFactoryDescriptors,
new Comparator() {
public int compare( Object arg0, Object arg1 ) {
return ((CommandFactoryDescriptor)arg0).getName().compareTo( ((CommandFactoryDescriptor)arg1).getName() );
}
} );
String[] descLabels = new String[fCommandFactoryDescriptors.length];
String commandFactoryId = MIPlugin.getCommandFactory( configuration );
int index = -1;
for( int i = 0; i < fCommandFactoryDescriptors.length; ++i ) {
descLabels[i] = fCommandFactoryDescriptors[i].getName();
if ( fCommandFactoryDescriptors[i].getIdentifier().equals( commandFactoryId ) )
index = i;
}
fCommandFactoryCombo.setItems( descLabels );
if ( index < 0 ) {
index = 0;
}
//It may be the case that we can't match up any identifier with any installed debuggers associated
//with this debuggerID (ie fCommandFactoryDescriptors.length == 0) for example when importing a
//launch from different environments that use CDT debugging. In this case we try and soldier on
//using the defaults as much as is realistic.
String[] miVersions = new String[0];
if(index < fCommandFactoryDescriptors.length) {
fCommandFactoryCombo.select( index );
miVersions = fCommandFactoryDescriptors[index].getMIVersions();
}
fProtocolCombo.setItems( miVersions );
if ( miVersions.length == 0 ) {
miVersions = new String[] { DEFAULT_MI_VERSION };
}
String mi = DEFAULT_MI_VERSION;
try {
mi = configuration.getAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_PROTOCOL, DEFAULT_MI_VERSION );
}
catch( CoreException e ) {
// use default
}
int miIndex = 0;
for ( int i = 0; i < miVersions.length; ++i ) {
if ( miVersions[i].equals( mi ) ) {
miIndex = i;
break;
}
}
fProtocolCombo.select( miIndex );
boolean verboseMode = IMILaunchConfigurationConstants.DEBUGGER_VERBOSE_MODE_DEFAULT;
try {
verboseMode = configuration.getAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_VERBOSE_MODE, IMILaunchConfigurationConstants.DEBUGGER_VERBOSE_MODE_DEFAULT );
}
catch( CoreException e ) {
// use default
}
fVerboseModeButton.setSelection( verboseMode );
fBreakpointsFullPath.setSelection(getBreakpointsWithFullNameAttribute(configuration));
// We've populated combos, which affects their preferred size, and so must relayout things.
Control changed[] = { fCommandFactoryCombo, fProtocolCombo };
((Composite) getControl()).layout( changed );
setInitializing( false );
}
protected boolean getBreakpointsWithFullNameAttribute( ILaunchConfiguration config ) {
boolean result = IMILaunchConfigurationConstants.DEBUGGER_FULLPATH_BREAKPOINTS_DEFAULT;
try {
return config.getAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_FULLPATH_BREAKPOINTS, result );
}
catch( CoreException e ) {
// use default
}
return result;
}
public void performApply( ILaunchConfigurationWorkingCopy configuration ) {
String str = fGDBCommandText.getText();
str.trim();
configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUG_NAME, str );
str = fGDBInitText.getText();
str.trim();
configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_GDB_INIT, str );
str = fCommandFactoryCombo.getText();
int index = fCommandFactoryCombo.indexOf( str );
str = ( index < 0 ) ? "" : fCommandFactoryDescriptors[index].getIdentifier(); //$NON-NLS-1$
configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_COMMAND_FACTORY, str );
str = fProtocolCombo.getText();
configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_PROTOCOL, str );
if ( fSolibBlock != null )
fSolibBlock.performApply( configuration );
configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_VERBOSE_MODE, fVerboseModeButton.getSelection() );
configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_FULLPATH_BREAKPOINTS, fBreakpointsFullPath.getSelection() );
}
public String getName() {
return MIUIMessages.getString( "StandardGDBDebuggerPage.1" ); //$NON-NLS-1$
}
/**
* @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#getShell()
*/
protected Shell getShell() {
return super.getShell();
}
/**
* @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#updateLaunchConfigurationDialog()
*/
protected void updateLaunchConfigurationDialog() {
super.updateLaunchConfigurationDialog();
}
/*
* (non-Javadoc)
*
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void update( Observable o, Object arg ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
public IMILaunchConfigurationComponent createSolibBlock( Composite parent ) {
IMILaunchConfigurationComponent block = MIUIUtils.createGDBSolibBlock( true, true );
block.createControl( parent );
return block;
}
public void createTabs( TabFolder tabFolder ) {
createMainTab( tabFolder );
createSolibTab( tabFolder );
}
public void createMainTab( TabFolder tabFolder ) {
TabItem tabItem = new TabItem( tabFolder, SWT.NONE );
tabItem.setText( MIUIMessages.getString( "StandardGDBDebuggerPage.2" ) ); //$NON-NLS-1$
Composite comp = ControlFactory.createCompositeEx( tabFolder, 1, GridData.FILL_BOTH );
((GridLayout)comp.getLayout()).makeColumnsEqualWidth = false;
comp.setFont( tabFolder.getFont() );
tabItem.setControl( comp );
Composite subComp = ControlFactory.createCompositeEx( comp, 3, GridData.FILL_HORIZONTAL );
((GridLayout)subComp.getLayout()).makeColumnsEqualWidth = false;
subComp.setFont( tabFolder.getFont() );
Label label = ControlFactory.createLabel( subComp, MIUIMessages.getString( "StandardGDBDebuggerPage.3" ) ); //$NON-NLS-1$
GridData gd = new GridData();
// gd.horizontalSpan = 2;
label.setLayoutData( gd );
fGDBCommandText = ControlFactory.createTextField( subComp, SWT.SINGLE | SWT.BORDER );
fGDBCommandText.addModifyListener( new ModifyListener() {
public void modifyText( ModifyEvent evt ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
} );
Button button = createPushButton( subComp, MIUIMessages.getString( "StandardGDBDebuggerPage.4" ), null ); //$NON-NLS-1$
button.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent evt ) {
handleGDBButtonSelected();
updateLaunchConfigurationDialog();
}
private void handleGDBButtonSelected() {
FileDialog dialog = new FileDialog( getShell(), SWT.NONE );
dialog.setText( MIUIMessages.getString( "StandardGDBDebuggerPage.5" ) ); //$NON-NLS-1$
String gdbCommand = fGDBCommandText.getText().trim();
int lastSeparatorIndex = gdbCommand.lastIndexOf( File.separator );
if ( lastSeparatorIndex != -1 ) {
dialog.setFilterPath( gdbCommand.substring( 0, lastSeparatorIndex ) );
}
String res = dialog.open();
if ( res == null ) {
return;
}
fGDBCommandText.setText( res );
}
} );
label = ControlFactory.createLabel( subComp, MIUIMessages.getString( "StandardGDBDebuggerPage.6" ) ); //$NON-NLS-1$
gd = new GridData();
// gd.horizontalSpan = 2;
label.setLayoutData( gd );
fGDBInitText = ControlFactory.createTextField( subComp, SWT.SINGLE | SWT.BORDER );
gd = new GridData( GridData.FILL_HORIZONTAL );
fGDBInitText.setLayoutData( gd );
fGDBInitText.addModifyListener( new ModifyListener() {
public void modifyText( ModifyEvent evt ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
} );
button = createPushButton( subComp, MIUIMessages.getString( "StandardGDBDebuggerPage.7" ), null ); //$NON-NLS-1$
button.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent evt ) {
handleGDBInitButtonSelected();
updateLaunchConfigurationDialog();
}
private void handleGDBInitButtonSelected() {
FileDialog dialog = new FileDialog( getShell(), SWT.NONE );
dialog.setText( MIUIMessages.getString( "StandardGDBDebuggerPage.8" ) ); //$NON-NLS-1$
String gdbCommand = fGDBInitText.getText().trim();
int lastSeparatorIndex = gdbCommand.lastIndexOf( File.separator );
if ( lastSeparatorIndex != -1 ) {
dialog.setFilterPath( gdbCommand.substring( 0, lastSeparatorIndex ) );
}
String res = dialog.open();
if ( res == null ) {
return;
}
fGDBInitText.setText( res );
}
} );
label = ControlFactory.createLabel( subComp, MIUIMessages.getString( "StandardGDBDebuggerPage.9" ), //$NON-NLS-1$
200, SWT.DEFAULT, SWT.WRAP );
gd = new GridData( GridData.FILL_HORIZONTAL );
gd.horizontalSpan = 3;
gd.widthHint = 200;
label.setLayoutData( gd );
Composite options = ControlFactory.createCompositeEx( subComp, 2, GridData.FILL_HORIZONTAL );
gd = new GridData( GridData.FILL_HORIZONTAL );
gd.horizontalSpan = 3;
options.setLayoutData( gd );
createCommandFactoryCombo( options );
createProtocolCombo( options );
createVerboseModeButton( subComp );
createBreakpointFullPathName(subComp);
// fit options into 3-grid one per line
GridData gd1 = new GridData();
gd1.horizontalSpan = 3;
fVerboseModeButton.setLayoutData(gd1);
GridData gd2 = new GridData();
gd2.horizontalSpan = 3;
fBreakpointsFullPath.setLayoutData(gd2);
}
public void createSolibTab( TabFolder tabFolder ) {
TabItem tabItem = new TabItem( tabFolder, SWT.NONE );
tabItem.setText( MIUIMessages.getString( "StandardGDBDebuggerPage.10" ) ); //$NON-NLS-1$
Composite comp = ControlFactory.createCompositeEx( fTabFolder, 1, GridData.FILL_BOTH );
comp.setFont( tabFolder.getFont() );
tabItem.setControl( comp );
fSolibBlock = createSolibBlock( comp );
if ( fSolibBlock instanceof Observable )
((Observable)fSolibBlock).addObserver( this );
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#dispose()
*/
public void dispose() {
if ( fSolibBlock != null ) {
if ( fSolibBlock instanceof Observable )
((Observable)fSolibBlock).deleteObserver( this );
fSolibBlock.dispose();
}
super.dispose();
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#activated(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
*/
public void activated( ILaunchConfigurationWorkingCopy workingCopy ) {
// Override the default behavior
}
protected boolean isInitializing() {
return fIsInitializing;
}
private void setInitializing( boolean isInitializing ) {
fIsInitializing = isInitializing;
}
protected void createCommandFactoryCombo( Composite parent ) {
Label label = new Label( parent, SWT.NONE );
label.setText( MIUIMessages.getString( "StandardGDBDebuggerPage.12" ) ); //$NON-NLS-1$
fCommandFactoryCombo = new Combo( parent, SWT.READ_ONLY | SWT.DROP_DOWN );
fCommandFactoryCombo.addSelectionListener( new SelectionListener() {
public void widgetDefaultSelected( SelectionEvent e ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
public void widgetSelected( SelectionEvent e ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
} );
}
protected void createProtocolCombo( Composite parent ) {
Label label = new Label( parent, SWT.NONE );
label.setText( MIUIMessages.getString( "StandardGDBDebuggerPage.11" ) ); //$NON-NLS-1$
fProtocolCombo = new Combo( parent, SWT.READ_ONLY | SWT.DROP_DOWN );
fProtocolCombo.addSelectionListener( new SelectionListener() {
public void widgetDefaultSelected( SelectionEvent e ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
public void widgetSelected( SelectionEvent e ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
} );
}
protected String getCurrentCommandFactoryID() {
String name = fCommandFactoryCombo.getText();
for ( int i = 0; i < fCommandFactoryDescriptors.length; ++i ) {
if ( fCommandFactoryDescriptors[i].getName().equals( name ) ) {
return fCommandFactoryDescriptors[i].getIdentifier();
}
}
return ""; //$NON-NLS-1$
}
protected void createVerboseModeButton( Composite parent ) {
fVerboseModeButton = createCheckButton( parent, MIUIMessages.getString( "StandardGDBDebuggerPage.13" ) ); //$NON-NLS-1$
fVerboseModeButton.addSelectionListener( new SelectionListener() {
public void widgetDefaultSelected( SelectionEvent e ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
public void widgetSelected( SelectionEvent e ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
} );
}
protected void createBreakpointFullPathName( Composite parent ) {
fBreakpointsFullPath = createCheckButton( parent, MIUIMessages.getString( "StandardGDBDebuggerPage.14" ) ); //$NON-NLS-1$
fBreakpointsFullPath.addSelectionListener( new SelectionListener() {
public void widgetDefaultSelected( SelectionEvent e ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
public void widgetSelected( SelectionEvent e ) {
if ( !isInitializing() )
updateLaunchConfigurationDialog();
}
} );
}
}