crashanalysis/crashanalyser/com.nokia.s60tools.crashanalyser/src/com/nokia/s60tools/crashanalyser/ui/editors/SummaryPage.java
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Tue, 24 Aug 2010 14:01:48 +0300
changeset 16 72f198be1c1d
parent 4 615035072f7e
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.editors;

import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.browser.*;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.TableCursor;
import org.eclipse.ui.PlatformUI;

import com.nokia.s60tools.crashanalyser.files.*;
import com.nokia.s60tools.crashanalyser.files.SummaryFile.ContentType;
import com.nokia.s60tools.crashanalyser.model.HtmlFormatter;
import com.nokia.s60tools.crashanalyser.containers.Summary;
import com.nokia.s60tools.crashanalyser.containers.Process;
import com.nokia.s60tools.crashanalyser.containers.Thread;
import com.nokia.s60tools.crashanalyser.containers.Stack;
import com.nokia.s60tools.crashanalyser.containers.RegisterSet;
import com.nokia.s60tools.crashanalyser.resources.HelpContextIDs;

import java.util.List;
import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.swt.graphics.FontData;

/**
 * Crash Data page in Crash Visualiser editor. 
 *
 */
public class SummaryPage {
	
	// summary group UI items
	Table tableSummary;

	// exit info group UI items
	Label labelExitType;
	Label labelPanicSummary;
	Browser browserPanicDescription;
		
	SummaryFile crashFile = null;
	FontRegistry fontRegistry;
	Thread selectedThread = null;
	
	/**
	 * Creates the page
	 * @param parent composite
	 * @param file summary file
	 * @return composite
	 */
	public Composite createPage(Composite parent, SummaryFile file) {
		crashFile = file;
		return doCreate(parent);
	}
	
	/**
	 * Creates the page
	 * @param parent composite
	 * @return composite
	 */
	public Composite createPage(Composite parent) {
		return doCreate(parent);
	}
	
	public void update() {
	//	AutoSizeCallStackTableCells();
	}
	
	/**
	 * Loads data from given file into UI elements.
	 * @param file crash file
	 */
	public void setFile(CrashFile file) {
		if (file != null) {
			crashFile = file;
			loadSummaryTable();
			loadExitInfo();
		}
	}
	
	/**
	 * Creates all UI elements to the page
	 * @param parent
	 * @return composite
	 */
	Composite doCreate(Composite parent) {
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		parent.setLayout(layout);
		parent.setLayoutData(new GridData(GridData.FILL_BOTH));
		fontRegistry = new FontRegistry(Display.getCurrent());
		fontRegistry.put("monospace", new FontData[]{new FontData("Courier", 8, SWT.NORMAL)});
		SashForm sashFormMain = new SashForm(parent, SWT.VERTICAL);
		sashFormMain.setLayoutData(new GridData(GridData.FILL_BOTH));
		createSummaryGroup(sashFormMain);
		createExitInfoGroup(sashFormMain);
		
		setHelps();
		
		return parent;
	}
	
	/**
	 * Creates summary group
	 * @param parent
	 */
	void createSummaryGroup(Composite parent) {
		Group groupSummary = new Group(parent, SWT.NONE);
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		groupSummary.setLayout(layout);
		groupSummary.setText("General");
		GridData groupGD = new GridData(GridData.FILL_HORIZONTAL);
		groupGD.heightHint = 200;
		groupSummary.setLayoutData(groupGD);
		
		tableSummary = new Table(groupSummary, SWT.BORDER  | SWT.FULL_SELECTION |  
				SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY );
		tableSummary.setHeaderVisible(true);
		tableSummary.setLinesVisible(true);
		TableColumn col1 = new TableColumn(tableSummary, SWT.LEFT);
		col1.setWidth(130);
		TableColumn col2 = new TableColumn(tableSummary, SWT.LEFT);
		col2.setWidth(300);
		tableSummary.setLayoutData(new GridData(GridData.FILL_BOTH));
		
		tableSummary.setFont(fontRegistry.get("monospace"));
		
		
		final TableCursor cursor = new TableCursor(tableSummary, SWT.NONE);
		TableKeyListener keyListener = new TableKeyListener(tableSummary, cursor);
		tableSummary.addKeyListener(keyListener);
		cursor.addKeyListener(keyListener);
                        
		loadSummaryTable();		
	}
	
