/* * 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.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import net.rim.ejde.internal.core.ContextManager; import net.rim.ejde.internal.core.IConstants; import net.rim.ejde.internal.model.BasicBlackBerryProperties.Icon; import net.rim.ejde.internal.model.BlackBerryProject; import net.rim.ejde.internal.ui.editors.model.BlackBerryProjectPropertiesPage.Action; import net.rim.ejde.internal.ui.editors.model.BlackBerryProjectPropertiesPage.FilePathOperationSelectionListener; import net.rim.ejde.internal.ui.editors.model.BlackBerryProjectPropertiesPage.TableSelectionListener; import net.rim.ejde.internal.ui.editors.model.factories.ControlFactory; import net.rim.ejde.internal.util.FileUtils; import net.rim.ejde.internal.util.Messages; import net.rim.ejde.internal.validation.BBDiagnostic; import net.rim.ejde.internal.validation.BBPropertiesValidator; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ArrayContentProvider; 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.ILabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.Window; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; import org.eclipse.ui.dialogs.ISelectionStatusValidator; import org.eclipse.ui.forms.AbstractFormPart; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.model.WorkbenchContentProvider; import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.views.navigator.ResourceComparator; /** * The icon sub section used in both the icons section and the aep details section * * @author jkeshavarzi * */ public class IconsSubSection { private String _lastSelectedPath = null; private AbstractFormPart _parent; private BlackBerryProjectPropertiesPage _parentPage; private CheckboxTableViewer _viewer; private Map< Action, Button > _actionButtons; private Composite _body; private FormToolkit _toolkit; /** * Instantiates the IconSubSection object * * @param page * @param parent * @param body * @param toolkit */ public IconsSubSection( BlackBerryProjectPropertiesPage page, AbstractFormPart parent, final Composite body, FormToolkit toolkit ) { _parent = parent; _parentPage = page; _body = body; _toolkit = toolkit; } /** * When called, the icon section will be creates on the given parent * * @param createLabel */ public void create( Boolean createLabel, String toolTipText ) { Map< Action, SelectionListener > _actionListeners = new HashMap< Action, SelectionListener >( Action.values().length ); _actionListeners.put( Action.ADD_FROM_PROJECT, new AddIconSelectionListener( _parent ) ); _actionListeners.put( Action.ADD_FROM_EXTERNAL, new AddExternalIconSelectionListener( _parent ) ); _actionListeners.put( Action.REMOVE, new DeleteIconSelectionListener( _parent ) ); String label = createLabel ? Messages.BlackBerryProjectPropertiesPage_Table_Title : null; _viewer = (CheckboxTableViewer) ControlFactory .buildIconTableControl( _body, _toolkit, label, toolTipText, SWT.CHECK, 2, new String[] { "Icon file:" }, null, new ArrayContentProvider(), new IconsTableLabelProvider(), new IconTableCheckStateProvider(), null ); //$NON-NLS-1$ _actionButtons = ControlFactory.buildButtonControls( _actionListeners, _body, _toolkit ); _viewer.getTable().addSelectionListener( new TableSelectionListener( _actionButtons ) ); _viewer.addCheckStateListener( new IconTableCheckStateListener() ); } /** * Adds the given icon object to the icon table * * @param icon */ public boolean addIconTableItem( Icon icon ) { Table table = _viewer.getTable(); if( table.getItemCount() == 1 ) { if( !table.getItem( 0 ).getChecked() ) { icon.setIsFocus( Boolean.TRUE ); } } boolean result = _parentPage.addTableItem( _viewer, icon, _actionButtons, false ); if( result ) { updateIconButtons(); validateIcon( icon ); _parent.markDirty(); refresh(); } else { MessageDialog.openError( _parent.getManagedForm().getForm().getShell(), Messages.BlackBerryProjectPropertiesPage_Dup_File_Err_Dialog_Title, Messages.BlackBerryProjectPropertiesPage_Dup_Icon_Err_Dialog_Msg ); } return result; } /** * Removes the selected icon object from the icon table Updates the Focus status and UI accordingly * * @param icon */ public void removeSelectedIconTableItem() { _parentPage.removeSelectedTableItem( _viewer, _actionButtons, false ); Table table = _viewer.getTable(); if( table.getItemCount() == 1 ) { ( (Icon) _viewer.getElementAt( 0 ) ).setIsFocus( Boolean.FALSE ); } updateIconButtons(); _parent.markDirty(); refresh(); } public void refresh() { Object obj1 = _viewer.getElementAt( 0 ); Object obj2 = _viewer.getElementAt( 1 ); if( obj2 != null ) { _viewer.update( obj2, null ); } if( obj1 != null ) { _viewer.update( obj1, null ); } } public void setInput( Icon[] icons ) { _viewer.getTable().removeAll(); _viewer.setInput( icons ); // refresh(); refreshSelection(); updateIconButtons(); } public void refreshSelection() { Table table = _viewer.getTable(); if( table.getItemCount() > 0 ) { table.setSelection( 0 ); } } public void validateIcons() { Icon icons[] = getIcons(); for( Icon icon : icons ) { validateIcon( icon ); } } private void validateIcon( Icon icon ) { BlackBerryProjectFormEditor editor = ( (BlackBerryProjectFormEditor) _parentPage.getEditor() ); BBDiagnostic diag = BBPropertiesValidator.validateIconExists( editor.getBlackBerryProject().getProject(), icon ); if( diag.getSeverity() == Diagnostic.ERROR ) { String key = icon.getCanonicalFileName(); String msg = diag.getMessage(); if( _parent instanceof AlternateEntryPointDetails ) { // uniquely identify the keys AlternateEntryPointDetails details = (AlternateEntryPointDetails) _parent; String title = details.getCurrentAep().getTitle(); key = details.createUniquePrefix() + key; msg = "(" + title + ") " + msg; //$NON-NLS-1$ //$NON-NLS-2$ } if( diag.getSeverity() == Diagnostic.ERROR ) { _parentPage.createEditorErrorMarker( key, msg, _viewer.getTable() ); } else { _parentPage.removeEditorErrorMarker( key, _viewer.getTable() ); } } } /** * Sets the state (enabled/disabled) of the section * * @param enabled */ public void setEnabled( boolean enabled ) { if( enabled ) { updateIconButtons(); } else { _actionButtons.get( Action.ADD_FROM_PROJECT ).setEnabled( enabled ); _actionButtons.get( Action.ADD_FROM_EXTERNAL ).setEnabled( enabled ); _actionButtons.get( Action.REMOVE ).setEnabled( true ); } } private void updateIconButtons() { int count = _viewer.getTable().getItemCount(); if( count > 1 ) { if( _actionButtons.get( Action.ADD_FROM_PROJECT ) != null ) { _actionButtons.get( Action.ADD_FROM_PROJECT ).setEnabled( false ); } if( _actionButtons.get( Action.ADD_FROM_EXTERNAL ) != null ) { _actionButtons.get( Action.ADD_FROM_EXTERNAL ).setEnabled( false ); } if( _actionButtons.get( Action.REMOVE ) != null ) { _actionButtons.get( Action.REMOVE ).setEnabled( true ); } } else { if( _actionButtons.get( Action.ADD_FROM_PROJECT ) != null ) { _actionButtons.get( Action.ADD_FROM_PROJECT ).setEnabled( true ); } if( _actionButtons.get( Action.ADD_FROM_EXTERNAL ) != null ) { _actionButtons.get( Action.ADD_FROM_EXTERNAL ).setEnabled( true ); } if( _actionButtons.get( Action.REMOVE ) != null ) { _actionButtons.get( Action.REMOVE ).setEnabled( count == 0 ? false : true ); } } } private String openImageFileDialog( Shell shell, String fileName ) { FileDialog dialog = new FileDialog( shell, SWT.SINGLE ); String[] filterNames = new String[] { Messages.BlackBerryProjectPropertiesPage_Dialog_Filter_Image_Files }; String[] filterExtensions = new String[] { "*.gif;*.png;*.xpm;*.jpg;*.jpeg;*.tiff", "*" }; //$NON-NLS-1$ //$NON-NLS-2$ String filterPath = "/"; //$NON-NLS-1$ String platform = SWT.getPlatform(); if( platform.equals( "win32" ) || platform.equals( "wpf" ) ) { //$NON-NLS-1$ //$NON-NLS-2$ filterNames = new String[] { Messages.BlackBerryProjectPropertiesPage_Dialog_Filter_Image_Files }; filterExtensions = new String[] { "*.gif;*.png;*.bmp;*.jpg;*.jpeg;*.tiff", "*.*" }; //$NON-NLS-1$ //$NON-NLS-2$ if( _lastSelectedPath != null ) { filterPath = _lastSelectedPath; } else { filterPath = _parentPage.getBlackBerryProject().getProject().getLocation().toOSString(); } } dialog.setFilterNames( filterNames ); dialog.setFilterExtensions( filterExtensions ); dialog.setFilterPath( filterPath ); dialog.setFileName( fileName ); return dialog.open(); } /** * The label provider used by the icon table viewer * * @author jkeshavarzi * */ public class IconsTableLabelProvider implements ITableLabelProvider { @Override public Image getColumnImage( Object element, int columnIndex ) { Image image = null; if( ( null != element ) && ( element instanceof Icon ) && ( columnIndex == 1 ) ) { Icon icon = (Icon) element; image = ( (BlackBerryProjectFormEditor) _parentPage.getEditor() ).createIconImage( icon ); } return image; } @Override public String getColumnText( Object element, int columnIndex ) { if( ( null != element ) && Icon.class.equals( element.getClass() ) && ( columnIndex >= 0 ) ) { Icon icon = (Icon) element; switch( columnIndex ) { case 0: if( icon.isFocus().booleanValue() && ( _viewer.getTable().getItemCount() > 1 ) ) { _viewer.setChecked( element, true ); } return ""; //$NON-NLS-1$ case 1: return ""; //$NON-NLS-1$ case 2: return AbstractSection.pathToColumnValue( new Path( icon.getCanonicalFileName() ) ); } } return ""; //$NON-NLS-1$ } @Override public void addListener( ILabelProviderListener listener ) { // Do nothing } @Override public void dispose() { // Do nothing } @Override public boolean isLabelProperty( Object element, String property ) { return false; } @Override public void removeListener( ILabelProviderListener listener ) { // Do nothing } } /** * The checked state listener used by the icon table viewer. Ensures that only one focus icon can be selected. * * @author jkeshavarzi, bkurz * */ private class IconTableCheckStateListener implements ICheckStateListener { @Override public void checkStateChanged( CheckStateChangedEvent event ) { BlackBerryProjectFormEditor editor = (BlackBerryProjectFormEditor) _parentPage.getEditor(); Object eventSource = event.getSource(); Object eventElement = event.getElement(); boolean isChecked = event.getChecked(); if( eventSource instanceof CheckboxTableViewer ) { CheckboxTableViewer tableViewer = (CheckboxTableViewer) eventSource; int firstElementIndex = _parentPage.getObjectIndexInViewer( tableViewer, eventElement ).intValue(); BlackBerryProjectApplicationPage projectApplicationPage = editor._applicationPage; if( projectApplicationPage.getGeneralSection().getProjectType().equals( BlackBerryProject.LIBRARY ) ) { tableViewer.setChecked( eventElement, !isChecked ); } else if( tableViewer.getTable().getItemCount() <= 1 ) { tableViewer.setChecked( eventElement, false ); } else { if( firstElementIndex != -1 ) { Object otherElement = tableViewer.getElementAt( firstElementIndex == 0 ? 1 : 0 ); updateIconFocus( tableViewer, eventElement, isChecked ); updateIconFocus( tableViewer, otherElement, !isChecked ); _parent.markDirty(); editor.setDirty( true ); refresh(); } } } } private void updateIconFocus( CheckboxTableViewer tableViewer, Object element, boolean focusState ) { if( element instanceof Icon ) { Icon icon = (Icon) element; icon.setIsFocus( focusState ); } } } /** * The listener that handles add events. When the add button is pressed the user will be be prompted with a project based * dialog to select an icon * * @author jkeshavarzi * */ private class AddIconSelectionListener extends FilePathOperationSelectionListener { protected AddIconSelectionListener( AbstractFormPart section ) { _parentPage.super( section ); } @Override protected boolean process( SelectionEvent evt ) { Table table = _viewer.getTable(); if( table.getItemCount() <= 1 ) { Object iconObj = null; if( table.getItemCount() == 1 ) { Object tableObj = table.getItem( 0 ); TableItem item = (TableItem) tableObj; iconObj = item.getData(); } final Icon icon = (Icon) iconObj; ILabelProvider lp = new WorkbenchLabelProvider(); ITreeContentProvider cp = new WorkbenchContentProvider(); ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog( _body.getShell(), lp, cp ); ISelectionStatusValidator validator = new ISelectionStatusValidator() { public IStatus validate( Object[] selection ) { Status errorStatus = new Status( IStatus.ERROR, ContextManager.PLUGIN_ID, NLS.bind( Messages.BlackBerryProjectPropertiesPage_Add_File_Error_Status_Invalid_File, "icon" ) ); IStatus okStatus = Status.OK_STATUS; for( Object element : selection ) { if( element instanceof IFile ) { IFile file = (IFile) element; if( icon != null ) { // Relative Path IPath fileAbsPath = file.getLocation(); IPath fileRelPath = _parentPage.getBlackBerryProject().getProject().getLocation() .append( file.getProjectRelativePath() ); IPath iconPath = _parentPage.getBlackBerryProject().getProject().getLocation() .append( icon.getCanonicalFileName() ); if( fileAbsPath.equals( iconPath ) || fileRelPath.equals( iconPath ) ) { return new Status( IStatus.ERROR, ContextManager.PLUGIN_ID, Messages.BlackBerryProjectPropertiesPage_Dup_File_Err_Status_Msg ); } } String fileName = file.getName(); if( !BlackBerryProjectPropertiesPage.isImage( fileName ) ) { return errorStatus; } } else { return errorStatus; } } if( selection.length > 2 ) { return new Status( IStatus.ERROR, ContextManager.PLUGIN_ID, Messages.BlackBerryProjectPropertiesPage_Add_Icon_Error_Status_Max_Two ); } return okStatus; } }; dialog.addFilter( new ViewerFilter() { @Override public boolean select( Viewer viewer, Object parentElement, Object element ) { if( element instanceof IProject ) { return true; } if( element instanceof IFolder ) { IFolder folder = (IFolder) element; return !folder.getName().equals( IConstants.BIN_FOLD_NAME ) && !folder.isDerived(); } if( element instanceof IFile ) { return BlackBerryProjectPropertiesPage.isImage( ( (IFile) element ).getName() ); } return false; } } ); dialog.setComparator( new ResourceComparator( ResourceComparator.NAME ) ); dialog.setValidator( validator ); dialog.setTitle( Messages.BlackBerryProjectPropertiesPage_Add_Icon_Title ); dialog.setMessage( Messages.BlackBerryProjectPropertiesPage_Add_Icon_Message ); dialog.setInput( _parentPage.getBlackBerryProject().getProject() ); dialog.setAllowMultiple( false ); if( dialog.open() == Window.OK ) { Object[] elements = dialog.getResult(); if( elements != null ) { boolean result = false; for( Object element : elements ) { IResource resource = (IResource) element; result = result || addIconTableItem( new Icon( resource.getProjectRelativePath().toOSString(), false ) ); table.getColumn( 2 ).pack(); } if( table.getItemCount() > 1 ) { _actionButtons.get( Action.ADD_FROM_PROJECT ).setEnabled( false ); _actionButtons.get( Action.ADD_FROM_EXTERNAL ).setEnabled( false ); } return result; } } } return false; } } /** * The listener that handles add external events. When the add external button is pressed the user will be be prompted with a * file browser dialog to select an icon * * @author jkeshavarzi * */ private class AddExternalIconSelectionListener extends FilePathOperationSelectionListener { protected AddExternalIconSelectionListener( AbstractFormPart section ) { _parentPage.super( section ); } @Override protected boolean process( SelectionEvent e ) { Shell shell = _body.getShell(); Table table = _viewer.getTable(); if( table.getItemCount() <= 1 ) { String absolutePath = openImageFileDialog( shell, null ); if( absolutePath != null ) { _lastSelectedPath = new File( absolutePath ).getParent(); IPath relPath = ( (BlackBerryProjectFormEditor) _parentPage.getEditor() ).makeRelative( new Path( absolutePath ) ); // Will not be able to link external icon if one already exists in the res folder. IFolder resFolder = FileUtils.getResFolder( _parentPage.getBlackBerryProject().getProject() ); IFile relFile = AbstractSection.figureFile( relPath, resFolder ); if( !AbstractSection.isFileClear( relFile, null, resFolder, _parent.getManagedForm().getForm().getShell() ) ) { return false; } if( table.getItemCount() > 0 ) { Object ico = table.getItem( 0 ).getData(); if( ico instanceof Icon ) { IPath prevPath = new Path( ( (Icon) ico ).getCanonicalFileName() ); if( !AbstractSection.isFileClear( relFile, AbstractSection.figureFile( prevPath, resFolder ), resFolder, _parent.getManagedForm().getForm().getShell() ) ) { return false; } } } boolean result = addIconTableItem( new Icon( relPath.toOSString(), false ) ); table.getColumn( 2 ).pack(); if( table.getItemCount() > 1 ) { _actionButtons.get( Action.ADD_FROM_PROJECT ).setEnabled( false ); _actionButtons.get( Action.ADD_FROM_EXTERNAL ).setEnabled( false ); } return result; } } return false; } } /** * The listener that handles remove events. When the remove button is pressed thw selected icon will be removed from the * viewer * * @author jkeshavarzi * */ private class DeleteIconSelectionListener extends FilePathOperationSelectionListener { protected DeleteIconSelectionListener( AbstractFormPart section ) { _parentPage.super( section ); } @Override protected boolean process( SelectionEvent e ) { IStructuredSelection selection = (IStructuredSelection) _viewer.getSelection(); Object icon = selection.getFirstElement(); if( icon != null ) { if( _parent instanceof AlternateEntryPointDetails ) { AlternateEntryPointDetails details = (AlternateEntryPointDetails) _parent; String key = details.createUniquePrefix() + ( (Icon) icon ).getCanonicalFileName(); _parentPage.removeEditorErrorMarker( key, _viewer.getTable() ); } else { _parentPage.removeEditorErrorMarker( ( (Icon) icon ).getCanonicalFileName(), _viewer.getTable() ); } removeSelectedIconTableItem(); return true; } return false; } } private class IconTableCheckStateProvider implements ICheckStateProvider { @Override public boolean isChecked( Object element ) { boolean result = false; if( element instanceof Icon ) { result = ( (Icon) element ).isFocus().booleanValue(); } return result; } @Override public boolean isGrayed( Object element ) { return false; } } /** * @return An array of Icon objects pulled from the UI */ public Icon[] getIcons() { ArrayList< Icon > icons = new ArrayList< Icon >(); Object icon1 = _viewer.getElementAt( 0 ); Object icon2 = _viewer.getElementAt( 1 ); if( icon1 != null ) { icons.add( (Icon) icon1 ); } if( icon2 != null ) { icons.add( (Icon) icon2 ); } return icons.toArray( new Icon[ icons.size() ] ); } /** * @return The icon table viewer */ public CheckboxTableViewer getViewer() { return _viewer; } }