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