/* * 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.editors.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import net.rim.ejde.internal.core.IConstants; import net.rim.ejde.internal.model.BasicBlackBerryProperties.Icon; import net.rim.ejde.internal.model.BasicBlackBerryProperties.PreprocessorTag; import net.rim.ejde.internal.model.BlackBerryProject; import net.rim.ejde.internal.util.Messages; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.forms.AbstractFormPart; import org.eclipse.ui.forms.SectionPart; import org.eclipse.ui.forms.editor.FormEditor; import org.eclipse.ui.forms.editor.FormPage; /** * This is the base class for all pages within the project application descriptor editor. It provides various helper methods used * through out the pages. * * @author cmalinescu, jkeshavarzi * */ public abstract class BlackBerryProjectPropertiesPage extends FormPage { public static final String CONTROL_TITLE_KEY = "TITLE"; //$NON-NLS-1$ public static final String TABLE_TEXT_INDEX_KEY = "TEXT_COLUMN"; //$NON-NLS-1$ public static final String SECTION_PART_KEY = "part"; //$NON-NLS-1$ private final BlackBerryProject _blackBerryProject; private ArrayList< SectionPart > sections = new ArrayList< SectionPart >(); /** * The actions associated with each button event used in the editor * * @author jkeshavarzi * */ public static enum Action { ADD, ADD_FROM_PROJECT, ADD_FROM_EXTERNAL, REMOVE, EDIT, SELECT_ALL, SELECT_NONE, BROWSE, MOVE_UP, MOVE_DOWN; public String getButtonLabel() { switch( this ) { case ADD: return Messages.BlackBerryProjectPropertiesPage_Add_Button_Label; case REMOVE: return Messages.BlackBerryProjectPropertiesPage_Remove_Button_Label; case EDIT: return Messages.BlackBerryProjectPropertiesPage_Edit_Button_Label; case ADD_FROM_PROJECT: return Messages.BlackBerryProjectPropertiesPage_Add_From_Project_Button_Label; case ADD_FROM_EXTERNAL: return Messages.BlackBerryProjectPropertiesPage_Add_From_External_Button_Label; case SELECT_ALL: return Messages.BlackBerryProjectPropertiesPage_Select_All_Button_Label; case SELECT_NONE: return Messages.BlackBerryProjectPropertiesPage_Deselect_All_Button_Label; case BROWSE: return Messages.BlackBerryProjectPropertiesPage_Browse_Button_Label_Ellipsis; case MOVE_UP: return Messages.BlackBerryProjectPropertiesPage_MoveUp_Button_Label; case MOVE_DOWN: return Messages.BlackBerryProjectPropertiesPage_MoveDown_Button_Label; default: return IConstants.EMPTY_STRING; } } } /** * @param editor * @param id * @param title */ public BlackBerryProjectPropertiesPage( FormEditor editor, String id, String title ) { super( editor, id, title ); _blackBerryProject = ( (BlackBerryProjectFormEditor) editor ).getBlackBerryProject(); } protected void addSection( SectionPart part ) { getManagedForm().addPart( part ); sections.add( part ); } protected SectionPart[] getSections() { return sections.toArray( new SectionPart[ sections.size() ] ); } protected AbstractSection getSectionPartProperty( Composite body ) { AbstractSection section = null; Object parent = body.getParent().getData( SECTION_PART_KEY ); if( parent == null ) { // if part cannot be found, check higher. Used in packaging section where there is another level of composite parents parent = body.getParent().getParent().getData( SECTION_PART_KEY ); } if( ( parent != null ) && ( parent instanceof AbstractSection ) ) { section = (AbstractSection) parent; } return section; } /** * @param keyTable * @return An array of he resource keys in the passed in resource */ protected String[] getResourceKeys( Hashtable< String, String > keyTable ) { if( keyTable == null ) { return new String[] {}; } ArrayList< String > keys = new ArrayList< String >(); // Add blank entry to key list to allow user to select none. keys.add( "" ); //$NON-NLS-1$ for( Iterator< String > iterator = keyTable.keySet().iterator(); iterator.hasNext(); ) { keys.add( iterator.next() ); } return keys.toArray( new String[ keys.size() ] ); } /** * Creates an error marker in the editor with the given key * * @param key * @param message * @param control */ public void createEditorErrorMarker( Object key, String message, Control control ) { getManagedForm().getMessageManager().addMessage( key, message, null, IMessageProvider.ERROR, control ); } /** * Creates a warning marker in the editor with the given key * * @param key * @param message * @param control */ public void createEditorWarnMarker( Object key, String message, Control control ) { getManagedForm().getMessageManager().addMessage( key, message, null, IMessageProvider.WARNING, control ); } /** * Removes an error marker in the editor specified by the given key * * @param key * @param control */ public void removeEditorErrorMarker( Object key, Control control ) { getManagedForm().getMessageManager().removeMessage( key, control ); } /** * Sets the editor and managed forms to dirty */ protected void notifyModelChanged() { ( (BlackBerryProjectFormEditor) getEditor() ).setDirty( true ); getManagedForm().dirtyStateChanged(); } /** * Adds the given object item to the given table if and only if the object does not already exist. Also updates button * controls. * * @param viewer * @param item * @param actionButtons */ public boolean addTableItem( TableViewer viewer, Object item, Map< Action, Button > actionButtons, boolean updateUIOnly ) { if( updateUIOnly ) { if( actionButtons.containsKey( Action.EDIT ) ) { actionButtons.get( Action.EDIT ).setEnabled( true ); } if( actionButtons.containsKey( Action.REMOVE ) ) { actionButtons.get( Action.REMOVE ).setEnabled( true ); } return true; } else { if( getObjectIndexInViewer( viewer, item ) == -1 ) { if( item != null ) { viewer.add( item ); Table table = viewer.getTable(); table.select( table.getItemCount() - 1 ); // Used to fire any selection events viewer.setSelection( viewer.getSelection() ); } if( actionButtons.containsKey( Action.EDIT ) ) { actionButtons.get( Action.EDIT ).setEnabled( true ); } if( actionButtons.containsKey( Action.REMOVE ) ) { actionButtons.get( Action.REMOVE ).setEnabled( true ); } return true; } return false; } } /** * Sets the given viewer to the given input. Convenience method that removes all existing data before setting the input. * * @param viewer * @param input */ public void setViewerInput( TableViewer viewer, Object[] input ) { Arrays.sort( input ); // Remove existing data viewer.setInput( null ); viewer.getTable().removeAll(); viewer.setInput( input ); viewer.refresh( true ); } /** * Helper method that locates the given itemText and if found selects it. * * @param viewer * @param itemText * @param actionButtons */ public void selectItemInViewer( TableViewer viewer, String itemText, Map< Action, Button > actionButtons ) { Integer index = getItemIndex( viewer.getTable(), itemText ); if( index != -1 ) { viewer.getTable().select( index ); // Used to fire any selection events viewer.setSelection( viewer.getSelection() ); if( actionButtons != null ) { if( actionButtons.containsKey( Action.EDIT ) ) { actionButtons.get( Action.EDIT ).setEnabled( true ); } if( actionButtons.containsKey( Action.REMOVE ) ) { actionButtons.get( Action.REMOVE ).setEnabled( true ); } if( actionButtons.containsKey( Action.MOVE_UP ) ) { if( viewer.getTable().getItemCount() > 1 ) { actionButtons.get( Action.MOVE_UP ).setEnabled( true ); } } if( actionButtons.containsKey( Action.MOVE_DOWN ) ) { actionButtons.get( Action.MOVE_DOWN ) .setEnabled( index < viewer.getTable().getItemCount() - 1 ? true : false ); } } } } /** * Removes the currently selected table item from the viewer and updates controls accordingly * * @param viewer * @param actionButtons * @param updateUIOnly * <code>true</code> only update UI but not remove items from the table; <code>false</code> update UI and remove * items from the table; */ public void removeSelectedTableItem( TableViewer viewer, Map< Action, Button > actionButtons, boolean updateUIOnly ) { StructuredSelection selection = (StructuredSelection) viewer.getSelection(); Table table = viewer.getTable(); int selectionIndex = table.getSelectionIndex(); Boolean entryRemoved = false; if( !updateUIOnly ) { for( Iterator< ? > iter = selection.iterator(); iter.hasNext(); ) { Object selectedElement = iter.next(); if( selectedElement != null ) { viewer.remove( selectedElement ); if( !entryRemoved ) { entryRemoved = true; } } } } if( updateUIOnly || entryRemoved ) { int itemCount = table.getItemCount(); if( itemCount != 0 ) { table.select( itemCount - 1 > selectionIndex ? selectionIndex : itemCount - 1 ); if( actionButtons.containsKey( Action.MOVE_DOWN ) ) { if( selectionIndex == itemCount - 1 ) { actionButtons.get( Action.MOVE_DOWN ).setEnabled( false ); } actionButtons.get( Action.MOVE_UP ).setEnabled( itemCount > 1 ? true : false ); } // Used to fire any selection events viewer.setSelection( viewer.getSelection() ); } else { if( actionButtons.containsKey( Action.EDIT ) ) { actionButtons.get( Action.EDIT ).setEnabled( false ); } if( actionButtons.containsKey( Action.REMOVE ) ) { actionButtons.get( Action.REMOVE ).setEnabled( false ); } if( actionButtons.containsKey( Action.MOVE_UP ) ) { actionButtons.get( Action.MOVE_UP ).setEnabled( false ); } if( actionButtons.containsKey( Action.MOVE_DOWN ) ) { actionButtons.get( Action.MOVE_DOWN ).setEnabled( false ); } if( actionButtons.containsKey( Action.SELECT_ALL ) ) { actionButtons.get( Action.SELECT_ALL ).setEnabled( false ); } if( actionButtons.containsKey( Action.SELECT_NONE ) ) { actionButtons.get( Action.SELECT_NONE ).setEnabled( false ); } } // Enable any disabled add buttons - icon scenarios where only 2 icons can be added. if( actionButtons.containsKey( Action.ADD ) ) { actionButtons.get( Action.ADD ).setEnabled( true ); } if( actionButtons.containsKey( Action.ADD_FROM_PROJECT ) ) { actionButtons.get( Action.ADD_FROM_PROJECT ).setEnabled( true ); } if( actionButtons.containsKey( Action.ADD_FROM_EXTERNAL ) ) { actionButtons.get( Action.ADD_FROM_EXTERNAL ).setEnabled( true ); } if( table.getColumnCount() > 1 ) { table.getColumn( 1 ).pack(); } } } /** * Searches the given viewer for the given object and returns its index or -1 if the object was not found * * @param viewer * @param obj * @return */ public Integer getObjectIndexInViewer( TableViewer viewer, Object obj ) { for( int i = 0; i < viewer.getTable().getItemCount(); i++ ) { Object element = viewer.getElementAt( i ); if( ( obj instanceof Icon ) && ( element instanceof Icon ) ) { IProject project = _blackBerryProject.getProject(); IPath iconPath = new Path( ( (Icon) element ).getCanonicalFileName() ); IResource iconRes = project.findMember( iconPath ); IPath projectPath = project.getLocation(), iconRelPath, iconAbsPath; if( iconRes != null ) { iconRelPath = projectPath.append( iconRes.getProjectRelativePath() ); iconAbsPath = iconRes.getLocation(); } else { iconRelPath = null; iconAbsPath = projectPath.append( iconPath ); } IPath newIconPath = projectPath.append( ( (Icon) obj ).getCanonicalFileName() ); if( newIconPath.equals( iconRelPath ) || newIconPath.equals( iconAbsPath ) ) { return i; } } else if( ( obj instanceof PreprocessorTag ) && ( element instanceof PreprocessorTag ) ) { PreprocessorTag o1 = (PreprocessorTag) obj; PreprocessorTag o2 = (PreprocessorTag) element; if( o1.getPreprocessorDefine().equals( o2.getPreprocessorDefine() ) ) { return i; } } else { if( obj.equals( element ) ) { return i; } } } return -1; } /** * Checks the given table for any items with the given text and returns the first found index * * @param table * @param itemText * @return The index or -1 if the text was not found */ public static Integer getItemIndex( Table table, String itemText ) { Object obj = table.getData( TABLE_TEXT_INDEX_KEY ); Integer textColumn = null; if( ( obj != null ) && ( obj instanceof Integer ) ) { textColumn = (Integer) obj; for( int i = 0; i < table.getItemCount(); i++ ) { TableItem item = table.getItem( i ); if( item.getText( textColumn ).equals( itemText ) ) { return i; } } } return -1; } /** * Returns an instance of BlackBerryProject * * @return Instance of BlackBerryProject */ public BlackBerryProject getBlackBerryProject() { return _blackBerryProject; } public static boolean isImage( String fileName ) { if( fileName.toLowerCase().matches( ".*[.](gif|png|xpm|bmp|jpg|jpeg|tiff)" ) ) { //$NON-NLS-1$ return true; } return false; } public static boolean isAlx( String fileName ) { if( fileName.toLowerCase().matches( ".*[.](alx)" ) ) { //$NON-NLS-1$ return true; } return false; } /** * Dirty listener * * @author jkeshavarzi * */ public class DirtyListener implements ModifyListener, SelectionListener { AbstractFormPart _section = null; public DirtyListener( AbstractFormPart section ) { _section = section; } @Override public void modifyText( ModifyEvent e ) { process(); } @Override public void widgetDefaultSelected( SelectionEvent e ) { process(); } @Override public void widgetSelected( SelectionEvent e ) { process(); } public void process() { notifyModelChanged(); // The dirty flag must be set on the details rather than section so that changes made on it can be committed // see ManagedForm.commit() logic if( BlackBerryProjectPropertiesPage.this instanceof BlackBerryProjectAlternateEntryPointPage ) { AlternateEntryPointDetails details = ( (BlackBerryProjectAlternateEntryPointPage) BlackBerryProjectPropertiesPage.this ) .getAlternateEntryPointDetails(); if( details != null ) { details.markDirty(); } } else { _section.markDirty(); } } } /** * The parent listener to all button event listeners used in the editor * * @author jkeshavarzi * */ protected abstract class FilePathOperationSelectionListener implements SelectionListener { AbstractFormPart _section = null; protected FilePathOperationSelectionListener( AbstractFormPart section ) { _section = section; } @Override public void widgetDefaultSelected( SelectionEvent e ) { apply( e ); } @Override public void widgetSelected( SelectionEvent e ) { apply( e ); } private void apply( SelectionEvent e ) { if( process( e ) ) { notifyModelChanged(); if( _section != null ) { _section.markDirty(); } } } protected abstract boolean process( SelectionEvent e ); } /** * Project properties focus listener * * @author jkeshavarzi * */ protected class ProjectPropertiesFocusListener implements FocusListener { @Override public void focusLost( FocusEvent e ) { // TODO Future implementation } @Override public void focusGained( FocusEvent e ) { // Will be used in future outline View // BlackBerryProjectFormEditor editor = (BlackBerryProjectFormEditor) getEditor(); // editor.updateContentOutlinePageSelection( (Control) e.getSource() ); } } /** * The basic listener used in editor tables * * @author jkeshavarzi * */ protected static class TableSelectionListener implements SelectionListener { private Button remove, edit, moveUp, moveDown; public TableSelectionListener( Map< Action, Button > buttonMap ) { remove = buttonMap.get( Action.REMOVE ); edit = buttonMap.get( Action.EDIT ); moveUp = buttonMap.get( Action.MOVE_UP ); moveDown = buttonMap.get( Action.MOVE_DOWN ); } @Override public void widgetDefaultSelected( SelectionEvent e ) { } @Override public void widgetSelected( SelectionEvent e ) { Table table = ( (Table) e.getSource() ); int selectionCount = table.getSelectionCount(); int selectionIndex = table.getSelectionIndex(); int itemCount = table.getItemCount(); if( edit != null ) { if( selectionCount > 1 ) { edit.setEnabled( false ); } else { edit.setEnabled( true ); } } if( remove != null ) { remove.setEnabled( true ); } if( moveUp != null ) { moveUp.setEnabled( ( itemCount > 1 ) && ( selectionIndex > 0 ) ? true : false ); } if( moveDown != null ) { moveDown.setEnabled( ( itemCount > 1 ) && ( selectionIndex < itemCount - 1 ) ? true : false ); } } } }