srcanaapps/depexplorer/com.nokia.s60tools.appdep/src/com/nokia/s60tools/appdep/ui/dialogs/AddSISFilesDialog.java
author noe\swadi
Tue, 23 Feb 2010 10:27:57 +0530
changeset 3 ec51f72aa69a
parent 0 a02c979e8dfd
permissions -rw-r--r--
Licenses updated to EPL.

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
 
package com.nokia.s60tools.appdep.ui.dialogs;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
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.graphics.Point;
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.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Widget;

import com.nokia.s60tools.appdep.AppDepHelpContextIDs;
import com.nokia.s60tools.appdep.plugin.AppDepPlugin;
import com.nokia.s60tools.appdep.resources.ImageKeys;
import com.nokia.s60tools.appdep.resources.ImageResourceManager;
import com.nokia.s60tools.appdep.resources.Messages;
import com.nokia.s60tools.appdep.util.AppDepConsole;
import com.nokia.s60tools.appdep.util.SISFileUtils;
import com.nokia.s60tools.ui.S60ToolsTable;
import com.nokia.s60tools.ui.S60ToolsTableColumnData;
import com.nokia.s60tools.ui.S60ToolsTableFactory;
import com.nokia.s60tools.ui.S60ToolsUIConstants;



/**
 * Dialog for adding components from SIS file for analysis. 
 */
public class AddSISFilesDialog extends TitleAreaDialog  implements SelectionListener{	

	//
	// Private classes
	//
	
	/**
	 * Label provider for table viewer component.
	 */
	class SISFilesViewerLabelProvider extends LabelProvider implements ITableLabelProvider{

		/* (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
		 */
		public Image getColumnImage(Object element, int columnIndex) {
			return null; // No images used
		}

		/* (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
		 */
		public String getColumnText(Object element, int columnIndex) {
			String label = element.toString();
			
			SISFileEntry entryData = (SISFileEntry) element;

			switch (columnIndex) {
		
				case SISFileEntry.NAME_COLUMN_INDEX:
					label = entryData.getFileName();
					break;
		
				case SISFileEntry.LOCATION_COLUMN_INDEX:
					label = entryData.getLocation();
					break;
							
				default:
					AppDepConsole.getInstance().println(Messages.getString("GeneralMessages.Unexpected_Column_Index_ErrMsg") + ": " + columnIndex, AppDepConsole.MSG_ERROR); //$NON-NLS-1$ //$NON-NLS-2$
					break;
			}
			
			return label;
		}
		
	}
	
	//
	// Private constants
	//
	
	/**
	 * Columns in the container area.
	 */
	private static final int COLUMN_COUNT = 2;	  

	/**
	 * Dialog width.
	 */
	private static final int DIALOG_WIDTH = 425;
	
	/**
	 * Dialog height.
	 */
	private static final int DIALOG_HEIGHT = 425;
		
	/**
	 * Percentage as decimal number how much table viewer is taking space hirizontally. 
	 */
	private static final double TABLE_VIEWER_WIDTH_PERCENTAGE = 0.8;
	
	/**
	 * Default guiding message shown to the user in add new mode.
	 */
	private static final String DEFAULT_MESSAGE = Messages.getString("AddSISFilesDialog.Default_InfoMessage"); //$NON-NLS-1$
	
	/**
	 * Complete message shown to the user in add new mode.
	 */
	private static final String COMPLETE_MESSAGE = Messages.getString("AddSISFilesDialog.Complete_InfoMessage");  //$NON-NLS-1$
	
	//
	// Member data
	//
	
	/**
	 * Flag used to make sure that create() and open() are called in correct order.
	 */
	private boolean isCreateCalled = false;
	
	/**
	 * Stores the currently selected SIS file entries.
	 */
	Map<String, SISFileEntry> sisFileEntries;

	//
	// UI Controls
	//	
	
	/**
	 * Container area for individual fields for the user for entering information.
	 */
	private Composite container;

	/**
	 * Reference to OK button that can be disabled/enabled 
	 * due to information entered..
	 */
	private Button okActionBtn;

