crashanalysis/crashanalyser/com.nokia.s60tools.crashanalyser/src/com/nokia/s60tools/crashanalyser/ui/editors/RegistersPage.java
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Tue, 20 Apr 2010 14:41:43 +0300
changeset 4 615035072f7e
permissions -rw-r--r--
Crash Analyser Carbide extension v1.3

/*
* Copyright (c) 2010 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 java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;

import com.nokia.s60tools.crashanalyser.containers.Process;
import com.nokia.s60tools.crashanalyser.containers.Register;
import com.nokia.s60tools.crashanalyser.containers.RegisterBit;
import com.nokia.s60tools.crashanalyser.containers.RegisterDetails;
import com.nokia.s60tools.crashanalyser.containers.RegisterSet;
import com.nokia.s60tools.crashanalyser.containers.Thread;
import com.nokia.s60tools.crashanalyser.files.CrashFile;
import com.nokia.s60tools.crashanalyser.files.SummaryFile;
import com.nokia.s60tools.crashanalyser.resources.HelpContextIDs;

public class RegistersPage implements SelectionListener {
	// registers group UI items
	Combo comboRegisters;
	Table tableRegisters;

	// CPSR details group UI items
	Group groupCpsrEmpty;
	Combo comboCpsrDetails;
	Table tableCpsrDetails;

	FontRegistry fontRegistry;
	SummaryFile crashFile;
	Process selectedProcess = null;
	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 doCreatePage(parent);
	}
	
	/**
	 * Creates the page
	 * @param parent composite
	 * @return composite
	 */
	public Composite createPage(Composite parent) {
		return doCreatePage(parent);
	}
	
	/**
	 * Loads data from given file into UI elements.
	 * @param file crash file
	 */
	public void setFile(CrashFile file) {
		if (file != null) {
			crashFile = file;
			initialUserRegistersTableLoad();
			initialCpsrDetailsTableLoad();
		}
	}
	
	/**
	 * Creates all UI elements to the page
	 * @param parent
	 * @return composite
	 */
	Composite doCreatePage(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));
//		SashForm sashFormTop = new SashForm(sashFormMain, SWT.HORIZONTAL);
		createRegistersGroup(sashFormMain);
//		createCodeSegmentsGroup(sashFormTop);
//		SashForm sashFormBottom = new SashForm(sashFormMain, SWT.HORIZONTAL);
//		createEventLogGroup(sashFormBottom);
		createCpsrDetailsGroup(sashFormMain);
		
