crashanalysis/crashanalyser/com.nokia.s60tools.crashanalyser/src/com/nokia/s60tools/crashanalyser/ui/wizards/FilesSelectionPage.java
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Tue, 24 Aug 2010 14:01:48 +0300
changeset 16 72f198be1c1d
parent 0 5ad7ad99af01
permissions -rw-r--r--
Crash Analyser Carbide Extension 1.4.0

/*
* Copyright (c) 2008 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.crashanalyser.ui.wizards;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.browser.*;
import org.eclipse.swt.events.*;
import org.eclipse.ui.PlatformUI;
import com.nokia.s60tools.ui.wizards.S60ToolsWizardPage;
import com.nokia.s60tools.crashanalyser.model.*;
import com.nokia.s60tools.crashanalyser.resources.HelpContextIDs;
import com.nokia.s60tools.crashanalyser.files.*;
import java.util.*;
import java.text.Collator;
import java.util.Locale;
import java.text.DateFormat;
import java.util.Date;

/**
 * This is the 2nd page in the wizard. This page contains a table from which
 * user selects the crash files he/she wants to import.
 */
public class FilesSelectionPage extends S60ToolsWizardPage implements SelectionListener{

	Button buttonSelectDeselect;
	Table tableFiles;
	TableColumn tableColumnCreated;
	TableColumn tableColumnType;
	TableColumn tableColumnRomId;
	TableColumn tableColumnFile;
	Label labelFileInfoTitle;
	Browser browserFileInfo;
	DecoderEngine engine;
	Composite composite;
	List<CrashFileBundle> files = null;
	String[] filesToBeShown = null;
	public boolean romIdsMatch = true;
	static final int TABLE_COLUMN_CREATED = 0;
	static final int TABLE_COLUMN_TYPE = 1;
	static final int TABLE_COLUMN_ROMID = 2;
	static final int TABLE_COLUMN_FILE = 3;
	static final int TABLE_COLUMN_COUNT = 4;
	
	/**
	 * Constructor
	 * @param decEng decoder engine
	 */
	public FilesSelectionPage(DecoderEngine decEng, String[] showOnlyTheseFiles) {
		super("");
			
		setTitle("Select Files");
			
		setDescription("Select crash files to be imported.");

		// User cannot finish the page before some valid 
		// selection is made.
		setPageComplete(false);
		engine = decEng;
		filesToBeShown = showOnlyTheseFiles;
	}

	public void showOnlyTheseFiles(String[] files) {
		filesToBeShown = files;
	}
	
	@Override
	public void recalculateButtonStates() {
		// no implementation needed
	}

	@Override
	public void setInitialFocus() {
		tableFiles.setFocus();
	}

	/**
	 * Creates all UI controls
	 */
	public void createControl(Composite parent) {
		composite =  new Composite(parent, SWT.NULL);
		
	    // create the desired layout for this wizard page
		GridLayout gl = new GridLayout();
		gl.numColumns = 1;
		composite.setLayout(gl);

		// Table
		tableFiles = new Table(composite, SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION | SWT.CHECK | SWT.V_SCROLL | SWT.H_SCROLL);
		tableFiles.setLinesVisible (true);
		tableFiles.setHeaderVisible (true);
		
		// Created column
		tableColumnCreated = new TableColumn (tableFiles, SWT.NONE);
		tableColumnCreated.setText("Created");
		tableColumnCreated.addSelectionListener(this);
		
		// Type column
		tableColumnType = new TableColumn (tableFiles, SWT.NONE);
		tableColumnType.setText("Type");
		tableColumnType.addSelectionListener(this);

		// ROM ID column
		tableColumnRomId = new TableColumn (tableFiles, SWT.NONE);
		tableColumnRomId.setText("ROM ID");
		tableColumnRomId.addSelectionListener(this);

		// File column
		tableColumnFile = new TableColumn (tableFiles, SWT.NONE);
		tableColumnFile.setText("File");
		tableColumnFile.addSelectionListener(this);
		
		autoSizeTableColumns();
		
		GridData treeGD = new GridData(GridData.FILL_BOTH);
		tableFiles.setLayoutData(treeGD);		
		tableFiles.addSelectionListener(this);
		
		// Select/Deselect button
		buttonSelectDeselect = new Button(composite, SWT.PUSH);
		buttonSelectDeselect.setText("Select/Unselect");
		buttonSelectDeselect.addSelectionListener(this);

		// File info title
		labelFileInfoTitle = new Label(composite, SWT.LEFT);
		labelFileInfoTitle.setText("File Info");
		
		// File info
		browserFileInfo = new Browser(composite, SWT.BORDER);
		GridData textGD = new GridData(GridData.FILL_HORIZONTAL);
		textGD.heightHint = 150;
		browserFileInfo.setLayoutData(textGD);
		browserFileInfo.setText("");
		
		setHelps();
		
		setInitialFocus();
		
		setControl(composite);		
		
		updateButtons();
	}
	
