crashanalysis/crashanalyser/com.nokia.s60tools.crashanalyser/src/com/nokia/s60tools/crashanalyser/ui/wizards/CrashAnalyserWizard.java
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:06:45 +0200
changeset 0 5ad7ad99af01
child 4 615035072f7e
permissions -rw-r--r--
Initial version of CrashAnalyser under EPL

/*
* 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.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbench;
import com.nokia.s60tools.ui.wizards.S60ToolsWizard;
import com.nokia.s60tools.crashanalyser.model.*;
import com.nokia.s60tools.crashanalyser.plugin.CrashAnalyserPlugin;
import com.nokia.s60tools.crashanalyser.resources.*;
import com.nokia.s60tools.crashanalyser.ui.views.*;
import com.nokia.s60tools.crashanalyser.data.*;
import com.nokia.s60tools.crashanalyser.export.ICrashFileProvider;

import java.util.*;

/**
 * Crash Analyser Wizard is used for collecting required data from user so that CrashAnalyser.exe 
 * can be executed.
 *
 */
public class CrashAnalyserWizard extends S60ToolsWizard {

	static private final ImageDescriptor bannerImgDescriptor = ImageResourceManager.getImageDescriptor(ImageKeys.WIZARD_BANNER);
	List<CrashFileBundle> filesToDecode = null;
	IWizardPage returnPage = null;
	ErrorLibrary errorLibrary;
	FileOrPathSelectionPage crashFileOrFolderSelectionPage = null;
	FilesSelectionPage filesSelectionPage = null;
	ParameterFilesPage parameterFilesPage = null;
	DecoderEngine engine;
	String userProvidedCrashFileOrFolder;
	boolean crashAnalyserExeExecutionSuccess = false;
	boolean readCrashFileFromDevice = false;
	String providedFileOrFolder = "";
	String errorMessage = "";
	String[] filesToBeSelectedOnSecondPage = null;
	final String EXTENSION_FILE_PROVIDER = "fileprovider"; //$NON-NLS-1$
	ICrashFileProvider fileProvider = null;
	/**
	 * Constructor
	 * @param filesToBeDecoded list of files to be decoded. If null is passed, wizard will start from the beginning. 
	 * If list contains files, then wizard is started from the 3rd page
	 * @param library error library
	 */
	public CrashAnalyserWizard(List<CrashFileBundle> filesToBeDecoded, ErrorLibrary library) {
		super(bannerImgDescriptor);
		engine = new DecoderEngine();
		filesToDecode = filesToBeDecoded;
		errorLibrary = library;
		readFileProvider();
	}
	
	/**
	 * Constructor (used in drag&drop cases)
	 * @param prefilledFileOrFolder single file or folder which is filled to 1st wizard page
	 * @param filesToSelect only these files should be shown in 2nd wizard page
	 * @param library error library
	 */
	public CrashAnalyserWizard(String prefilledFileOrFolder, String[] filesToSelect, ErrorLibrary library) {
		super(bannerImgDescriptor);
		engine = new DecoderEngine();
		filesToDecode = null;
		errorLibrary = library;
		providedFileOrFolder = prefilledFileOrFolder;
		filesToBeSelectedOnSecondPage = filesToSelect;
		readFileProvider();
	}
	
	public void init(IWorkbench arg0, IStructuredSelection arg1) {
		// No implementation needed
	}

	
	@Override
	public boolean needsProgressMonitor() {
		return true;
	}	
	