	/**
	 * Creates exit info group
	 * @param parent
	 */
	void createExitInfoGroup(Composite parent) {
		Group groupExitInfo = new Group(parent, SWT.NONE);
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		groupExitInfo.setLayout(layout);
		groupExitInfo.setText("Exit Info");
		GridData groupGD = new GridData(GridData.FILL_HORIZONTAL);
		groupGD.heightHint = 200;
		groupExitInfo.setLayoutData(groupGD);
		
		labelExitType = new Label(groupExitInfo, SWT.NONE);
		labelExitType.setText("Exit Type:");
		labelExitType.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		
		labelPanicSummary = new Label(groupExitInfo, SWT.BORDER);
		labelPanicSummary.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		
		browserPanicDescription = new Browser(groupExitInfo, SWT.BORDER);
		browserPanicDescription.setLayoutData(new GridData(GridData.FILL_BOTH));
		
		loadExitInfo();
	}
	
	
	/**
	 * Packs all columns for given table
	 * @param table table which columns are to be packed
	 */
	void AutoSizeTableCells(Table table) {
		for (int i = 0; i < table.getColumnCount(); i++) {
			table.getColumn(i).pack();
		}
	}
	
	/**
	 * Loads data into summary table
	 */
	void loadSummaryTable() {
		// if there is no crashFile given, we are waiting for data to be loaded.
		// Show 'Loading file' text in summary table until we get data.
		if (crashFile == null) {
			TableItem item = new TableItem(tableSummary, SWT.NONE);
			item.setText(new String[] {"Loading file. Please wait.", ""});
		// we have crash data, load summary table
		} else {
			tableSummary.removeAll();
		
			// show the data of crashed process
			Process process = null;
			if (crashFile.getThread() != null) {
				process = crashFile.getProcessByThread(crashFile.getThread().getId());
			} else {
				process = crashFile.getCrashedProcess();
			}
			
			if (process != null) {
				newSummaryTableItem("PROCESS", process.getName(), true);
				
				// current UI support only one thread, so show the first thread of first process
				Thread thread = null;
				if (crashFile.getThread() != null) {
					// Show only thread information (no crash info)
					thread = crashFile.getThread();
				} else {
					thread = crashFile.getCrashedThread();
				}
				
				if (thread != null) {
					selectedThread = thread;
					newSummaryTableItem("THREAD", thread.getFullName(), true);
					newSummaryTableItem("STACK POINTER", thread.getStackPointer(), true);
					newSummaryTableItem("LINK REGISTER", thread.getLinkRegister(), true);
					newSummaryTableItem("PROGRAM COUNTER", thread.getProgramCounter(), true);
				}
			}
			
			Summary crashSummary = crashFile.getSummary();
			if (crashSummary != null) {
				// there can be several software version informations, show them all
				String[] versions = crashSummary.getSwVersion();
				if (versions != null && versions.length > 0) {
					for (int i = 0; i < versions.length; i++) {
						newSummaryTableItem("SW VERSION", versions[i], false);
					}
				}
				// there can be several hardware version informations, show them all
				versions = crashSummary.getHwVersion();
				if (versions != null && versions.length > 0) {
					for (int i = 0; i < versions.length; i++) {
						newSummaryTableItem("HW VERSION", versions[i], false);
					}
				}
				newSummaryTableItem("PRODUCT TYPE", crashSummary.getProductType(), true);
				newSummaryTableItem("PRODUCT CODE", crashSummary.getProductCode(), true);
				newSummaryTableItem("LANGUAGE", crashSummary.getLanguage(), true);
				newSummaryTableItem("IMEI", crashSummary.getImei(), true);
				newSummaryTableItem("CRASH TIME", crashSummary.getCrashTime(), true);
				newSummaryTableItem("CRASH DATE", crashSummary.getCrashDate(), true);
				newSummaryTableItem("ROM ID", crashSummary.getRomId(), true);
				newSummaryTableItem("AVAILABLE MEMORY", crashSummary.getFreeRam(), true);
				newSummaryTableItem("PSN", crashSummary.getSerialNumber(), true);
				newSummaryTableItem("UPTIME", crashSummary.getUpTime(), true);
				newSummaryTableItem("MOBILECRASH CONFIGURATION", crashSummary.getProductionMode(), true);
				newSummaryTableItem("CRASH SOURCE", crashSummary.getCrashSource(), true);
				newSummaryTableItem("FREE DISK SPACE", crashSummary.getFreeDisk(), true);
				
				// Print defect hash and detailed defect hash if exist
				List<Stack> stacks = null;
				if (selectedThread != null)
					stacks = selectedThread.getStacks();
				
				if (stacks != null && !stacks.isEmpty()) 
				{
					String defectHash = "";
					String detailedDefectHash = "";
					
					for(Stack stack: stacks) {
						defectHash = stack.getHash();
						if(! "".equals(defectHash)) {
							newSummaryTableItem("DEFECT HASH", defectHash, true);
						}
						
						detailedDefectHash = stack.getDetailedHash();
						if(! "".equals(detailedDefectHash)) {
							newSummaryTableItem("DETAILED DEFECT HASH", detailedDefectHash, true);
						}
					}
				}
			}
			
			// stand alone stacks don't belong to a thread, check if there are any 
			// of these, and print SP, LR and PC if needed
			List<Stack> standAloneStacks = crashFile.getStandAloneStacks();
			if (standAloneStacks != null && !standAloneStacks.isEmpty()) {
				for (int i = 0; i < standAloneStacks.size(); i++) {
					Stack stack = standAloneStacks.get(i);
					if (stack.stackRegisterContainsCpsr()) {
						newSummaryTableItem("STACK POINTER", stack.getStackPointer(), true);
						newSummaryTableItem("LINK REGISTER", stack.getLinkRegister(), true);
						newSummaryTableItem("PROGRAM COUNTER", stack.getProgramCounter(), true);
					}
				}
			}
			
			// stand alone registers don't belong to a thread, check if there are any 
			// of these, and print SP, LR and PC if needed
			List<RegisterSet> standAloneRegisterSets = crashFile.getStandAloneRegisterSets();
			if (standAloneRegisterSets != null && !standAloneRegisterSets.isEmpty()) {
				for (int i = 0; i < standAloneRegisterSets.size(); i++) {
					RegisterSet regSet = standAloneRegisterSets.get(i);
					if (regSet.containsCPSR()) {
						newSummaryTableItem("STACK POINTER", regSet.getStackPointer(), true);
						newSummaryTableItem("LINK REGISTER", regSet.getLinkRegister(), true);
						newSummaryTableItem("PROGRAM COUNTER", regSet.getProgramCounter(), true);
					}
				}
			}
			
			AutoSizeTableCells(tableSummary);
		}
	}
	
