/******************************************************************************* * Copyright (c) 2000, 2011 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 * IBM Corporation *******************************************************************************/ package org.eclipse.cdt.debug.mi.internal.ui; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Observable; import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.IBinaryParser; import org.eclipse.cdt.core.IBinaryParser.IBinaryFile; import org.eclipse.cdt.core.IBinaryParser.IBinaryShared; import org.eclipse.cdt.core.model.CoreModelUtil; import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.debug.mi.core.IMILaunchConfigurationConstants; import org.eclipse.cdt.debug.mi.core.MICoreUtils; import org.eclipse.cdt.debug.mi.internal.ui.dialogfields.DialogField; import org.eclipse.cdt.debug.mi.internal.ui.dialogfields.IDialogFieldListener; import org.eclipse.cdt.debug.mi.internal.ui.dialogfields.IListAdapter; import org.eclipse.cdt.debug.mi.internal.ui.dialogfields.LayoutUtil; import org.eclipse.cdt.debug.mi.internal.ui.dialogfields.ListDialogField; import org.eclipse.cdt.debug.mi.ui.IMILaunchConfigurationComponent; import org.eclipse.cdt.utils.ui.controls.ControlFactory; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.layout.PixelConverter; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.jface.window.Window; 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.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.DirectoryDialog; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.dialogs.CheckedTreeSelectionDialog; /** * The UI component to access the shared libraries search path. */ public class SolibSearchPathBlock extends Observable implements IMILaunchConfigurationComponent, IDialogFieldListener { class AddDirectoryDialog extends Dialog { protected Text fText; private Button fBrowseButton; private IPath fValue; /** * Constructor for AddDirectoryDialog. */ public AddDirectoryDialog( Shell parentShell ) { super( parentShell ); } @Override protected Control createDialogArea( Composite parent ) { Composite composite = (Composite)super.createDialogArea( parent ); Composite subComp = ControlFactory.createCompositeEx( composite, 2, GridData.FILL_HORIZONTAL ); ((GridLayout)subComp.getLayout()).makeColumnsEqualWidth = false; GridData data = new GridData( GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER ); data.widthHint = convertHorizontalDLUsToPixels( IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH ); subComp.setLayoutData( data ); subComp.setFont( parent.getFont() ); fText = new Text( subComp, SWT.SINGLE | SWT.BORDER ); fText.setLayoutData( new GridData( GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL ) ); fText.addModifyListener( new ModifyListener() { public void modifyText( ModifyEvent e ) { updateOKButton(); } } ); fBrowseButton = ControlFactory.createPushButton( subComp, MIUIMessages.getString( "GDBServerDebuggerPage.7" ) ); //$NON-NLS-1$ data = new GridData(); data.horizontalAlignment = GridData.FILL; fBrowseButton.setLayoutData( data ); fBrowseButton.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent evt ) { DirectoryDialog dialog = new DirectoryDialog( AddDirectoryDialog.this.getShell() ); dialog.setMessage( MIUIMessages.getString( "SolibSearchPathBlock.5" ) ); //$NON-NLS-1$ String res = dialog.open(); if ( res != null ) { fText.setText( res ); } } } ); applyDialogFont( composite ); return composite; } @Override protected void configureShell( Shell newShell ) { super.configureShell( newShell ); newShell.setText( MIUIMessages.getString( "SolibSearchPathBlock.Add_Directory" ) ); //$NON-NLS-1$ } public IPath getValue() { return fValue; } private void setValue( String value ) { fValue = ( value != null ) ? new Path( value ) : null; } @Override protected void buttonPressed( int buttonId ) { if ( buttonId == IDialogConstants.OK_ID ) { setValue( fText.getText() ); } else { setValue( null ); } super.buttonPressed( buttonId ); } protected void updateOKButton() { Button okButton = getButton( IDialogConstants.OK_ID ); String text = fText.getText(); okButton.setEnabled( isValid( text ) ); } protected boolean isValid( String text ) { return ( text.trim().length() > 0 ); } @Override protected Control createButtonBar( Composite parent ) { Control control = super.createButtonBar( parent ); updateOKButton(); return control; } } private Composite fControl; public class SolibSearchPathListDialogField extends ListDialogField { public SolibSearchPathListDialogField( IListAdapter adapter, String[] buttonLabels, ILabelProvider lprovider ) { super( adapter, buttonLabels, lprovider ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.internal.ui.dialogfields.ListDialogField#managedButtonPressed(int) */ @Override protected boolean managedButtonPressed( int index ) { boolean result = super.managedButtonPressed( index ); if ( result ) buttonPressed( index ); return result; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.mi.internal.ui.dialogfields.ListDialogField#getManagedButtonState(org.eclipse.jface.viewers.ISelection, int) */ @Override protected boolean getManagedButtonState( ISelection sel, int index ) { if ( index > 3 ) return getButtonState( sel, index ); return super.getManagedButtonState( sel, index ); } } private static String[] fgStaticButtonLabels = new String[] { MIUIMessages.getString( "SolibSearchPathBlock.0" ), //$NON-NLS-1$ MIUIMessages.getString( "SolibSearchPathBlock.1" ), //$NON-NLS-1$ MIUIMessages.getString( "SolibSearchPathBlock.2" ), //$NON-NLS-1$ MIUIMessages.getString( "SolibSearchPathBlock.3" ), //$NON-NLS-1$ MIUIMessages.getString( "SolibSearchPathBlock.6" ), //$NON-NLS-1$ null, // separator }; private IProject fProject; private Shell fShell; private SolibSearchPathListDialogField fDirList; private IListAdapter fCustomListAdapter; private File[] fAutoSolibs = new File[0]; public SolibSearchPathBlock() { this( new String[0], null ); } public SolibSearchPathBlock( String[] customButtonLabels, IListAdapter customListAdapter ) { super(); fCustomListAdapter = customListAdapter; int length = fgStaticButtonLabels.length; if ( customButtonLabels.length > 0 ) length += customButtonLabels.length; String[] buttonLabels = new String[length]; System.arraycopy( fgStaticButtonLabels, 0, buttonLabels, 0, fgStaticButtonLabels.length ); if ( length > fgStaticButtonLabels.length ) { for ( int i = fgStaticButtonLabels.length; i < length; ++i ) buttonLabels[i] = customButtonLabels[i - fgStaticButtonLabels.length]; } IListAdapter listAdapter = new IListAdapter() { public void customButtonPressed( DialogField field, int index ) { buttonPressed( index ); } public void selectionChanged( DialogField field ) { } }; ILabelProvider lp = new LabelProvider() { @Override public String getText( Object element ) { if ( element instanceof IPath ) return ((IPath)element).toOSString(); return super.getText( element ); } }; fDirList = new SolibSearchPathListDialogField( listAdapter, buttonLabels, lp ); fDirList.setLabelText( MIUIMessages.getString( "SolibSearchPathBlock.4" ) ); //$NON-NLS-1$ fDirList.setUpButtonIndex( 1 ); fDirList.setDownButtonIndex( 2 ); fDirList.setRemoveButtonIndex( 3 ); fDirList.setDialogFieldListener(this); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.mi.internal.ui.IMILaunchConfigurationComponent#createControl(org.eclipse.swt.widgets.Composite) */ public void createControl( Composite parent ) { fShell = parent.getShell(); Composite comp = ControlFactory.createCompositeEx( parent, 2, GridData.FILL_BOTH ); ((GridLayout)comp.getLayout()).makeColumnsEqualWidth = false; ((GridLayout)comp.getLayout()).marginHeight = 0; ((GridLayout)comp.getLayout()).marginWidth = 0; comp.setFont( parent.getFont() ); PixelConverter converter = new PixelConverter( comp ); fDirList.doFillIntoGrid( comp, 3 ); LayoutUtil.setHorizontalSpan( fDirList.getLabelControl( null ), 2 ); LayoutUtil.setWidthHint( fDirList.getLabelControl( null ), converter.convertWidthInCharsToPixels( 30 ) ); LayoutUtil.setHorizontalGrabbing( fDirList.getListControl( null ) ); fControl = comp; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.mi.internal.ui.IMILaunchConfigurationComponent#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration) */ public void initializeFrom( ILaunchConfiguration configuration ) { IProject project = null; try { String projectName = configuration.getAttribute( ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null ); if ( projectName != null ) { projectName = projectName.trim(); if ( projectName.length() > 0 ) { project = ResourcesPlugin.getWorkspace().getRoot().getProject( projectName ); } } } catch( CoreException e ) { } setProject( project ); if ( fDirList != null ) { try { List values = configuration.getAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_SOLIB_PATH, Collections.EMPTY_LIST ); ArrayList paths = new ArrayList( values.size() ); Iterator it = values.iterator(); while( it.hasNext() ) { paths.add( new Path( (String)it.next() ) ); } fDirList.addElements( paths ); } catch( CoreException e ) { } } try { fAutoSolibs = MICoreUtils.getAutoSolibs( configuration ); } catch( CoreException e ) { } } /* (non-Javadoc) * @see org.eclipse.cdt.debug.mi.internal.ui.IMILaunchConfigurationComponent#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) */ public void setDefaults( ILaunchConfigurationWorkingCopy configuration ) { configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_SOLIB_PATH, Collections.EMPTY_LIST ); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.mi.internal.ui.IMILaunchConfigurationComponent#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) */ public void performApply( ILaunchConfigurationWorkingCopy configuration ) { if ( fDirList != null ) { List elements = fDirList.getElements(); ArrayList values = new ArrayList( elements.size() ); Iterator it = elements.iterator(); while( it.hasNext() ) { values.add( ((IPath)it.next()).toOSString() ); } configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_SOLIB_PATH, values ); } ArrayList autoLibs = new ArrayList( fAutoSolibs.length ); for ( int i = 0; i < fAutoSolibs.length; ++i ) autoLibs.add( fAutoSolibs[i].getPath() ); configuration.setAttribute( IMILaunchConfigurationConstants.ATTR_DEBUGGER_AUTO_SOLIB_LIST, autoLibs ); } protected void buttonPressed( int index ) { boolean changed = false; if ( index == 0 ) { // Add button changed = addDirectory(); } else if ( index == 4 ) { //Select from list changed = selectFromList(); } else if ( index >= fgStaticButtonLabels.length && fCustomListAdapter != null ) { fCustomListAdapter.customButtonPressed( fDirList, index ); changed = true; } if ( changed ) { setChanged(); notifyObservers(); } } protected boolean getButtonState( ISelection sel, int index ) { if ( index == 4 ) { // select from list return ( !sel.isEmpty() ); } return true; } protected Shell getShell() { return fShell; } protected DialogField getDirList(){ return fDirList; } protected boolean addDirectory() { boolean changed = false; AddDirectoryDialog dialog = new AddDirectoryDialog( getShell() ); dialog.open(); IPath result = dialog.getValue(); if ( result != null && !contains( result ) ) { fDirList.addElement( result ); changed = true; } return changed; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.mi.internal.ui.IMILaunchConfigurationComponent#dispose() */ public void dispose() { deleteObservers(); } /* (non-Javadoc) * @see org.eclipse.cdt.debug.mi.internal.ui.IMILaunchConfigurationComponent#getControl() */ public Control getControl() { return fControl; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.mi.internal.ui.IMILaunchConfigurationComponent#isValid(org.eclipse.debug.core.ILaunchConfiguration) */ public boolean isValid( ILaunchConfiguration launchConfig ) { // TODO Auto-generated method stub return false; } protected boolean contains( IPath path ) { List list = fDirList.getElements(); Iterator it = list.iterator(); while( it.hasNext() ) { IPath p = (IPath)it.next(); if ( p.toFile().equals( path.toFile() ) ) return true; } return false; } protected IProject getProject() { return fProject; } private void setProject( IProject project ) { fProject = project; } protected boolean selectFromList() { boolean changed = false; List dirList = fDirList.getSelectedElements(); final HashSet libs = new HashSet( 10 ); if ( generateLibraryList( (IPath[])dirList.toArray( new IPath[dirList.size()] ), libs ) ) { ITreeContentProvider cp = new ITreeContentProvider() { public Object[] getChildren( Object parentElement ) { return getElements( parentElement ); } public Object getParent( Object element ) { if ( libs.contains( element ) ) return libs; return null; } public boolean hasChildren( Object element ) { return false; } public Object[] getElements( Object inputElement ) { if ( inputElement instanceof Set ) { return ((Set)inputElement).toArray(); } return new Object[0]; } public void dispose() { } public void inputChanged( Viewer viewer, Object oldInput, Object newInput ) { } }; LabelProvider lp = new LabelProvider() { @Override public String getText( Object element ) { if ( element instanceof File ) return ((File)element).getName(); return super.getText( element ); } }; CheckedTreeSelectionDialog dialog = new CheckedTreeSelectionDialog( getShell(), lp, cp ); dialog.setTitle( MIUIMessages.getString( "SolibSearchPathBlock.7" ) ); //$NON-NLS-1$ dialog.setMessage( MIUIMessages.getString( "SolibSearchPathBlock.8" ) ); //$NON-NLS-1$ dialog.setEmptyListMessage( MIUIMessages.getString( "SolibSearchPathBlock.9" ) ); //$NON-NLS-1$ dialog.setSorter( new ViewerSorter() ); dialog.setInput( libs ); dialog.setInitialElementSelections( Arrays.asList( fAutoSolibs ) ); if ( dialog.open() == Window.OK ) { Object[] result = dialog.getResult(); fAutoSolibs = Arrays.asList( result ).toArray( new File[result.length] ); changed = true; } } return changed; } private boolean generateLibraryList( final IPath[] paths, final Set libs ) { boolean result = true; IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run( IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException { for ( int i = 0; i < paths.length; ++i ) { File dir = paths[i].toFile(); if ( dir.exists() && dir.isDirectory() ) { File[] all = dir.listFiles(); for ( int j = 0; j < all.length; ++j ) { if ( monitor.isCanceled() ) { throw new InterruptedException(); } monitor.subTask( all[j].getPath() ); String libName = getSharedLibraryName( all[j] ); if ( libName != null ) { libs.add( new File( libName ) ); } } } } } }; try { IRunnableContext context = new ProgressMonitorDialog( getShell() ); context.run( true, true, runnable ); } catch( InvocationTargetException e ) { } catch( InterruptedException e ) { result = false; } return result; } protected String getSharedLibraryName( File file ) { if ( !file.isFile() ) return null; IProject project = getProject(); if ( project != null ) { IPath fullPath = new Path( file.getPath() ); try { ICConfigExtensionReference[] binaryParsersExt = CCorePlugin.getDefault().getDefaultBinaryParserExtensions( project ); for( int i = 0; i < binaryParsersExt.length; i++ ) { IBinaryParser parser = CoreModelUtil.getBinaryParser(binaryParsersExt[i]); try { IBinaryFile bin = parser.getBinary( fullPath ); if ( bin instanceof IBinaryShared ) { String soname = ((IBinaryShared)bin).getSoName(); return ( soname.length() != 0 ) ? soname : file.getName(); } } catch( IOException e ) { } } } catch( CoreException e ) { } return null; } // no project: for now IPath path = new Path( file.getPath() ); String name = path.lastSegment(); String extension = path.getFileExtension(); if ( extension != null && (extension.compareTo( "so" ) == 0 || extension.compareToIgnoreCase( "dll" ) == 0) ) //$NON-NLS-1$ //$NON-NLS-2$ return name; return ( name.indexOf( ".so." ) >= 0 ) ? name : null; //$NON-NLS-1$ } protected boolean isSharedLibrary( File file ) { if ( !file.isFile() ) return false; IProject project = getProject(); if ( project != null ) { IPath fullPath = new Path( file.getPath() ); try { ICConfigExtensionReference[] binaryParsersExt = CCorePlugin.getDefault().getDefaultBinaryParserExtensions( project ); for( int i = 0; i < binaryParsersExt.length; i++ ) { IBinaryParser parser = CoreModelUtil.getBinaryParser(binaryParsersExt[i]); try { IBinaryFile bin = parser.getBinary( fullPath ); return ( bin instanceof IBinaryShared ); } catch( IOException e ) { } } } catch( CoreException e ) { } return false; } // no project: for now IPath path = new Path( file.getPath() ); String extension = path.getFileExtension(); if ( extension != null && (extension.compareTo( "so" ) == 0 || extension.compareToIgnoreCase( "dll" ) == 0) ) //$NON-NLS-1$ //$NON-NLS-2$ return true; String name = path.lastSegment(); return ( name.indexOf( ".so." ) >= 0 ); //$NON-NLS-1$ } public void dialogFieldChanged(DialogField field) { setChanged(); notifyObservers(); } }