/******************************************************************************* * 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(); } } ); } }