	/**
	 * Autos sizes all table columns
	 */
	void autoSizeTableColumns() {
		for (int i = 0; i < TABLE_COLUMN_COUNT; i++) {
			tableFiles.getColumn(i).pack();
		}		
	}
	
	/**
	 * Loads the table with files given by decoder engine
	 */
	public void loadTable() {
		tableFiles.removeAll();
		files = engine.getCrashFiles();
		if (files == null || files.size() < 1) {
			setErrorMessage("No crash files found.");
		} else {
			for (int i = 0; i < files.size(); i++) {
				CrashFileBundle file = files.get(i);
				String fileType = "";
				String fileName = "";
				// summary xml file
				if (file.isPartiallyDecoded()) {
					SummaryFile summaryFile = file.getSummaryFile();
					fileType = summaryFile.getSourceFileType();
					fileName = summaryFile.getSourceFileName();
				// .crashxml file
				} else {
					CrashFile crashfile = file.getCrashFile();
					fileType = crashfile.getSourceFileType();
					fileName = crashfile.getFileName();
				}
				// if user has drag&dropped multiple files, we have scanned the whole
				// folder, but we should show only the dragged ones
				if (!shouldCrashFileBeShown(fileName))
					continue;
				TableItem item = new TableItem (tableFiles, SWT.NONE);
				item.setText(0, file.getTime());
				item.setText(1, fileType);
				item.setText(2, file.getRomId());
				item.setText(3, fileName);
				item.setData(file);
				item.setChecked(true);
			}
			autoSizeTableColumns();
		}
		browserFileInfo.setText("");
		
		if (tableFiles.getItemCount() > 0) {
			tableFiles.select(0);
			showFileInfo();
		}
	}
	
	/**
	 * Checks whether given crash file should be shown in table. if user has drag&dropped 
	 * multiple files, we have scanned the whole folder, but we should show only the dragged ones. 
	 * @param fileName file to be checked
	 * @return true if file should be shown, false if not
	 */
	boolean shouldCrashFileBeShown(String fileName) {
		if (filesToBeShown != null && filesToBeShown.length > 0) {
			for (int i = 0; i < filesToBeShown.length; i++) {
				if (fileName.equalsIgnoreCase(FileOperations.getFileNameWithExtension(filesToBeShown[i])))
					return true;
			}
			return false;

		} else {
			return true;
		}
	}

	public void widgetDefaultSelected(SelectionEvent e) {
		// no implementation needed
	}

	public void widgetSelected(SelectionEvent e) {
		// Select/Unselect button pressed
		if (e.widget == buttonSelectDeselect) {
			TableItem[] items = tableFiles.getItems();
			if (items != null) {
				boolean checkAll = true;
				// check whether items needs to be checked or unchecked
				for (int i = 0; i < items.length; i++) {
					if (items[i].getChecked()) {
						checkAll = false;
						break;
					}
				}
				
				// check/uncheck all items
				for (int i = 0; i < items.length; i++)
					items[i].setChecked(checkAll);
			}
			showFileInfo();
			updateButtons();
			
		// table item selected/checked/unchecked
		} else if (e.widget == tableFiles) {
			// item was checked/unchecked
			if (e.detail == SWT.CHECK) {
				tableFiles.setSelection((TableItem)e.item);
				updateButtons();
			}
			showFileInfo();
			
		// table column presses -> sort
		} else if (e.widget == tableColumnCreated ) {
			sortTableByColumn(TABLE_COLUMN_CREATED, tableColumnCreated);
		} else if (e.widget == tableColumnType) {
			sortTableByColumn(TABLE_COLUMN_TYPE, tableColumnType);
		} else if (e.widget == tableColumnRomId) {
			sortTableByColumn(TABLE_COLUMN_ROMID, tableColumnRomId);
		} else if (e.widget == tableColumnFile) {
			sortTableByColumn(TABLE_COLUMN_FILE, tableColumnFile);
		}
	}
	