	/**
	 * Load exit information
	 */
	void loadExitInfo() {
		if (crashFile == null)
			return;
					
		String panicSummary = "";
		String panicDescription = "";

		if (crashFile.getContentType() == ContentType.REGMSG) {
			labelPanicSummary.setText("Registration message");
			panicDescription = HtmlFormatter.formatRegistrationMessage();
			browserPanicDescription.setText(HtmlFormatter.formatHtmlStyle(labelPanicSummary.getFont(), 
					panicDescription));
			return;
		} else if (crashFile.getContentType() == ContentType.REPORT) {
			labelPanicSummary.setText("Report");
			panicDescription = HtmlFormatter.formatReport();
			browserPanicDescription.setText(HtmlFormatter.formatHtmlStyle(labelPanicSummary.getFont(), 
					panicDescription));
			return;
		}
		
		if (selectedThread != null && !"".equals(selectedThread.getExitType())) {
			panicDescription = selectedThread.getPanicDescription();
			panicSummary = selectedThread.getExitType();
			if (!"".equals(selectedThread.getExitCategory()) && !"".equals(selectedThread.getExitReason())) {
				// if crash was an exception
				if (selectedThread.getExitType().equals("Exception")) {
					panicSummary += ": " + selectedThread.getExitReason();
				// crash was a panic
				} else {
					panicSummary += ": " + selectedThread.getExitCategory() + " - " + selectedThread.getExitReason();
				}
			}
		}
		
		// we could not find panic data
		if ("".equals(panicSummary.trim())) {
			panicSummary = "Unknown";
		}
		labelPanicSummary.setText(panicSummary);
		if ("".equals(panicDescription.trim()))
			panicDescription = HtmlFormatter.formatUnknownPanicMessage(panicSummary); 

		browserPanicDescription.setText(HtmlFormatter.formatHtmlStyle(labelPanicSummary.getFont(), 
																		panicDescription));
	}
	
	public void widgetDefaultSelected(SelectionEvent arg0) {
		// no implementation required
	}

	
	/**
	 * Adds new summary table row
	 * @param header header text
	 * @param value value text
	 */
	boolean newSummaryTableItem(String header, String value, boolean doNotDuplicate) {
		if (!"".equals(value)) {
			if (doNotDuplicate) {
				for (int i = 0; i < tableSummary.getItemCount(); i++) {
					TableItem it = tableSummary.getItem(i);
					if (it.getText(0).equalsIgnoreCase(header))
						return false;
				}
			}
			TableItem item = new TableItem(tableSummary, SWT.NONE);
			item.setText(new String[] {header, value});
			return true;
		}
		
		return false;
	}
	
	/**
	 * Sets context sensitive help ids to UI elements
	 */
	void setHelps() {
		PlatformUI.getWorkbench().getHelpSystem().setHelp(tableSummary,
				HelpContextIDs.CRASH_ANALYSER_HELP_CRASH_VISUALISER);	
		PlatformUI.getWorkbench().getHelpSystem().setHelp(browserPanicDescription,
				HelpContextIDs.CRASH_ANALYSER_HELP_CRASH_VISUALISER);	
	}
}