//		sashFormTop.setWeights(new int[]{3,2});
//		sashFormBottom.setWeights(new int[]{3,7});
			
		setHelps();
		
		return parent;
	}

	/**
	 * Creates registers group
	 * @param parent
	 */
	void createRegistersGroup(Composite parent) {
		Group groupRegisters = new Group(parent, SWT.NONE);
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		groupRegisters.setLayout(layout);
		groupRegisters.setText("Registers");
		GridData groupGD = new GridData(GridData.FILL_HORIZONTAL);
		groupRegisters.setLayoutData(groupGD);
		
		comboRegisters = new Combo(groupRegisters, SWT.BORDER | SWT.DROP_DOWN | SWT.READ_ONLY);
		GridData comboGD = new GridData();
		comboGD.horizontalSpan = 2;
		comboRegisters.setLayoutData(comboGD);
		comboRegisters.addSelectionListener(this);
		
		tableRegisters = new Table(groupRegisters, SWT.BORDER);
		tableRegisters.setHeaderVisible(true);
		tableRegisters.setLinesVisible(true);
		TableColumn col = new TableColumn(tableRegisters, SWT.LEFT);
		col.setWidth(100);
		col.setText("Register");
		col = new TableColumn(tableRegisters, SWT.LEFT);
		col.setWidth(100);
		col.setText("Value");
		col = new TableColumn(tableRegisters, SWT.LEFT);
		col.setWidth(100);
		col.setText("Symbol");
		col = new TableColumn(tableRegisters, SWT.LEFT);
		col.setWidth(100);
		col.setText("Comment");
		tableRegisters.setFont(fontRegistry.get("monospace"));

		GridData tableGd = new GridData(GridData.FILL_BOTH);
		tableGd.horizontalSpan = 2;
		tableRegisters.setLayoutData(tableGd);

		initialUserRegistersTableLoad();
	}
		/**
		 * Creates cpsr details group
		 * @param parent
		 */
		void createCpsrDetailsGroup(Composite parent) {
			Group groupCpsrDetails = new Group(parent, SWT.NONE);
			GridLayout layout = new GridLayout();
			layout.numColumns = 1;
			groupCpsrDetails.setLayout(layout);
			groupCpsrDetails.setText("CPSR Details");
			GridData groupGD = new GridData(GridData.FILL_VERTICAL);
			groupCpsrDetails.setLayoutData(groupGD);
			
			comboCpsrDetails = new Combo(groupCpsrDetails, SWT.BORDER | SWT.DROP_DOWN | SWT.READ_ONLY);
			comboCpsrDetails.addSelectionListener(this);

			// Empty group
			groupCpsrEmpty = new Group(groupCpsrDetails, SWT.NONE);
			FormLayout fl = new FormLayout();
			fl.marginRight = 5;
			fl.marginLeft = 5;
			fl.marginBottom = 5;
			groupCpsrEmpty.setLayout(fl);
			GridData groupCpsrEmptyGd = new GridData(GridData.FILL_HORIZONTAL);
			groupCpsrEmptyGd.horizontalAlignment = SWT.FILL;
			groupCpsrEmptyGd.grabExcessHorizontalSpace = true;
			groupCpsrEmpty.setLayoutData(groupCpsrEmptyGd);

			// create 32 empty text boxes
			for (int i = 0; i < 32; i++) {
				Text text = new Text(groupCpsrEmpty, SWT.READ_ONLY | SWT.BORDER | SWT.NO_FOCUS | SWT.CENTER);
				text.setFont(fontRegistry.get("monospace"));
				FormData textFd = new FormData();
				textFd.left = new FormAttachment(0,i*20);
				textFd.top = new FormAttachment(8, 15);
				textFd.width = 8;
				text.setLayoutData(textFd); 			
			}

			tableCpsrDetails = new Table(groupCpsrDetails, SWT.BORDER);
			tableCpsrDetails.setLinesVisible(true);
			tableCpsrDetails.setHeaderVisible(true);
			TableColumn col = new TableColumn(tableCpsrDetails, SWT.LEFT);
			col.setWidth(380);
			col.setText("Name");
			col = new TableColumn(tableCpsrDetails, SWT.LEFT);
			col.setWidth(220);
			col.setText("Value");
			GridData tableGd = new GridData(GridData.FILL_VERTICAL | GridData.FILL_HORIZONTAL);
			tableGd.horizontalAlignment = SWT.FILL;
			tableGd.grabExcessHorizontalSpace = true;
			tableCpsrDetails.setLayoutData(tableGd);
			tableCpsrDetails.setFont(fontRegistry.get("monospace"));
			initialCpsrDetailsTableLoad();
		}
		
		
		/**
		 * Loads register sets to combo, selects the correct set as
		 * default set and then loads set's registers to table.
		 */
		void initialUserRegistersTableLoad() {
			if (crashFile == null)
				return;

			int defaultSelectionIndex = 0;

			// show the data of crashed process
			if (crashFile.getThread() != null) {
				selectedProcess = crashFile.getProcessByThread(crashFile.getThread().getId());
			} else {
				selectedProcess = crashFile.getCrashedProcess();
			}
				
			if (selectedProcess != null) {
				// current UI support only one thread, so show the first thread of first process
				if(crashFile.getThread() != null) {
					selectedThread = crashFile.getThread();
				} else {
					selectedThread = crashFile.getCrashedThread();
				}
				
				if (selectedThread != null) {
					List<RegisterSet> registerSets = selectedThread.getRegisters();
					if (registerSets != null && !registerSets.isEmpty()) {
						// load all register sets to combo
						for (int i = 0; i < registerSets.size(); i++) {
							RegisterSet registerSet = registerSets.get(i);
							// default register to show is the one that contains CPSR register
							if (registerSet.containsCPSR()) 
								defaultSelectionIndex = i;
							comboRegisters.add(registerSet.getName());
							comboRegisters.setData(registerSet.getName(), registerSet);
						}
					}
				}
			}
			
			List<RegisterSet> standAloneRegisters = crashFile.getStandAloneRegisterSets();
			if (standAloneRegisters != null && !standAloneRegisters.isEmpty()) {
				for (int i = 0; i < standAloneRegisters.size(); i++) {
					RegisterSet regSet = standAloneRegisters.get(i);
					if (regSet.containsCPSR())
						defaultSelectionIndex = comboRegisters.getItemCount() + i;
					comboRegisters.add(regSet.getName());
					comboRegisters.setData(regSet.getName(), regSet);
				}
			}
			
			if (comboRegisters.getItemCount() > 0) {
				comboRegisters.select(defaultSelectionIndex);
				loadRegistersTable();
			}
			
		}
		
		/**
		 * Loads user registers table according to which registers set is
		 * selected in combo. 
		 */
		void loadRegistersTable() {
			tableRegisters.removeAll();
			
			if (comboRegisters.getItemCount() < 1)
				return;
			
			try {
				RegisterSet registerSet = (RegisterSet)comboRegisters.getData(comboRegisters.getText());
				List<Register> registers = registerSet.getRegisters();
				if (registers != null && !registers.isEmpty()) {
					// show all register values in selected register set
					for (int i = 0; i < registers.size(); i++) {
						Register register = registers.get(i);
						newRegistersTableItem(register);
					}
					AutoSizeTableCells(tableRegisters);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		/**
		 * Loads cprs types to combo, selects first type and then loads it's
		 * data to table.
		 */
		void initialCpsrDetailsTableLoad() {
			if (crashFile == null)
				return;

			List<RegisterDetails> registerDetails = crashFile.getRegisterDetails();
			if (registerDetails != null && !registerDetails.isEmpty()) {
				for (int i = 0; i < registerDetails.size(); i++) {
					RegisterDetails regDetails = registerDetails.get(i);
					if (regDetails.getDescription().contains("CPSR")) {
						comboCpsrDetails.add(regDetails.getDescription());
						comboCpsrDetails.setData(regDetails.getDescription(), regDetails);
					}
				}
				comboCpsrDetails.select(0);
				loadCpsrDetailsTable();
			}		
		}
		
		/**
		 * Loads currently selected cprs's details into table.
		 */
		void loadCpsrDetailsTable() {
			try {
				tableCpsrDetails.removeAll();

				RegisterDetails registerDetails = null;
				if (comboRegisters.getSelectionIndex() >= 0)
					registerDetails = (RegisterDetails)comboCpsrDetails.getData(comboCpsrDetails.getText());

				if (registerDetails != null) {
					boolean bitStartFromRight = registerDetails.bitsStartFromRight();
					Map<String, String> categories = new HashMap<String, String>();
					// go through all 32 text boxes, and see if there is a bit for each box
					for (int i = 0, j = 31; i < 32; i++, j--) {
						Text box = (Text)groupCpsrEmpty.getChildren().clone()[j];
						// bits can start from the right or left (endianess)
						if (!bitStartFromRight)
							box = (Text)groupCpsrEmpty.getChildren().clone()[i];
						RegisterBit bit = registerDetails.getBit(i);
						// there's no bit for this box
						if (bit == null) {
							box.setText("");
							box.setToolTipText("");
							// there is a bit for this box
						} else {
							String regChar = bit.getRegisterChar();
							String category = bit.getCategory();
							String interpretation = bit.getInterpretation();
							// if this bit contains a longer description, it should be shown in the table also
							if (!"".equals(interpretation) && !categories.containsKey(category)) {
								categories.put(category, interpretation);
							}
							box.setText(regChar);
							box.setToolTipText(category);
						}
					}
				
					// load table
					for (int i = 0; i < categories.size(); i++) {
						newCpsrDetailsTableItem(categories.keySet().toArray()[i].toString(),
											categories.values().toArray()[i].toString());
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		/**
		 * Adds a new table row for registers table
		 * @param register row data
		 */
		void newRegistersTableItem(Register register) {
			TableItem item = new TableItem(tableRegisters, SWT.NONE);
			item.setText(new String[] {register.getName(),
										register.getValue(),
										register.getSymbol(),
										register.getComments()});
		}	

		/**
		 * Adds a new table row for cpsr details table
		 * @param header header text
		 * @param value value text
		 */
		void newCpsrDetailsTableItem(String header, String value) {
			TableItem item = new TableItem(tableCpsrDetails, SWT.NONE);
			item.setText(new String[] {header, value});
		}

		/**
		 * 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();
			}
		}
		
		public void widgetDefaultSelected(SelectionEvent arg0) {
			// No implementation needed
		}

		public void widgetSelected(SelectionEvent event) {
			// cpsr was changed in combo
			if (event.widget == comboCpsrDetails) {
				loadCpsrDetailsTable();
			// register set was changed in combo
			} else if (event.widget == comboRegisters) {
				loadRegistersTable();
			}
		}
		
		/**
		 * Sets context sensitive help ids to UI elements
		 */
		void setHelps() {
			PlatformUI.getWorkbench().getHelpSystem().setHelp(tableCpsrDetails,
					HelpContextIDs.CRASH_ANALYSER_HELP_CRASH_VISUALISER);	
			PlatformUI.getWorkbench().getHelpSystem().setHelp(tableRegisters,
					HelpContextIDs.CRASH_ANALYSER_HELP_CRASH_VISUALISER);	
			PlatformUI.getWorkbench().getHelpSystem().setHelp(tableRegisters,
					HelpContextIDs.CRASH_ANALYSER_HELP_CRASH_VISUALISER);	
			PlatformUI.getWorkbench().getHelpSystem().setHelp(comboCpsrDetails,
					HelpContextIDs.CRASH_ANALYSER_HELP_CRASH_VISUALISER);	
			PlatformUI.getWorkbench().getHelpSystem().setHelp(comboRegisters,
					HelpContextIDs.CRASH_ANALYSER_HELP_CRASH_VISUALISER);	
		}
		
	}