	/**
	 * Sorts table by given column number
	 * @param column column number
	 * @param col column item
	 */
	void sortTableByColumn(int column, TableColumn col) {
		TableItem[] items = tableFiles.getItems();
		Collator collator = Collator.getInstance(Locale.getDefault());

		TableColumn sortColumn = tableFiles.getSortColumn();
		
		// column is sorted for the "first time" or column is sorted UP. Sort column DOWN.
		if (sortColumn == null || !col.equals(sortColumn) || tableFiles.getSortDirection() == SWT.UP) {
			for (int i = 1; i < items.length; i++) {
				String value1 = items[i].getText(column);
				for (int j = 0; j < i; j++) {
					String value2 = items[j].getText(column);
					// time compare
					if (column == TABLE_COLUMN_CREATED) {
						try {
							DateFormat date = DateFormat.getInstance();
							Date d1 = date.parse(value1);
							Date d2 = date.parse(value2);
							if (d1 != null && d2 != null && d1.compareTo(d2) < 0) {
								boolean checked = items[i].getChecked();
								String[] values = { items[i].getText(0), items[i].getText(1), items[i].getText(2), items[i].getText(3)};
								items[i].dispose();
								TableItem item = new TableItem(tableFiles, SWT.NONE, j);
								item.setText(values);
								item.setChecked(checked);
								items = tableFiles.getItems();
								break;
							}
						} catch (Exception e) {
							e.printStackTrace();
						}
					// string compare
					} else {
						if (collator.compare(value1, value2) < 0) {
							boolean checked = items[i].getChecked();
							String[] values = { items[i].getText(0), items[i].getText(1), items[i].getText(2), items[i].getText(3)};
							items[i].dispose();
							TableItem item = new TableItem(tableFiles, SWT.NONE, j);
							item.setText(values);
							item.setChecked(checked);
							items = tableFiles.getItems();
							break;
						}
					}
				}
			}
			tableFiles.setSortColumn(col);
			tableFiles.setSortDirection(SWT.DOWN);
		
		// Reverse rows
		} else {
			int index = items.length-1;
			for (int i = 0; i < items.length-1; i++) {
				boolean checked = items[index].getChecked();
				String[] values = { items[index].getText(0), items[index].getText(1), items[index].getText(2), items[index].getText(3)};
				items[index].dispose();
				TableItem item = new TableItem(tableFiles, SWT.NONE, i);
				item.setText(values);
				item.setChecked(checked);
				items = tableFiles.getItems();
			}
			
			tableFiles.setSortColumn(col);
			tableFiles.setSortDirection(SWT.UP);
		}
	}
	
	/**
	 * Updates next, finish button states
	 */
	void updateButtons() {
		try {
			getWizard().getContainer().updateButtons();
		} catch (Exception E) {
		}
	}
	
	/**
	 * Show information about the currently selected file
	 */
	void showFileInfo() {
		int selected = tableFiles.getSelectionIndex();
		if (selected >= 0) {
			CrashFileBundle cfb = (CrashFileBundle)tableFiles.getItem(selected).getData();
			browserFileInfo.setText(HtmlFormatter.formatHtmlStyle(labelFileInfoTitle.getFont(), 
																	cfb.getDescription(false)));
		} else {
			browserFileInfo.setText("");
		}
	}

