/* * Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved. * * This program and the accompanying materials are made available * under the terms of the Eclipse Public License, Version 1.0, * which accompanies this distribution and is available at * * http://www.eclipse.org/legal/epl-v10.html * */ package net.rim.ejde.internal.ui.preferences; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import net.rim.ejde.internal.core.IConstants; import net.rim.ejde.internal.model.BasicBlackBerryProperties.PreprocessorTag; import net.rim.ejde.internal.model.BlackBerryProject; import net.rim.ejde.internal.model.BlackBerrySDKInstall; import net.rim.ejde.internal.model.BlackBerryVMInstallType; import net.rim.ejde.internal.model.preferences.PreprocessorPreferences; import net.rim.ejde.internal.util.Messages; import net.rim.ejde.internal.util.VMUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.IVMInstallChangedListener; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.ICheckStateProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; 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.Display; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; /** * This class represent a common UI of the view for preprocess directives. * */ public abstract class PreprocessDirectiveUI implements IPropertyChangeListener, IVMInstallChangedListener { static private final Logger log = Logger.getLogger( PreprocessDirectiveUI.class ); private BlackBerryProject _bbProject; private int _scope; private Composite _parent; private CheckboxTableViewer _preprocessorTableViewer; private Table _fTable; private Button _addButton; private Button _removeButton; private Button _editButton; private Button _selectAllButton; private Button _deselectAllButton; /** * Construct a PreprocessDirectiveUI instance. * * @param parent * @param scope */ public PreprocessDirectiveUI( Composite parent, int scope ) { this( parent, scope, null ); } /** * Construct a PreprocessDirectiveUI instance. * * @param parent * @param scope * @param bbProject */ public PreprocessDirectiveUI( Composite parent, int scope, BlackBerryProject bbProject ) { _parent = parent; _scope = scope; _bbProject = bbProject; createContent(); } private void createContent() { Composite main = new Composite( _parent, SWT.NONE ); GridLayout layout = new GridLayout(); layout.marginWidth = 0; layout.marginHeight = 0; layout.numColumns = 1; main.setLayout( layout ); main.setLayoutData( new GridData( GridData.FILL_BOTH ) ); Composite tableButtonComposite = new Composite( main, SWT.NONE ); tableButtonComposite.setLayout( BasicPrefsPage.getGridLayout( 2, 5, 0, 0, 0 ) ); tableButtonComposite.setLayoutData( new GridData( GridData.FILL_BOTH ) ); Composite tableComposite = new Composite( tableButtonComposite, SWT.NONE ); tableComposite.setLayout( BasicPrefsPage.getGridLayout( 1, 0, 0, 0, 5 ) ); tableComposite.setLayoutData( new GridData( GridData.FILL_BOTH ) ); Font font = _parent.getFont(); _fTable = new Table( tableComposite, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION ); GridData gd = new GridData( GridData.FILL_BOTH ); gd.heightHint = 250; gd.widthHint = 338; _fTable.setLayoutData( gd ); _fTable.setFont( font ); _fTable.setHeaderVisible( true ); _fTable.setLinesVisible( true ); _fTable.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { updateButtons(); } } ); TableColumn statusColumn = new TableColumn( _fTable, SWT.NONE ); statusColumn.setText( Messages.BuildPrefsPage_PreprocessActiveColulmnHeader ); statusColumn.setWidth( 50 ); TableColumn tagsColumn = new TableColumn( _fTable, SWT.NONE ); tagsColumn.setText( Messages.BuildPrefsPage_PreprocessTagsColulmnHeader ); tagsColumn.setWidth( 200 ); tagsColumn.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { Object input = _preprocessorTableViewer.getInput(); if( input instanceof PreprocessorTag[] ) { PreprocessorTag[] tags = (PreprocessorTag[]) input; Arrays.sort( tags, new DirectiveString() ); _preprocessorTableViewer.setInput( tags ); } } } ); TableColumn scopeColumn = new TableColumn( _fTable, SWT.NONE ); scopeColumn.setText( Messages.BuildPrefsPage_PreprocessScopeColulmnHeader ); scopeColumn.setWidth( 100 ); scopeColumn.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { Object input = _preprocessorTableViewer.getInput(); if( input instanceof PreprocessorTag[] ) { PreprocessorTag[] tags = (PreprocessorTag[]) input; Arrays.sort( tags, new ScopeComparator() ); _preprocessorTableViewer.setInput( tags ); } } } ); _preprocessorTableViewer = new CheckboxTableViewer( _fTable ); _preprocessorTableViewer.setContentProvider( new PreprocessorTagContentProvider() ); _preprocessorTableViewer.setLabelProvider( new PreprocessorTagLabelProvider() ); _preprocessorTableViewer.setCheckStateProvider( new PreprocessorTagCheckStateProvider() ); _preprocessorTableViewer.addCheckStateListener( new ICheckStateListener() { @Override public void checkStateChanged( CheckStateChangedEvent event ) { Object element = event.getElement(); if( element instanceof PreprocessorTag ) { PreprocessorTag tag = (PreprocessorTag) element; if( tag.getScopeID() <= _scope ) { tag.setIsActive( Boolean.valueOf( event.getChecked() ) ); performChanged(); } else { _preprocessorTableViewer.setChecked( tag, !event.getChecked() ); } } } } ); // create a button group with buttons Composite buttonComposite = new Composite( tableButtonComposite, SWT.NONE ); buttonComposite.setLayout( BasicPrefsPage.getGridLayout( 1, 0, 0, 0, 0 ) ); buttonComposite.setLayoutData( new GridData( GridData.FILL_VERTICAL ) ); // add "Add..." button _addButton = new Button( buttonComposite, SWT.PUSH ); _addButton.setText( Messages.BasicPrefsPage_AddButtonLabel ); BasicPrefsPage.setDialogConfirmButtonLayoutData( _addButton, 0 ); // add "Remove" button _removeButton = new Button( buttonComposite, SWT.PUSH ); _removeButton.setText( Messages.BasicPrefsPage_RemoveButtonLabel ); BasicPrefsPage.setDialogConfirmButtonLayoutData( _removeButton, 5 ); // add "Edit" button _editButton = new Button( buttonComposite, SWT.PUSH ); _editButton.setText( Messages.BasicPrefsPage_EditButtonLabel ); BasicPrefsPage.setDialogConfirmButtonLayoutData( _editButton, 5 ); // add "Select All" button _selectAllButton = new Button( buttonComposite, SWT.PUSH ); _selectAllButton.setText( Messages.BasicPrefsPage_SelectAllButtonLabel ); BasicPrefsPage.setDialogConfirmButtonLayoutData( _selectAllButton, 5 ); // add "De-select All" button _deselectAllButton = new Button( buttonComposite, SWT.PUSH ); _deselectAllButton.setText( Messages.BasicPrefsPage_DeselectAllButtonLabel ); BasicPrefsPage.setDialogConfirmButtonLayoutData( _deselectAllButton, 5 ); // add listener to listen to the event when "Add..." button is pressed final PreprocessDirectiveUI ui = this; _addButton.addSelectionListener( new SelectionAdapter() { PreprocessDefineInputValidator validator = new PreprocessDefineInputValidator( ui ); @Override public void widgetSelected( SelectionEvent e ) { InputDialog dialog = new InputDialog( _parent.getShell(), Messages.BuildPrefsPage_PreprocessAddDialogTitle, Messages.BuildPrefsPage_PreprocessDialogLabel, "", validator ); dialog.open(); String tags = dialog.getValue(); PreprocessorTag tag = null; List< PreprocessorTag > input = getInput(); boolean changed = false; for( String tagString : StringUtils.split( tags, IConstants.SEMICOLON_MARK ) ) { tag = new PreprocessorTag( tagString, true, _scope ); input.add( tag ); if( !changed ) { changed = true; } } if( changed ) { performChanged(); } _preprocessorTableViewer.setInput( input.toArray( new PreprocessorTag[ input.size() ] ) ); enableNonAddButtons(); } } ); // add listener to listen to the event when "Remove" button is pressed _removeButton.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { List< PreprocessorTag > input = getInput(); TableItem[] selections = _fTable.getSelection(); for( int i = 0; i < selections.length; i++ ) { input.remove( selections[ i ].getData() ); } _preprocessorTableViewer.setInput( input.toArray( new PreprocessorTag[ input.size() ] ) ); disableNonAddButtons(); if( selections.length > 0 ) { performChanged(); } } } ); // add listener to listen to the event when "Edit..." button is pressed _editButton.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { int[] selectedIndexes = _fTable.getSelectionIndices(); PreprocessDefineInputValidator validator = null; String tagString = null; List< PreprocessorTag > input = getInput(); PreprocessorTag tag; boolean changed = false; for( int tagIndex : selectedIndexes ) { TableItem item = _fTable.getItem( tagIndex ); String initialText = item.getText( 1 ); validator = new PreprocessDefineInputValidator( ui, true, initialText ); InputDialog dialog = new InputDialog( _parent.getShell(), Messages.BuildPrefsPage_PreprocessEditDialogTitle, Messages.BuildPrefsPage_PreprocessEditLabel, initialText, validator ); dialog.open(); tagString = dialog.getValue(); if( ( !initialText.equals( tagString ) ) && ( validator.isValid( tagString ) == null ) ) { tag = new PreprocessorTag( tagString, true, _scope ); input.remove( tagIndex ); input.add( tagIndex, tag ); if( !changed ) { changed = true; } } } _preprocessorTableViewer.setInput( input.toArray( new PreprocessorTag[ input.size() ] ) ); if( changed ) { performChanged(); } } } ); // add listener to listen to the event when "Select All" button is pressed _selectAllButton.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { List< PreprocessorTag > input = getInput(); boolean changed = false; for( PreprocessorTag tag : input ) { if( tag.getScopeID() == _scope && !tag.isActive() ) { tag.setIsActive( true ); if( !changed ) { changed = true; } } } _preprocessorTableViewer.setInput( input.toArray( new PreprocessorTag[ input.size() ] ) ); if( changed ) { performChanged(); } } } ); // add listener to listen to the event when "Deselect All" button is pressed _deselectAllButton.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { List< PreprocessorTag > input = getInput(); boolean changed = false; for( PreprocessorTag tag : input ) { if( tag.getScopeID() == _scope && tag.isActive() ) { tag.setIsActive( false ); if( !changed ) { changed = true; } } } _preprocessorTableViewer.setInput( input.toArray( new PreprocessorTag[ input.size() ] ) ); if( changed ) { performChanged(); } } } ); // show data showData(); } private boolean isValidSelections( TableItem[] selections ) { if( selections == null ) { return false; } PreprocessorTag tag; for( int i = 0; i < selections.length; i++ ) { tag = (PreprocessorTag) selections[ i ].getData(); if( tag.getScopeID() != _scope ) { return false; } } return true; } /** * Display data. */ public void showData() { List< PreprocessorTag > scopeDirectives = getDirectives(); List< PreprocessorTag > otherDirectives = getUnChangableDirectives(); List< PreprocessorTag > allDefines = new ArrayList< PreprocessorTag >(); allDefines.addAll( otherDirectives ); allDefines.addAll( scopeDirectives ); PreprocessorTag[] directiveArray = allDefines.toArray( new PreprocessorTag[ allDefines.size() ] ); Arrays.sort( directiveArray, new ScopeComparator() ); setInput( directiveArray ); } protected void setInput( final PreprocessorTag[] input ) { Display.getDefault().asyncExec( new Runnable() { public void run() { _preprocessorTableViewer.setInput( input ); updateButtons(); } } ); } private List< PreprocessorTag > getDirectives() { switch( _scope ) { case PreprocessorTag.WS_SCOPE: { return getWorkspaceDirectives(); } case PreprocessorTag.PJ_SCOPE: { if( _bbProject != null ) { return Arrays.asList( _bbProject.getProperties()._compile.getPreprocessorDefines() ); } else { return new ArrayList< PreprocessorTag >( 0 ); } } default: { return new ArrayList< PreprocessorTag >( 0 ); } } } protected List< PreprocessorTag > getUnChangableDirectives() { ArrayList< PreprocessorTag > unChangableDirectives = new ArrayList< PreprocessorTag >(); unChangableDirectives.addAll( getJREWorkspaceDirectives() ); if( _scope == PreprocessorTag.PJ_SCOPE ) { unChangableDirectives.addAll( getWorkspaceDirectives() ); } return unChangableDirectives; } protected List< PreprocessorTag > getJREWorkspaceDirectives() { ArrayList< PreprocessorTag > JREDirectives = new ArrayList< PreprocessorTag >(); List< String > JREDirectiveStrings = VMUtils.getAllJREDirectives(); String currentCPDefine = IConstants.EMPTY_STRING; switch( _scope ) { case PreprocessorTag.PJ_SCOPE: { if( _bbProject != null ) { try { currentCPDefine = VMUtils.getJREDirective( _bbProject ); } catch( Exception e ) { // the jre used by the project may be removed log.error( e.getMessage() ); } } break; } case PreprocessorTag.WS_SCOPE: { IVMInstall defaultVm = JavaRuntime.getDefaultVMInstall(); if( BlackBerryVMInstallType.VM_ID.equals( defaultVm.getVMInstallType().getId() ) ) { currentCPDefine = VMUtils.getJREDirective( (BlackBerrySDKInstall) defaultVm ); } break; } } for( String define : JREDirectiveStrings ) { JREDirectives.add( new PreprocessorTag( define, define.equals( currentCPDefine ), PreprocessorTag.SDK_SCOPE ) ); } return JREDirectives; } protected List< PreprocessorTag > getWorkspaceDirectives() { List< PreprocessorTag > workspaceDefines = PreprocessorPreferences.getPreprocessDefines(); for( PreprocessorTag ppDefine : workspaceDefines ) { ppDefine.setScopeID( PreprocessorTag.WS_SCOPE ); } return workspaceDefines; } protected void disableNonAddButtons() { if( isTableEmpty( _fTable ) ) { _removeButton.setEnabled( false ); _editButton.setEnabled( false ); _selectAllButton.setEnabled( false ); _deselectAllButton.setEnabled( false ); } } protected List< String > getDefineList() { List< String > defines = new ArrayList< String >(); for( TableItem itm : _fTable.getItems() ) { defines.add( itm.getText( 1 ) ); } return defines; } private void enableNonAddButtons() { if( !isTableEmpty( _fTable ) ) { _selectAllButton.setEnabled( true ); _deselectAllButton.setEnabled( true ); } } protected boolean isTableEmpty( Table table ) { if( table == null ) return false; return ( table.getItems().length == 0 ); } protected int getIndexof( PreprocessorTag tag ) { List< PreprocessorTag > tags = getInput(); return tags.indexOf( tag ); } /** * Gets the preprocess directives of the scope of this UI. * * @return */ public List< PreprocessorTag > getScopeDirectives() { List< PreprocessorTag > tagList = new ArrayList< PreprocessorTag >(); Object input = _preprocessorTableViewer.getInput(); if( input instanceof PreprocessorTag[] ) { PreprocessorTag[] tags = (PreprocessorTag[]) input; for( int i = 0; i < tags.length; i++ ) { if( tags[ i ].getScopeID() == _scope ) { tagList.add( tags[ i ] ); } } return tagList; } else { return new ArrayList< PreprocessorTag >( 0 ); } } private void updateButtons() { List< PreprocessorTag > tagList = getScopeDirectives(); if( tagList.size() == 0 ) { _removeButton.setEnabled( false ); _editButton.setEnabled( false ); _selectAllButton.setEnabled( false ); _deselectAllButton.setEnabled( false ); } else { _removeButton.setEnabled( true ); _editButton.setEnabled( true ); _selectAllButton.setEnabled( true ); _deselectAllButton.setEnabled( true ); } TableItem[] selections = _fTable.getSelection(); if( isValidSelections( selections ) ) { _editButton.setEnabled( _fTable.getSelectionCount() == 1 ); _removeButton.setEnabled( _fTable.getSelectionCount() >= 1 ); } else { _editButton.setEnabled( false ); _removeButton.setEnabled( false ); } } /** * Set a BlackBerry project. * * @param bbProject */ public void setProject( BlackBerryProject bbProject ) { _bbProject = bbProject; } public List< PreprocessorTag > getInput() { List< PreprocessorTag > tagList = new ArrayList< PreprocessorTag >(); Object input = _preprocessorTableViewer.getInput(); if( input instanceof PreprocessorTag[] ) { PreprocessorTag[] tags = (PreprocessorTag[]) input; for( int i = 0; i < tags.length; i++ ) { tagList.add( tags[ i ] ); } return tagList; } else { return new ArrayList< PreprocessorTag >( 0 ); } } public void removeAllDirectives() { _fTable.removeAll(); } @Override public void propertyChange( PropertyChangeEvent event ) { if( event.getProperty().equalsIgnoreCase( PreferenceConstants.PREPROCESSOR_DEFINE_LIST ) && _scope != PreprocessorTag.WS_SCOPE ) { showData(); } } abstract protected void performDefaults(); abstract protected void performChanged(); abstract protected void addListener(); abstract protected void removeListener(); /** * The label provider used for the PreprocessorTag table within the UI * */ class PreprocessorTagLabelProvider extends LabelProvider implements ITableLabelProvider { @Override public Image getColumnImage( Object element, int columnIndex ) { return null; } @Override public String getColumnText( Object element, int columnIndex ) { if( ( null != element ) && PreprocessorTag.class.equals( element.getClass() ) && ( columnIndex >= 0 ) ) { PreprocessorTag tag = (PreprocessorTag) element; switch( columnIndex ) { case 0: { return ""; //$NON-NLS-1$ } case 1: return tag.getPreprocessorDefine(); case 2: { if( tag.getScopeID() > _scope ) { int index = getIndexof( (PreprocessorTag) element ); if( index >= 0 ) { TableItem item = _preprocessorTableViewer.getTable().getItem( index ); if( item != null ) { item.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_GRAY ) ); } } } return PreprocessorTag.getScope( tag.getScopeID() ); } } } return ""; //$NON-NLS-1$ } } /** * The content provider used for the PreprocessorTags table within the UI * * */ class PreprocessorTagContentProvider implements IStructuredContentProvider { public Object[] getElements( Object inputElement ) { if( inputElement instanceof PreprocessorTag[] ) { PreprocessorTag input[] = (PreprocessorTag[]) inputElement; return input; } return new Object[ 0 ]; } public void dispose() { } @Override public void inputChanged( Viewer viewer, Object oldInput, Object newInput ) { } } /** * The content provider used for the PreprocessorTags table within the UI * * */ class PreprocessorTagCheckStateProvider implements ICheckStateProvider { @Override public boolean isChecked( Object element ) { boolean result = false; if( element instanceof PreprocessorTag ) { result = ( (PreprocessorTag) element ).isActive().booleanValue(); } return result; } @Override public boolean isGrayed( Object element ) { return false; } } class ScopeComparator implements Comparator< PreprocessorTag > { @Override public int compare( PreprocessorTag o1, PreprocessorTag o2 ) { if( o1.getScopeID() > o2.getScopeID() ) { return -1; } else if( o1.getScopeID() < o2.getScopeID() ) { return 1; } else { return o1.getPreprocessorDefine().compareToIgnoreCase( o2.getPreprocessorDefine() ); } } } class DirectiveString implements Comparator< PreprocessorTag > { @Override public int compare( PreprocessorTag o1, PreprocessorTag o2 ) { return o1.getPreprocessorDefine().compareToIgnoreCase( o2.getPreprocessorDefine() ); } } @Override public void defaultVMInstallChanged( IVMInstall previous, IVMInstall current ) { showData(); } @Override public void vmAdded( IVMInstall vm ) { showData(); } @Override public void vmChanged( org.eclipse.jdt.launching.PropertyChangeEvent event ) { showData(); } @Override public void vmRemoved( IVMInstall vm ) { showData(); } }