	@Override
	public void addPages() {
		// we are doing a full import, add all pages
		if (filesToDecode == null) {
			crashFileOrFolderSelectionPage = 
				new FileOrPathSelectionPage(engine, 
											errorLibrary, 
											providedFileOrFolder, 
											this,
											fileProvider);
			addPage(crashFileOrFolderSelectionPage);
			
			filesSelectionPage = new FilesSelectionPage(engine, filesToBeSelectedOnSecondPage);
			addPage(filesSelectionPage);
			
			parameterFilesPage = new ParameterFilesPage(engine, false);
			addPage(parameterFilesPage);
		
			setWindowTitle("Crash Analyser - Crash File Import Wizard");
			
			// files were drag&dropped, "press next automatically"
			if (!"".equals(providedFileOrFolder))
				moveToSecondPage();
			
		// we are re-decoding files provided by user, show only "3rd" page
		} else {
			parameterFilesPage = new ParameterFilesPage(engine, true);
			addPage(parameterFilesPage);
			
			engine.setCrashFiles(filesToDecode);
			
			setWindowTitle("Crash Analyser - Re-Decoding Selected Files");
		}
	}
	
	public void moveToSecondPageRequest(String[] showOnlyTheseFiles) {
		filesSelectionPage.showOnlyTheseFiles(showOnlyTheseFiles);
		moveToSecondPage();
	}
	
	public void moveToSecondPageRequest(boolean readFilesFromDevice) {
		readCrashFileFromDevice = readFilesFromDevice;
		moveToSecondPage();
	}
	
	/**
	 * When user has drag&dropped files, we "automatically press next" 
	 * in the first wizard page.
	 */
	void moveToSecondPage() {
		Runnable showWizardRunnable = new Runnable(){
			public void run(){
				IWizardPage nextPage = getNextPage(crashFileOrFolderSelectionPage);
				if (nextPage != null)
					getContainer().showPage(nextPage);
			}
		};
		
		Display.getDefault().asyncExec(showWizardRunnable);   		
	}
	
	
	@Override
	public boolean performFinish() {
		boolean fullImport = crashFileOrFolderSelectionPage != null;
		
		// full import is the case when wizard is started from page 1
		if (fullImport) {
			// if Finish was pressed in 2nd wizard page, symbol page (3rd page) was not used
			// false here would mean that only "decoded" files (.crashxml) files were selected.
			boolean symbolPageWasUsed = this.getContainer().getCurrentPage() != filesSelectionPage;
	
			DecodingData decodingData = new DecodingData();
			decodingData.importingFiles = true;
	
			// save 1st page
			crashFileOrFolderSelectionPage.saveUserEnteredData();

			decodingData.crashFileIndexes = filesSelectionPage.getFileIndexes();
			
			if (symbolPageWasUsed) {
				// save 3rd page
				parameterFilesPage.saveUserEnteredData();
				decodingData.symbolFiles = parameterFilesPage.getSymbolFiles();
				decodingData.mapFilesFolder = parameterFilesPage.getMapFilesFolder();
				decodingData.mapFilesZip = parameterFilesPage.getMapFilesZip();
				decodingData.imageFiles = parameterFilesPage.getImageFiles();
			}
			
			decodingData.errorLibrary = errorLibrary;
			
			engine.setDecodingData(decodingData);
			
		// not full import is the case when files are Re-Decoded via MainView
		} else {
			DecodingData decodingData = new DecodingData();
			decodingData.importingFiles = false;

			// save 3rd page
			parameterFilesPage.saveUserEnteredData();
			decodingData.symbolFiles = parameterFilesPage.getSymbolFiles();
			decodingData.mapFilesFolder = parameterFilesPage.getMapFilesFolder();
			decodingData.mapFilesZip = parameterFilesPage.getMapFilesZip();
			decodingData.imageFiles = parameterFilesPage.getImageFiles();
			
			decodingData.errorLibrary = errorLibrary;
			
			engine.setDecodingData(decodingData);
		}

		MainView mainView = MainView.showAndReturnYourself();
		if (mainView != null) {
			mainView.startDecoding(engine);
		}

		return true;
	}
	
	public boolean canFinish()
	{
		if (this.getContainer().getCurrentPage() == filesSelectionPage) {
			return filesSelectionPage.canFinish();
		} else if (this.getContainer().getCurrentPage() == parameterFilesPage) {
			return parameterFilesPage.canFinish();
		} else {
			return false;
		}
	}
	
