/*
* 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.List;
import java.util.Map;
import net.rim.ejde.internal.core.ContextManager;
import net.rim.ejde.internal.core.IConstants;
import net.rim.ejde.internal.model.BlackBerryProperties;
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.ui.editors.model.factories.LayoutFactory;
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.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TableViewer;
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.layout.GridData;
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.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.views.navigator.ResourceComparator;
/**
* This class creates the ALX files section used in the project properties editor.
*
* @author jkeshavarzi
*/
public class ALXFilesSection extends AbstractSection {
private TableViewer _alxFilesViewer;
private Map< Action, Button > _actionButtons;
private Composite _client;
private String _lastSelectedPath = null;
/**
* This class creates the ALX files section used in the project properties editor.
*
* @param page
* the page
* @param parent
* the parent
* @param toolkit
* the toolkit
* @param style
* the style
*/
public ALXFilesSection( BlackBerryProjectPropertiesPage page, Composite parent, FormToolkit toolkit, int style ) {
super( page, parent, page.getManagedForm().getToolkit(), ( style | Section.DESCRIPTION | ExpandableComposite.TITLE_BAR ) );
createFormContent( getSection(), toolkit );
}
/**
* Creates the form content.
*
* @param section
* the section
* @param toolkit
* the toolkit
*/
protected void createFormContent( Section section, FormToolkit toolkit ) {
preBuild();
GridData gd = new GridData( SWT.FILL, SWT.FILL, true, false );
gd.minimumWidth = 250;
section.setLayout( LayoutFactory.createClearGridLayout( false, 1 ) );
section.setLayoutData( gd );
section.setDescription( Messages.ALXFilesSection_Description );
setClient( toolkit.createComposite( section ) );
getClient().setLayout( LayoutFactory.createSectionGridLayout( false, 3 ) );
section.setClient( getClient() );
build( getClient(), toolkit );
postBuild( getClient(), toolkit );
}
private void preBuild() {
getSection().setText( Messages.ALXFilesSection_Title );
}
private void build( final Composite body, FormToolkit toolkit ) {
Map< Action, SelectionListener > actionListeners = new HashMap< Action, SelectionListener >( Action.values().length );
actionListeners.put( Action.ADD_FROM_PROJECT, new AddSelectionListener( getParentPage() ) );
actionListeners.put( Action.ADD_FROM_EXTERNAL, new AddExternalSelectionListener( getParentPage() ) );
actionListeners.put( Action.EDIT, new EditSelectionListener( getParentPage() ) );
actionListeners.put( Action.REMOVE, new DeleteSelectionListener( getParentPage() ) );
setAlxFilesViewer( (TableViewer) ControlFactory.buildTableControl( body, toolkit, null, null,
Integer.valueOf( SWT.NONE ), Integer.valueOf( 2 ),
new String[] { "alx file:" }, new ArrayContentProvider(), new AlxTableLabelProvider(), null ) ); //$NON-NLS-1$
setActionButtons( ControlFactory.buildButtonControls( actionListeners, body, toolkit ) );
Table table = _alxFilesViewer.getTable();
table.addSelectionListener( new TableSelectionListener( _actionButtons ) );
table.setData( BlackBerryProjectPropertiesPage.TABLE_TEXT_INDEX_KEY, Integer.valueOf( 1 ) );
insertControlValuesFromModel( getParentPage().getBlackBerryProject().getProperties() );
}
private void postBuild( Composite body, FormToolkit toolkit ) {
toolkit.paintBordersFor( body );
}
private List< IPath > getInput() {
List< IPath > alxList = new ArrayList< IPath >();
Object input = _alxFilesViewer.getInput();
if( input instanceof List ) {
alxList = (List< IPath >) input;
return alxList;
} else {
return new ArrayList< IPath >( 0 );
}
}
@Override
public void commit( boolean onSave ) {
List< IPath > alxFiles = getInput();
IPath alxFilePath;
for( int i = 0; i < alxFiles.size(); i++ ) {
alxFilePath = alxFiles.get( i );
alxFilePath = getEditor().linkExternalFile( alxFilePath );
alxFiles.remove( i );
alxFiles.add( i, alxFilePath );
}
_alxFilesViewer.setInput( alxFiles );
setAlxFilsToModel( alxFiles );
super.commit( onSave );
}
private void setAlxFilsToModel( List< IPath > alxFiles ) {
String[] alxFileStrings = new String[ alxFiles.size() ];
for( int i = 0; i < alxFiles.size(); i++ ) {
alxFileStrings[ i ] = alxFiles.get( i ).toOSString();
}
BlackBerryProperties properties = getProjectPropertiesPage().getBlackBerryProject().getProperties();
properties._packaging.setAlxFiles( alxFileStrings );
}
private List< IPath > getAlxFilesFromModel() {
BlackBerryProperties properties = getProjectPropertiesPage().getBlackBerryProject().getProperties();
String[] alxFileStrings = properties._packaging.getAlxFiles();
List< IPath > input = new ArrayList< IPath >();
for( int i = 0; i < alxFileStrings.length; i++ ) {
input.add( new Path( alxFileStrings[ i ] ) );
}
return input;
}
private void validateALXFile( IPath filePath ) {
BBDiagnostic diag = BBPropertiesValidator.validateFileExists( getProjectPropertiesPage().getBlackBerryProject()
.getProject(), filePath.toFile(), false );
if( diag.getSeverity() == Diagnostic.ERROR ) {
if( diag.getSeverity() == Diagnostic.ERROR ) {
getProjectPropertiesPage().createEditorErrorMarker( filePath.toString(), diag.getMessage(),
_alxFilesViewer.getTable() );
} else {
getProjectPropertiesPage().removeEditorErrorMarker( filePath.toString(), _alxFilesViewer.getTable() );
}
}
}
/**
* Update the controls within this section with values from the given properties object.
*
* @param properties
* the properties
*/
public void insertControlValuesFromModel( BlackBerryProperties properties ) {
Boolean generateALXFile = properties._packaging.getGenerateALXFile();
if( generateALXFile != null ) {
properties._packaging.setGenerateALXFile( generateALXFile );
}
_alxFilesViewer.setInput( getAlxFilesFromModel() );
}
public void validateAlxFiles() {
String alxFiles[] = getAlxFiles();
for( String alxFile : alxFiles ) {
validateALXFile( new Path( alxFile ) );
}
}
String openFileDialog( Shell shell, IPath filePath ) {
FileDialog dialog = new FileDialog( shell, SWT.OPEN );
String filterName[] = new String[] { Messages.ALXFilesSection_Add_Dialog_Filter_Name };
String filterExtension[] = new String[] { "*.alx" }; //$NON-NLS-1$
String filterPath = "/"; //$NON-NLS-1$
String fileName = null;
String platform = SWT.getPlatform();
if( platform.equals( "win32" ) || platform.equals( "wpf" ) ) { //$NON-NLS-1$ //$NON-NLS-2$
if( filePath != null ) {
filterPath = filePath.removeLastSegments( 1 ).toString();
fileName = filePath.lastSegment();
} else {
if( getLastSelectedPath() != null ) {
filterPath = getLastSelectedPath();
} else {
filterPath = getParentPage().getBlackBerryProject().getProject().getLocation().toOSString();
}
}
}
dialog.setFilterNames( filterName );
dialog.setFilterExtensions( filterExtension );
dialog.setFilterPath( filterPath );
dialog.setFileName( fileName );
return dialog.open();
}
/**
* Gets the alx files.
*
* @return An array of String objects containing the relative paths to each ALX file pulled from the view
*/
public String[] getAlxFiles() {
ArrayList< String > list = new ArrayList< String >();
for( TableItem item : getAlxFilesViewer().getTable().getItems() ) {
list.add( ( (IPath) item.getData() ).toOSString() );
}
return list.toArray( new String[ list.size() ] );
}
/**
* @param client
* the client to set
*/
void setClient( Composite client ) {
_client = client;
}
/**
* @return the client
*/
Composite getClient() {
return _client;
}
/**
* @param lastSelectedPath
* the lastSelectedPath to set
*/
void setLastSelectedPath( String lastSelectedPath ) {
_lastSelectedPath = lastSelectedPath;
}
/**
* @return the lastSelectedPath
*/
String getLastSelectedPath() {
return _lastSelectedPath;
}
/**
* @param parentPage
* the parentPage to set
*/
void setParentPage( BlackBerryProjectPropertiesPage parentPage ) {
setProjectPropertiesPage( parentPage );
}
/**
* @return the parentPage
*/
BlackBerryProjectPropertiesPage getParentPage() {
return getProjectPropertiesPage();
}
/**
* @param actionButtons
* the actionButtons to set
*/
void setActionButtons( Map< Action, Button > actionButtons ) {
_actionButtons = actionButtons;
}
/**
* @return the actionButtons
*/
Map< Action, Button > getActionButtons() {
return _actionButtons;
}
/**
* @param alxFilesViewer
* the alxFilesViewer to set
*/
void setAlxFilesViewer( TableViewer alxFilesViewer ) {
_alxFilesViewer = alxFilesViewer;
}
/**
* @return the alxFilesViewer
*/
TableViewer getAlxFilesViewer() {
return _alxFilesViewer;
}
protected void removeTableItems( TableItem item ) {
getParentPage().removeEditorErrorMarker( item.getText(), getAlxFilesViewer().getTable() );
getParentPage().removeSelectedTableItem( getAlxFilesViewer(), getActionButtons(), true );
}
/**
* The listener that listens for add events. When the add button is pressed, a file dialog will provided to the user to select
* an file.
*
*/
private class AddExternalSelectionListener extends BlackBerryProjectPropertiesPage.FilePathOperationSelectionListener {
/**
* Instantiates a new adds the selection listener.
*
* @param page
* the page
*/
public AddExternalSelectionListener( BlackBerryProjectPropertiesPage page ) {
page.super( getPart() );
}
/*
* (non-Javadoc)
*
* @see
* net.rim.ejde.internal.ui.editors.model.BlackBerryProjectPropertiesPage.FilePathOperationSelectionListener#process(org
* .eclipse.swt.events.SelectionEvent)
*/
@Override
protected boolean process( SelectionEvent evt ) {
Shell shell = getClient().getShell();
String filePath = openFileDialog( shell, null );
if( filePath != null ) {
setLastSelectedPath( new File( filePath ).getParent() );
IPath relativePath = getEditor().makeRelative( new Path( filePath ) );
if( isValidFile( relativePath ).isOK() ) {
List< IPath > input = getInput();
input.add( relativePath );
_alxFilesViewer.setInput( input );
return getProjectPropertiesPage().addTableItem( getAlxFilesViewer(), null, getActionButtons(), true );
}
}
return false;
}
}
protected IStatus isValidFile( IPath filePath ) {
TableItem[] items = _alxFilesViewer.getTable().getItems();
String alxFilePath;
for( int i = 0; i < items.length; i++ ) {
alxFilePath = items[ i ].getText();
if( getAbsolutePath( new Path( alxFilePath ) ).equals( filePath ) ) {
return new Status( IStatus.ERROR, ContextManager.PLUGIN_ID,
Messages.BlackBerryProjectPropertiesPage_Dup_File_Err_Status_Msg );
}
}
String fileName = filePath.lastSegment();
if( !BlackBerryProjectPropertiesPage.isAlx( fileName ) ) {
return new Status( IStatus.ERROR, ContextManager.PLUGIN_ID, NLS.bind(
Messages.BlackBerryProjectPropertiesPage_Add_File_Error_Status_Invalid_File, "alx" ) );
}
return Status.OK_STATUS;
}
protected IPath getAbsolutePath( IPath path ) {
IProject project = getEditor().getBlackBerryProject().getProject();
if( path.isAbsolute() ) {
return path;
} else {
if( path.segment( 0 ).equals( ".." ) ) { //$NON-NLS-1$
// Do an external file check
File externalFile = project.getLocation().append( path ).toFile();
return new Path( externalFile.getAbsolutePath() );
} else {
// Do a local proj file check
IFile iFile = project.getFile( path );
return iFile.getLocation();
}
}
}
/**
* 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 alx file
*
*/
private class AddSelectionListener extends FilePathOperationSelectionListener {
BlackBerryProjectPropertiesPage _page;
protected AddSelectionListener( BlackBerryProjectPropertiesPage page ) {
page.super( getPart() );
_page = page;
}
@Override
protected boolean process( SelectionEvent evt ) {
ILabelProvider lp = new WorkbenchLabelProvider();
ITreeContentProvider cp = new WorkbenchContentProvider();
ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog( getClient().getShell(), lp, cp );
ISelectionStatusValidator validator = new ISelectionStatusValidator() {
public IStatus validate( Object[] selection ) {
IStatus errorStatus = new Status( IStatus.ERROR, ContextManager.PLUGIN_ID, NLS.bind(
Messages.BlackBerryProjectPropertiesPage_Add_File_Error_Status_Invalid_File, "alx" ) );
IStatus status = null;
for( Object element : selection ) {
if( element instanceof IFile ) {
IFile file = (IFile) element;
status = isValidFile( file.getLocation() );
if( !status.isOK() ) {
return status;
}
} else {
return errorStatus;
}
}
return Status.OK_STATUS;
}
};
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.isAlx( ( (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( _page.getBlackBerryProject().getProject() );
dialog.setAllowMultiple( false );
if( dialog.open() == Window.OK ) {
Object[] elements = dialog.getResult();
if( elements != null ) {
boolean result = false;
List< IPath > input = getInput();
for( Object element : elements ) {
IResource resource = (IResource) element;
input.add( resource.getProjectRelativePath() );
result = result
|| getProjectPropertiesPage().addTableItem( getAlxFilesViewer(), null, getActionButtons(), true );
}
_alxFilesViewer.setInput( input );
return result;
}
}
return false;
}
}
/**
* The listener that listens for remove events. When the remove button is pressed, the selected ALX file table item will be
* removed
*
* @author jkeshavarzi
*/
class DeleteSelectionListener extends BlackBerryProjectPropertiesPage.FilePathOperationSelectionListener {
/**
* Instantiates a new delete selection listener.
*
* @param page
* the page
*/
public DeleteSelectionListener( BlackBerryProjectPropertiesPage page ) {
page.super( getPart() );
}
/*
* (non-Javadoc)
*
* @see
* net.rim.ejde.internal.ui.editors.model.BlackBerryProjectPropertiesPage.FilePathOperationSelectionListener#process(org
* .eclipse.swt.events.SelectionEvent)
*/
@Override
protected boolean process( SelectionEvent e ) {
List< IPath > input = getInput();
TableItem items[] = getAlxFilesViewer().getTable().getSelection();
if( items.length > 0 ) {
TableItem item = items[ 0 ];
removeTableItems( item );
input.remove( items[ 0 ].getData() );
_alxFilesViewer.setInput( input );
return true;
}
return false;
}
}
/**
* The listener that listens for edit events. When the edit button is pressed, the user will be prompted with a file dialog to
* edit the selected ALX file location
*
* @author jkeshavarzi
*/
class EditSelectionListener extends BlackBerryProjectPropertiesPage.FilePathOperationSelectionListener {
/**
* Instantiates a new edits the selection listener.
*
* @param page
* the page
*/
public EditSelectionListener( BlackBerryProjectPropertiesPage page ) {
page.super( getPart() );
}
/*
* (non-Javadoc)
*
* @see
* net.rim.ejde.internal.ui.editors.model.BlackBerryProjectPropertiesPage.FilePathOperationSelectionListener#process(org
* .eclipse.swt.events.SelectionEvent)
*/
@Override
protected boolean process( SelectionEvent e ) {
Shell shell = getClient().getShell();
int selectedIndex = getAlxFilesViewer().getTable().getSelectionIndex();
if( selectedIndex != -1 ) {
String alxItem = ( (IPath) getAlxFilesViewer().getElementAt( selectedIndex ) ).toOSString();
IPath itemPath = getParentPage().getBlackBerryProject().getProject().getLocation().append( alxItem );
String filePath = openFileDialog( shell, itemPath );
if( filePath != null ) {
setLastSelectedPath( new File( filePath ).getParent() );
IPath relativePath = getEditor().makeRelative( new Path( filePath ) );
if( getProjectPropertiesPage().getObjectIndexInViewer( getAlxFilesViewer(), relativePath.toString() )
.intValue() == -1 ) {
getAlxFilesViewer().replace( relativePath.toString(), selectedIndex );
return true;
}
}
}
return false;
}
}
/**
* The label provider used by the alx table viewer
*
*
*/
class AlxTableLabelProvider implements ITableLabelProvider {
@Override
public String getColumnText( Object element, int columnIndex ) {
if( ( null != element ) && ( columnIndex >= 0 ) ) {
IPath filePath = (IPath) element;
switch( columnIndex ) {
case 0:
return pathToColumnValue( filePath );
}
}
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
}
@Override
public Image getColumnImage( Object element, int columnIndex ) {
// TODO Auto-generated method stub
return null;
}
}
}