sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.irq/src/com/nokia/carbide/cpp/pi/irq/SwiThreadTable.java
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Tue, 24 Aug 2010 14:01:48 +0300
changeset 16 72f198be1c1d
parent 5 844b047e260d
permissions -rw-r--r--
Crash Analyser Carbide Extension 1.4.0

/*
 * 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 the License "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.carbide.cpp.pi.irq;

import java.awt.event.MouseEvent;
import java.util.Vector;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import com.nokia.carbide.cpp.internal.pi.visual.GenericTable;

/**
 *	Software thread interrupt table 
 */
public class SwiThreadTable extends GenericTable implements ICheckStateListener {
	
	private IrqTraceGraph myGraph;
	private Composite parent;
	
    protected Vector<SwiThreadWrapper> tableItemData;

	// sort direction
	private boolean sortAscending = true;
	
	/**
	 * Constructor
	 * @param myGraph irq graph
	 * @param parent parent where table is placed
	 */
	public SwiThreadTable(IrqTraceGraph myGraph, Composite parent){
		this.myGraph = myGraph;
		this.parent  = parent;

		this.tableViewer = CheckboxTableViewer.newCheckList(parent,
  				SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
		this.table = this.tableViewer.getTable();
		
		// add the check state handler, label provider and content provider
		this.tableViewer.addCheckStateListener(this);
		this.tableViewer.setLabelProvider(new SwiThreadLabelProvider(this.table));
		this.tableViewer.setContentProvider(new TableContentProvider());
		this.tableViewer.setSorter(new SharedSorter());

		// create the columns
		TableColumn column;

		// data associated with the TableViewer will note which columns contain hex values
		// Keep this in the order in which columns have been created
		boolean[] isHex = {false, false, false, false};
		this.table.setData("isHex", isHex); //$NON-NLS-1$

		// Check column
		column = new TableColumn(this.table, SWT.CENTER);
		column.setText(Messages.SwiThreadTable_0);
		column.setWidth(20);
		column.setData(COLUMN_ID_SWI_CHECK);
		column.setMoveable(true);
		column.setResizable(true);
		column.addSelectionListener(new ColumnSelectionHandler());
		
		// Thread Name column
		column = new TableColumn(this.table, SWT.LEFT);
		column.setText(Messages.SwiThreadTable_1);
		column.setWidth(COLUMN_WIDTH_THREAD_IRQ_LINE);
		column.setData(COLUMN_ID_SWI_THREAD);
		column.setMoveable(true);
		column.setResizable(true);
		column.addSelectionListener(new ColumnSelectionHandler());

		// Thread address
		column = new TableColumn(tableViewer.getTable(), SWT.RIGHT);
		column.setText(Messages.SwiThreadTable_2);
		column.setWidth(COLUMN_WIDTH_ADDRESS_COUNT);
		column.setData(COLUMN_ID_ADDRESS);
		column.setMoveable(true);
		column.setResizable(true);
		column.addSelectionListener(new ColumnSelectionHandler());

		// add mouse listener and set other table settings
		this.table.addMouseListener(new TableMouseListener());
		this.table.setHeaderVisible(true);
		this.table.setLinesVisible(true);
		this.table.setRedraw(true);
		
		// format data into table
		this.updateItemData(true);
		((SharedSorter) tableViewer.getSorter()).doSort(COLUMN_ID_SWI_THREAD);

		// Select initially no lines
		this.tableViewer.setAllChecked(false);
		
		// listen for key sequences such as Ctrl-A and Ctrl-C
		table.addKeyListener(new TableKeyListener());
		
		tableViewer.refresh();
		table.redraw();
	}
	
	
	/**
	 * Content provider for table
	 */
	private static class TableContentProvider implements IStructuredContentProvider {
		
		/**
		 * Constructor
		 */
		public TableContentProvider() {
			super();
		}

		/*
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
		 */
		@SuppressWarnings("unchecked")
		public Object[] getElements(Object inputElement) {
			return ((Vector<SwiThreadWrapper>) inputElement).toArray();
		}

		/*
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
		 */
		public void dispose() {
		}

		/*
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
		 */
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.nokia.carbide.cpp.internal.pi.visual.GenericTable#action(java.lang.String)
	 */
	public void action(String actionString)
	{
		if (actionString.equals("add")){ //$NON-NLS-1$
			checkOrUncheckSelectedItems(true);
		}
		else if (actionString.equals("remove")){ //$NON-NLS-1$
			checkOrUncheckSelectedItems(false);
		}
		else if (actionString.equals("addall")){ //$NON-NLS-1$
			checkOrUncheckAllItems(true);
		}
		else if (actionString.equals("removeall")){ //$NON-NLS-1$
			checkOrUncheckAllItems(false);
		}
	    else if (actionString.equals("copy")) //$NON-NLS-1$
	    {
	    	actionCopyOrSave(true, this.table, CHECKBOX_TEXT, false, "\t", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
	        return; // no redraw needed
	    }
	    else if (actionString.equals("copyTable")) //$NON-NLS-1$
	    {
	    	actionCopyOrSave(true, this.table, CHECKBOX_TEXT, true, "\t", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
	        return; // no redraw needed
	    }
		else if (actionString.equals("selectAll")) //$NON-NLS-1$
	    {
	    	actionSelectAll();
	        return;
	    }
		
	    else if (actionString.equals("saveTable")) //$NON-NLS-1$
	    {
	    	actionCopyOrSave(false, this.table, CHECKBOX_TEXT, true, ",", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
	        return; // no redraw needed
	    }
	}
	
	/**
	 * Checks or unchecks all selected threads from table
	 * @param value true if items are checked 
	 */
	private void checkOrUncheckSelectedItems(boolean value)
	{
		
		TableItem[] selectedItems = this.table.getSelection();
		for (int i = 0; i < selectedItems.length; i++)
		{
			if(selectedItems[i].getData().getClass() == SwiThreadWrapper.class){
				selectedItems[i].setChecked(value);
				SwiThreadWrapper wrapper = (SwiThreadWrapper)selectedItems[i].getData();
				if(value){
					myGraph.threadChecked(wrapper.threadName);
				}
				else{
					myGraph.threadUnchecked(wrapper.threadName);

				}
			}
		}
		myGraph.updateIrqCountsInLegendsAsynch(IrqTraceGraph.TYPE_SWI);
		myGraph.repaint();

	}
	
	/**
	 * Checks or unchecks all table items
	 * @param value true if all items are checked
	 */
	private void checkOrUncheckAllItems(boolean value)
	{
		
		TableItem[] allItems = this.table.getItems();
		for (int i = 0; i < allItems.length; i++)
		{
			if(allItems[i].getData().getClass() == SwiThreadWrapper.class){
				allItems[i].setChecked(value);
				SwiThreadWrapper wrapper = (SwiThreadWrapper)allItems[i].getData();
				if(value){
					myGraph.threadChecked(wrapper.threadName);
				}
				else{
					myGraph.threadUnchecked(wrapper.threadName);

				}
			}

			
		}
		myGraph.repaint();
		myGraph.updateIrqCountsInLegendsAsynch(IrqTraceGraph.TYPE_SWI);

	}
	
	/**
	 * Formats item data into table
	 * @param setInput true if table needs to be refreshed
	 */
	public void updateItemData(boolean setInput)
	{
		tableItemData = ((IrqTrace)this.myGraph.getTrace()).getAllThreadWrappers();

		// refresh the table, if needed
		if (setInput)
			refreshTableViewer();
	}
	
	/**
	 * Refreshes table viewer
	 */
	public void refreshTableViewer()
	{
		this.tableViewer.setInput(tableItemData);
	}

	/**
	 * @return tableviewer of the thread table
	 */
	public CheckboxTableViewer getTableViewer(){
		return this.tableViewer;
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged(org.eclipse.jface.viewers.CheckStateChangedEvent)
	 */
	public void checkStateChanged(CheckStateChangedEvent event) {
		if(event.getElement().getClass() == SwiThreadWrapper.class){
			SwiThreadWrapper wrapper = (SwiThreadWrapper) event.getElement();
			if(event.getChecked()){
				myGraph.threadChecked(wrapper.threadName);
			}
			else{
				myGraph.threadUnchecked(wrapper.threadName);
			}
			myGraph.repaint();
			myGraph.updateIrqCountsInLegendsAsynch(IrqTraceGraph.TYPE_SWI);
			
		}
		
	}
	
	/**
	 * Mouse listener of the table
	 */
	private class TableMouseListener implements MouseListener
	{
		/*
		 * (non-Javadoc)
		 * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
		 */
		public void mouseDoubleClick(org.eclipse.swt.events.MouseEvent e) {
			
		}
		
		/*
		 * (non-Javadoc)
		 * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
		 */
		public void mouseDown(org.eclipse.swt.events.MouseEvent e) {
		}
		
		/*
		 * (non-Javadoc)
		 * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
		 */
		public void mouseUp(org.eclipse.swt.events.MouseEvent e) {

			if (e.button == MouseEvent.BUTTON3) {
				// get rid of last Menu created so we don't have double menu
				// on click
				if (contextMenu != null) {
					contextMenu.dispose();
				}

				contextMenu = new Menu(table.getShell(), SWT.POP_UP);
				getCheckRows(contextMenu, table.getSelectionCount() > 0);
				
				
				// select all, copy, and copy all
				new MenuItem(contextMenu, SWT.SEPARATOR);
				getSelectAllItem(contextMenu, table.getItemCount() > 0);
				getCopyItem(contextMenu, table.getSelectionCount() > 0);
				getCopyTableItem(contextMenu, table.getItemCount() > 0);

				// save all
				new MenuItem(contextMenu, SWT.SEPARATOR);
				getSaveTableItem(contextMenu, table.getItemCount() > 0);
				
				// Recolor highlighted items
				new MenuItem(contextMenu, SWT.SEPARATOR);
				getRecolorItem(contextMenu, Messages.SwiThreadTable_3, table.getSelectionCount() > 0);

				contextMenu.setLocation(parent.toDisplay(e.x + table.getLocation().x, e.y + table.getLocation().y));
			    contextMenu.setVisible(true);

			    table.setMenu(contextMenu);
			}
		}
	}
	
	/**
	 * Column selection handler for the table
	 */
	private class ColumnSelectionHandler extends SelectionAdapter
	{
		public void widgetSelected(SelectionEvent e)
        {
        	if (!(e.widget instanceof TableColumn))
        		return;
        	
        	sortOnColumnSelection((TableColumn) e.widget);
        }
	}
	
	/**
	 * @param tableColumn which column is sorted
	 */
	public void sortOnColumnSelection(TableColumn tableColumn) {
    	int columnID = ((Integer) tableColumn.getData()).intValue();
    	((SharedSorter) tableViewer.getSorter()).doSort(columnID);

		this.refreshTableViewer();
		this.table.redraw();
	}
	
	/**
	 * Sorter for the table
	 */
	private class SharedSorter extends ViewerSorter {
		// last column sorted
		private int column = -1;
		
		/* 
		 * decide on which column to sort by, and the sort ordering
		 */
		public void doSort(int column) {
			// ignore the column passed in and use the id set by the column selection handler
			if (column == this.column) {
				// sort in other order
				sortAscending = !sortAscending;
			} else {
				// changed columns, so sort in the default order
				switch (column) {
					case COLUMN_ID_SWI_CHECK:
					{
		            	// sort in ascending order
		            	sortAscending = true;
		                break;
					}
					case COLUMN_ID_SWI_THREAD:
					case COLUMN_ID_ADDRESS:
					{
		            	// sort in descending order
		            	sortAscending = false;
		                break;
					}
					default:
					{
						// ignore the column
						return;
					}
				}
				this.column = column;
			}

			// find the TableColumn corresponding to column, and give it a column direction
			TableColumn sortByColumn = null;
			for (int i = 0; i < table.getColumnCount(); i++) {
				if (table.getColumn(i).getData() instanceof Integer) {
					if (((Integer)table.getColumn(i).getData()) == column) {
						sortByColumn = table.getColumn(i);
						break;
					}
				}
			}

			if (sortByColumn != null) {
				table.setSortColumn(sortByColumn);
				table.setSortDirection(sortAscending ? SWT.UP : SWT.DOWN);
			}
		}
		
		/*
		 * compare two items from a table column
		 */
		public int compare(Viewer viewer, Object e1, Object e2) {
			int returnCode = 0;
			
			SwiThreadWrapper elem1 = (SwiThreadWrapper)e1;
			SwiThreadWrapper elem2 = (SwiThreadWrapper)e2;

			// find the memory information for the two threads
			
			// compare based on the memory information
			switch (column) {
			case COLUMN_ID_SWI_CHECK:
				if(tableViewer.getChecked(e1) == true && tableViewer.getChecked(e2) == false){
					returnCode = -1;
				}
				else{
					returnCode = 1;
				}
				break;
			case COLUMN_ID_SWI_THREAD:
				returnCode = elem1.threadName.compareToIgnoreCase(elem2.threadName);
				break;
			case COLUMN_ID_ADDRESS:
				returnCode = elem1.threadAddress > elem2.threadAddress ? 1 : -1;
				break;
			default:
				break;
			}

			// for descending order, reverse the sense of the compare
			if (!sortAscending)
				returnCode = -returnCode;

			return returnCode;
		}
	}
	
	
	/**
	 * sets sort direction
	 * @param sortAscending new sort direction
	 */
	public void setSortAscending(boolean sortAscending) {
		this.sortAscending = sortAscending;
	}
	
}