	public IWizardPage getNextPage(IWizardPage page) {
		// We are moving from 1st page to 2nd page.
		// We need to run CrashAnalyser.exe to get summary data for crash files
		if(page.equals(crashFileOrFolderSelectionPage)){
			returnPage = null;
			userProvidedCrashFileOrFolder = crashFileOrFolderSelectionPage.getSelectedFileOrFolder();
			crashAnalyserExeExecutionSuccess = false;
			try {
				getContainer().run(true, false, new IRunnableWithProgress() {
					public void run(IProgressMonitor monitor) {
						errorMessage = "";
						// run CrashAnalyser.exe for summary information for selected file(s).
						if (readCrashFileFromDevice && fileProvider != null) {
							errorMessage = fileProvider.executeFunctionality(DecoderEngine.getTemporaryCrashFileFolder(true));
							userProvidedCrashFileOrFolder = DecoderEngine.getTemporaryCrashFileFolder(false);
						}
						crashAnalyserExeExecutionSuccess = 
							engine.processSummaryInfoForFiles(userProvidedCrashFileOrFolder, errorLibrary, monitor);
					}
				}
				);
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			// CrashAnalyser.exe execution was successful -> return next wizard page
			if (crashAnalyserExeExecutionSuccess) {
				crashFileOrFolderSelectionPage.errorInProcessingNextPress(false);
				filesSelectionPage.loadTable();
				returnPage = filesSelectionPage;
			// CrashAnalyser.exe execution was unsuccessful, don't proceed to next 
			// wizard page -> return current page
			} else {
				if (readCrashFileFromDevice) {
					if ("".equals(errorMessage)) {
						showMessage("The device did not contain any crash files");
					} else {
						showMessage("Could not read crash files. Please check PC Suite connection.\n\nError:\n" + errorMessage);
					}
				} else {
					crashFileOrFolderSelectionPage.errorInProcessingNextPress(true);
				}
				returnPage = crashFileOrFolderSelectionPage;
				filesSelectionPage.showOnlyTheseFiles(null);
			}			

			readCrashFileFromDevice = false;
			
			return returnPage;
		}
		// We are moving from 2nd page to 3rd/4th page.
		else if (page.equals(filesSelectionPage)) {
			// only (already "decoded") output.crashxml files have been selected in 2nd page.
			// Skip parameterFiles page and go to additionalSettingsPage, because we don't have
			// to query for symbols etc. because there is nothing to decode.
			return parameterFilesPage;
		}

		return null;
	}
	
	/**
	 * Shows a message box with given message
	 * @param message
	 */
	private void showMessage(String message) {
		MessageDialog.openInformation(
			getShell(),
			"Crash Analyser",
			message);
	}
	
	@Override
	public boolean performCancel() {
		DecoderEngine.getTemporaryCrashFileFolder(true);
		return super.performCancel();
	}

	/**
	 * Tries to find plugins which are File Providers. Selectes the first found
	 * File provider plugin.
	 */
	void readFileProvider() {
		try {
			IExtensionRegistry er = Platform.getExtensionRegistry();
			IExtensionPoint ep = 
				er.getExtensionPoint(CrashAnalyserPlugin.PLUGIN_ID, EXTENSION_FILE_PROVIDER);
			IExtension[] extensions = ep.getExtensions();
			
			// if plug-ins were found.
			if (extensions != null && extensions.length > 0) {
				
				// read all found trace providers
				for (int i = 0; i < extensions.length; i++) {
					IConfigurationElement[] ce = extensions[i].getConfigurationElements();
					if (ce != null && ce.length > 0) {
						try {
							ICrashFileProvider provider = (ICrashFileProvider)ce[0].createExecutableExtension("class");
							// we support only one trace provider
							if (provider != null) {
								fileProvider = provider;
								break;
							}
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}