	/**
	 * Button for opening file dialog for selecting SIS file(s).
	 */
	private Button addButton;

	/**
	 * Button for removing currently selected SIS file from table viewer, 
	 */
	private Button removeButton;

	/**
	 * Button for removing all SIS files from table viewer,
	 */
	private Button removeAllButton;

	/**
	 * Viewer showing currently selected SIS file entries.
	 */
	private TableViewer sisFilesViewer;

	
	/**
	 * Constructor. Used to open dialog in order to add new entry.
	 * @param parentShell Parent shell for the dialog.
	 */
	public AddSISFilesDialog(Shell parentShell) {
		super(parentShell);
		sisFileEntries = new HashMap<String, SISFileEntry>();
		// Setting banner image
		String bannerImage = ImageKeys.WIZARD_BANNER;
		setTitleImage(ImageResourceManager.getImage(bannerImage));
	}

    /* (non-Javadoc)
     * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
     */
    protected void createButtonsForButtonBar(Composite parent) {
        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
                true);
        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL,
                true);     
		okActionBtn = getButton(IDialogConstants.OK_ID);
		disableOk();        
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
     */
    protected void configureShell(Shell shell) {
        super.configureShell(shell);
        shell.setText(Messages.getString("AddSISFilesDialog.DialogTitleText"));			  //$NON-NLS-1$
    }    
    
	/* (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
	 */
	protected Control createDialogArea(Composite parent) {
		
		Composite dialogAreaComposite = (Composite) super.createDialogArea(parent);
		
		//
		// Creating container and layout for it
		//
		container = new Composite(dialogAreaComposite, SWT.NONE);
		GridLayout gdl = new GridLayout(COLUMN_COUNT, false);
		// Settings margins according Carbide branding guideline
		gdl.marginLeft = S60ToolsUIConstants.MARGIN_BTW_FRAME_AND_CONTENTS;
		gdl.marginRight = S60ToolsUIConstants.MARGIN_BTW_FRAME_AND_CONTENTS;
		gdl.marginTop = S60ToolsUIConstants.MARGIN_BTW_FRAME_AND_CONTENTS;
		gdl.marginBottom = S60ToolsUIConstants.MARGIN_BTW_FRAME_AND_CONTENTS;		
		container.setLayout(gdl);
		container.setLayoutData(new GridData(GridData.FILL_BOTH));
		
		//
		// Creating table viewer for showing SIS file entries
		//
		
		sisFilesViewer = createSISFilesTableViewer(container);
	    GridData sisFilesViewerGd = new GridData(GridData.FILL_BOTH);
	    // Spanning as many rows as there are actions buttons on the right
	    sisFilesViewerGd.verticalSpan = 3;
	    sisFilesViewerGd.widthHint = (int) (TABLE_VIEWER_WIDTH_PERCENTAGE * DIALOG_WIDTH);
		sisFilesViewer.getControl().setLayoutData(sisFilesViewerGd);
		sisFilesViewer.setSorter(new SISFileEntryTableViewerSorter());
		// Adding selection change listener
		sisFilesViewer.addSelectionChangedListener(new ISelectionChangedListener(){

			/* (non-Javadoc)
			 * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
			 */
			public void selectionChanged(SelectionChangedEvent event) {
				IStructuredSelection selection = (IStructuredSelection) event.getSelection();
				// Just settings remove button enable/disable state based on the selection state
				if(selection != null && selection.getFirstElement() != null){
					removeButton.setEnabled(true);
				}
				else{
					removeButton.setEnabled(false);					
				}				
			}
			
		});
		
		//
		// Creating buttons
		//
		
		int buttonGridDataStyleBits = GridData.HORIZONTAL_ALIGN_END | GridData.VERTICAL_ALIGN_BEGINNING;
		addButton = createButtonControl(Messages.getString("AddSISFilesDialog.Add_BtnCaptionText"), true, new GridData(buttonGridDataStyleBits)); //$NON-NLS-1$
		removeButton = createButtonControl(Messages.getString("AddSISFilesDialog.Remove_BtnCaptionText"), false, new GridData(buttonGridDataStyleBits));		 //$NON-NLS-1$
		removeAllButton = createButtonControl(Messages.getString("AddSISFilesDialog.RemoveAll_BtnCaptionText"), false, new GridData(buttonGridDataStyleBits)); //$NON-NLS-1$
		
		//
		// Setting providers for table viewer
		//
		
		// Creating content provider
		IStructuredContentProvider sisFilesViewerContentProvider = new IStructuredContentProvider(){

					/* (non-Javadoc)
					 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
					 */
					public Object[] getElements(Object inputElement) {
						return sisFileEntries.values().toArray();
					}
		
					/* (non-Javadoc)
					 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
					 */
					public void dispose() {
						// Not needed but needs to be implemented
					}
		
					public void inputChanged(Viewer viewer, Object oldInput,
							Object newInput) {				
						// Not used but needs to be implemented				
					}
	
				};
				
		// Setting content provider
		sisFilesViewer.setContentProvider(sisFilesViewerContentProvider);
		sisFilesViewer.setInput(sisFilesViewerContentProvider);
		
		// Label provider
		sisFilesViewer.setLabelProvider(new SISFilesViewerLabelProvider());

		// Setting context-sensitive help ID
		AppDepPlugin.setContextSensitiveHelpID(dialogAreaComposite, AppDepHelpContextIDs.APPDEP_DIALOG_ADD_SIS_FILES);
		
		// Dialog are composite ready
		return dialogAreaComposite;
	}

	/**
	 * Creates button with given label text.
	 * @param labelText Label for the button.
	 * @param isEnabled Set to <code>true</code> if button is enabled initially, otherwise <code>false</code>.
	 * @param gridData Grid data to be applied to the button.
	 * @return new instance of Button object.
	 */
	private Button createButtonControl(String labelText, boolean isEnabled, GridData gridData) {
		  Button btn = new Button(container, SWT.PUSH );
		  btn.setText(labelText); 
		  btn.addSelectionListener(this);
		  // What room is left horizontally from table viewer is given for buttons 
		  gridData.widthHint = (int) (0.95 * (1-TABLE_VIEWER_WIDTH_PERCENTAGE) * DIALOG_WIDTH);
		  btn.setLayoutData(gridData);
		  btn.setEnabled(isEnabled);
		  return btn;
	}    
		
	 /* (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.TitleAreaDialog#getInitialSize()
	 */
	protected Point getInitialSize() {
			return new Point(DIALOG_WIDTH, DIALOG_HEIGHT);
	    }
	 
	/* (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.Dialog#create()
	 */
	public void create() {
		super.create();
		// Currently just does creation by super call and stores status
		isCreateCalled = true;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.jface.window.Window#open()
	 */
	public int open(){
		try {
			// Making sure that create is called
			if(!isCreateCalled){
				create();
			}
			showDefaultMessage();			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return super.open();
	}

	/**
	 * Resets possible error messages and show the default message.
	 */
	private void showDefaultMessage() {
		setErrorMessage(null);
		setMessage(DEFAULT_MESSAGE, IMessageProvider.INFORMATION);			
	}

	/**
	 * Informs user that parameters are valid and dialog can be
	 * dismissed with OK button..
	 */
	private void setCompleteOkMessage() {
		setErrorMessage(null);
		setMessage(COMPLETE_MESSAGE, IMessageProvider.INFORMATION);			
	}

	/**
	 * Disables OK button.
	 * This method is guarded against call during construction
	 * when button row has not been created yet and widget is <code>null</code>.
	 */
	private void disableOk() {
		if(okActionBtn != null){
			okActionBtn.setEnabled(false);			
		}
	}

	/**
	 * Enables OK button.
	 * This method is guarded against call during construction
	 * when button row has not been created yet and widget is <code>null</code>.
	 */
	private void enableOk() {
		if(okActionBtn != null){
			okActionBtn.setEnabled(true);
		}
	}	
			
	/* (non-Javadoc)
	 * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
	 */
	public void widgetDefaultSelected(SelectionEvent e) {
		// Not needed in here, but needs to be implemented		
	}

	/* (non-Javadoc)
	 * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
	 */
	public void widgetSelected(SelectionEvent e) {
		Widget widget = e.widget;
		
		if(widget.equals(addButton)){
			queryAndAddNewEntries();
		}
		else if(widget.equals(removeAllButton)){
			removeAllEntries();
		}
		else if(widget.equals(removeButton)){
			// We have made sure by enabling/disabling button in selection 
			// changed listener code that we have valid selection.
			removeSelectedEntries();
		}
	}

	/**
	 * Launches SIS file selection and adds the selected and valid 
	 * SIS files to the entries.
	 */
	private void queryAndAddNewEntries() {
		List<String> illegalSISfilesList = new ArrayList<String>();
		String[] selectedSISFiles = invokeAddSISFilesDialog(getShell());
		for (int i = 0; i < selectedSISFiles.length; i++) {
			String absolutePathFilename = selectedSISFiles[i];
			if(checkSISFileValidity(absolutePathFilename, illegalSISfilesList)){
				addEntry(absolutePathFilename);					
			}
		}
		// Report user about the illegal SIS files that are not added to the table viewer
		notifyIllegalSISFile(illegalSISfilesList);
	}

	/**
	 * Shows an error dialog to user if there are any items 
	 * in given list of illegal SIS files. 
	 * @param illegalSISfilesList List of illegal SIS files.
	 */
	private void notifyIllegalSISFile(List<String> illegalSISfilesList) {
		if(illegalSISfilesList.size() > 0){
			String errMsg = Messages.getString("AddSISFilesDialog.NotSupportedSISFileDialog_ErrMsg"); //$NON-NLS-1$
			for (int i = 0; i < illegalSISfilesList.size(); i++) {
				String fileName = illegalSISfilesList.get(i);
				errMsg = errMsg + "\n" + fileName; //$NON-NLS-1$
			}
			AppDepMessageBox msgBox = new AppDepMessageBox(getShell(), errMsg, SWT.ICON_ERROR);
			msgBox.open();
		}
	}

	/**
	 * Checks validity of SIS file and in case file is not valid 
	 * adds it into list of illegal SIS files passed as parameter. 
	 * @param absolutePathFilename absolute file name to a SIS file.
	 * @param illegalSISfilesList list of illegal SIS files 
	 * @return <code>true</code> if file was a valid and supported SIS file. 
	 */
	private boolean checkSISFileValidity(String absolutePathFilename, List<String> illegalSISfilesList) {
		boolean valid_9x_SISFile = SISFileUtils.isValid_9x_SISFile(absolutePathFilename);
		if(!valid_9x_SISFile){
			illegalSISfilesList.add(absolutePathFilename);
		}
		return valid_9x_SISFile;
	}

	/**
	 * Removes the currently selected entries.
	 * Precondition for calling this method to make sure 
	 * that a valid selection exists.
	 */
	private void removeSelectedEntries() {
		IStructuredSelection selection = (IStructuredSelection) sisFilesViewer.getSelection();
		for (Iterator<?> iterator = selection.iterator(); iterator.hasNext();) {
			SISFileEntry fileEntry = (SISFileEntry) iterator.next();
			sisFileEntries.remove(fileEntry.getFullPathFileName());
		}
		notifyEntriesModified();
	}

	/**
	 * Removes all entries from SIS files table viewer.
	 */
	private void removeAllEntries() {
		sisFileEntries.clear();
		notifyEntriesModified();		
	}

	/**
	 * Adds SIS file entry and update buttons statuses.
	 * @param absolutePathFilename absolute pathname to SIS file to be added.
	 */
	private void addEntry(String absolutePathFilename) {
		File file = new File(absolutePathFilename);
		String location = file.getParentFile().getAbsolutePath();
		String sisFileName = file.getName();
		SISFileEntry fileEntry = new SISFileEntry(location, sisFileName);
		sisFileEntries.put(fileEntry.getFullPathFileName(), fileEntry);
		notifyEntriesModified();
	}
		
	/**
	 * Updates buttons statuses according the current 
	 * status of table entry viewer contents.
	 */
	private void notifyEntriesModified() {
		if(sisFileEntries.size() > 0){
			removeAllButton.setEnabled(true);
			enableOk();
			setCompleteOkMessage();
		}
		else{
			removeAllButton.setEnabled(false);
			showDefaultMessage();			
		}		
		sisFilesViewer.refresh();
	}

	/**
	 * Creates viewer component for showing selected SIS files. 
	 * @param parent Parent composite for the created composite.
	 * @return New <code>TableViewer</code> object instance.
	 */
	protected TableViewer createSISFilesTableViewer(Composite parent) {
		
		ArrayList<S60ToolsTableColumnData> columnDataArr = new ArrayList<S60ToolsTableColumnData>();
		
		//
		// NOTE: Column indices must start from zero (0) and
		// the columns must be added in ascending numeric
		// order.
		//
		columnDataArr.add(new S60ToolsTableColumnData(Messages.getString("AddSISFilesDialog.Name_ColumnTitleText"), //$NON-NLS-1$
														140,
														SISFileEntry.NAME_COLUMN_INDEX,
														SISFileEntryTableViewerSorter.CRITERIA_NAME));
		columnDataArr.add(new S60ToolsTableColumnData(Messages.getString("AddSISFilesDialog.Location_ColumnTitleText"),  //$NON-NLS-1$
														140,
														SISFileEntry.LOCATION_COLUMN_INDEX,
														SISFileEntryTableViewerSorter.CRITERIA_LOCATION));
		
		S60ToolsTableColumnData[] arr 
				= columnDataArr.toArray(
									   new S60ToolsTableColumnData[0]);
		
		S60ToolsTable tbl = S60ToolsTableFactory.create(parent, arr);
		
		TableViewer tblViewer = new TableViewer(tbl.getTableInstance());
		tbl.setHostingViewer(tblViewer);
		
		return tblViewer;
	}
	
	/**
	 * Opens the Open File(s) dialog.
	 * @param sh parent shell
	 * @return file name(s) selected, or <code>null</code> if canceled or errors occurs.
	 */
	public static String [] invokeAddSISFilesDialog(Shell sh){
		//Open file dialog
		FileDialog fdia = new FileDialog(sh, SWT.MULTI);	
		fdia.setText(Messages.getString("AddSISFilesDialog.SISFileBrowseDialog_TitleText")); //$NON-NLS-1$
		String [] extensions = new String[] {"*.SIS", "*.SISX"}; //$NON-NLS-1$ //$NON-NLS-2$
		fdia.setFilterExtensions(extensions);
		String file = fdia.open();
		//If there is at least one file selected
		if(file != null){
			//get all selected file names
			String [] files = fdia.getFileNames();
			String path = fdia.getFilterPath();//Path (dir) where file(s) are
			String [] filesWithPath = new String[files.length];
			//Create absolute file paths <path>\<filename>
			for (int i = 0; i < files.length; i++) {
				filesWithPath[i] = path + File.separatorChar + files[i];
			}
			return filesWithPath;
		}
		else{
			//User has canceled the operation
			return null;
		}
	}

	/**
	 * Returns currently selected SIS files as string array containing absolute path names.
	 * @return currently selected SIS files.
	 */
	public String[] getSelectedSISFiles() {
		return sisFileEntries.keySet().toArray(new String[0]);
	}

	/**
	 * Sets initial set of SIS file to be shown for the user.
	 * Should be called before calling <code>open()</code> method.
	 * @param initialSISFileSet initial file set to be shown for the user.
	 */
	public void setInitialSISFileSet(String[] initialSISFileSet) {
		if(initialSISFileSet != null && initialSISFileSet.length > 0){
			enableOk(); // Enabling OK because there is some content available
			setCompleteOkMessage();
			for (int i = 0; i < initialSISFileSet.length; i++) {
				String fileFullPathName = initialSISFileSet[i];
				addEntry(fileFullPathName);
			}					
		}
	}
	
}