	/**
	 * Checks whether we can press Next button
	 */
	public boolean canFlipToNextPage() {
		try {
			// decoder engine contains no files (shouldn't happen)
			if (files == null || files.size() < 1)
				return false;
			
			if (onlyCrashxmlFilesSelected())
			{
				// If there are just crashxml files then we do not need symbol files ->
				// only Finish button is enabled. 
				return false;
			}
			
			TableItem[] items = tableFiles.getItems();
			// no items in table (shouldn't happen)
			if (items == null) {
				return false;
			// table contains items
			} else {
				String romId = "";
				boolean selectedFiles = false;
				boolean hasMultipleRomIds = false;
				// check whether user is trying to import files which 
				// have different ROM IDs
				for (int i = 0; i < items.length; i++) {
					CrashFileBundle file = (CrashFileBundle)items[i].getData();
					if (!items[i].getChecked() || file == null)
						continue;

					selectedFiles = true;
					
					// ignore ROM ID of .crashxml file
					if (file.isFullyDecoded())
						continue;
					
					//ignore if file has no rom id
					if ("".equals(file.getRomId()))
						continue;
					
					if (!"".equals(romId) && !file.getRomId().equalsIgnoreCase(romId)) {
						hasMultipleRomIds = true;
					}
					romId = file.getRomId();
				}
				
				// don't allow to proceed when multiple different ROM ID file are selected
				if (hasMultipleRomIds) {
					this.setErrorMessage("ROM IDs of selected files do not match. Please select only files which have same ROM IDs.");
					return false;
				} else {
					this.setErrorMessage(null);
				}
				
				// no checked files
				if (!selectedFiles)
					return false;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}		
	
	/**
	 * Checks whether Finish button can be enabled. Finish button can be
	 * enabled if user is importing only already decoded files (.crashxml files).
	 * 
	 * @return true if Finish button can be enable, false if not
	 */
	public boolean canFinish() {
		try {
			// if no files in this page (shouldn't happen)
			if (files == null || files.size() < 1)
				return false;
			
			TableItem[] items = tableFiles.getItems();
			// if no files in table (shouldn't happen)
			if (items == null) {
				return false;
			} else {
				boolean hasAnalyzedFiles = false;
				boolean hasUndecodedFiles = false;
				// go through all checked files in the table
				for (int i = 0; i < items.length; i++) {
					if (!items[i].getChecked())
						continue;
					
					CrashFileBundle file = (CrashFileBundle)items[i].getData();
					if (file != null) {
						if (file.isPartiallyDecoded()) {
							hasUndecodedFiles = true;
						} else {
							hasAnalyzedFiles = true;
						}
					}
				}
				
				// only .crashxml files are selected, we can show Finish button
				if (hasAnalyzedFiles && !hasUndecodedFiles)
					return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	/**
	 * Checks whether only .crashxml files are selected in the table 
	 * @return true if only .crashxml files are selected, false if not
	 */
	public boolean onlyCrashxmlFilesSelected() {
		try {
			// if no files in this page (shouldn't happen)
			if (files == null || files.size() < 1)
				return false;
			
			TableItem[] items = tableFiles.getItems();
			// if no files in table (shouldn't happen)
			if (items == null) {
				return false;
			} else {
				boolean onlyCrashxmlFiles = true;
				// go through all checked files in the table
				for (int i = 0; i < items.length; i++) {
					if (!items[i].getChecked())
						continue;
					CrashFileBundle file = (CrashFileBundle)items[i].getData();
					if (file.isPartiallyDecoded()) {
						onlyCrashxmlFiles = false;
						break;
					}
				}
				
				if (onlyCrashxmlFiles)
					return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return false;
	}
	
	/**
	 * Returns indexes of those Crash files which are selected (checked) in the table
	 * @return indexes of those Crash files which are selected (checked) in the table
	 */
	public List<Integer> getFileIndexes() {
		List<Integer> indexes = new ArrayList<Integer>();
		
		TableItem[] items = tableFiles.getItems();
		// if no files in table (shouldn't happen)
		if (items == null) {
			return null;
		} else {
			// go through all checked files in the table
			for (int i = 0; i < items.length; i++) {
				if (items[i].getChecked())
					indexes.add(i);
			}
		}
		
		if (indexes.isEmpty()) {
			return null;
		} else {
			return indexes;
		}
	}
	
	/**
	 * Sets this page's context sensitive helps
	 *
	 */
	protected void setHelps() {
		PlatformUI.getWorkbench().getHelpSystem().setHelp(tableFiles,
				HelpContextIDs.CRASH_ANALYSER_HELP_IMPORT_CRASH_FILES);
		
		PlatformUI.getWorkbench().getHelpSystem().setHelp(browserFileInfo,
				HelpContextIDs.CRASH_ANALYSER_HELP_IMPORT_CRASH_FILES);		

		PlatformUI.getWorkbench().getHelpSystem().setHelp(buttonSelectDeselect,
				HelpContextIDs.CRASH_ANALYSER_HELP_IMPORT_CRASH_FILES);		
	}
}