sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.irq/src/com/nokia/carbide/cpp/pi/irq/IrqLineTable.java
author Toni Pulkkinen <ext-toni.p.pulkkinen@nokia.com>
Wed, 23 Jun 2010 15:05:09 +0300
changeset 12 ae255c9aa552
parent 5 844b047e260d
permissions -rw-r--r--
Performance Investigator Carbide extension 2.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.Enumeration;
import java.util.Hashtable;
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.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import com.nokia.carbide.cpp.internal.pi.visual.GenericTable;

/**
 * Table for irq lines
 */
public class IrqLineTable extends GenericTable implements ICheckStateListener {

	/* sort direction */
	private boolean sortAscending = true;

	/* Graph */
	private IrqTraceGraph myGraph;

	/* Parent component where ui components are placed */
	private Composite parent;

	/* item data for table */
	protected Vector<IrqSampleTypeWrapper> tableItemData;

	/**
	 * Constructor
	 * 
	 * @param myGraph
	 *            graph
	 * @param parent
	 *            Parent component where ui components are placed
	 */
	public IrqLineTable(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 IrqLineLabelProvider(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 and color column
		column = new TableColumn(this.table, SWT.CENTER);
		column.setText(Messages.IrqLineTable_0);
		column.setWidth(COLUMN_WIDTH_CHECK_COLUMN);
		column.setData(COLOR_COLUMN_INDEX);
		column.setMoveable(true);
		column.setResizable(true);
		column.addSelectionListener(new ColumnSelectionHandler());

		// Thread line column
		column = new TableColumn(this.table, SWT.LEFT);
		column.setText(Messages.IrqLineTable_1);
		column.setWidth(COLUMN_WIDTH_THREAD_IRQ_LINE);
		column.setData(COLUMN_ID_IRQ_LINE);
		column.setMoveable(true);
		column.setResizable(true);
		column.addSelectionListener(new ColumnSelectionHandler());

		// Return address
		column = new TableColumn(tableViewer.getTable(), SWT.RIGHT);
		column.setText(Messages.IrqLineTable_2);
		column.setWidth(COLUMN_WIDTH_ADDRESS_COUNT);
		column.setData(COLUMN_ID_IRQ_COUNT);
		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_IRQ_COUNT);

		// 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();
		this.addColor();
	}

	/**
	 * 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<IrqSampleTypeWrapper>) 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(Messages.IrqLineTable_3)) {
			actionRecolor();
		} 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 irq lines from table
	 * 
	 * @param value
	 *            true if items are checked
	 */
	private void checkOrUncheckSelectedItems(boolean value) {
		// go thru selected items from thread table and notify graph that
		// threads are checked or unchecked
		TableItem[] selectedItems = this.table.getSelection();
		for (int i = 0; i < selectedItems.length; i++) {

			if (selectedItems[i].getData().getClass() == IrqSampleTypeWrapper.class) {
				selectedItems[i].setChecked(value);
				IrqSampleTypeWrapper wrapper = (IrqSampleTypeWrapper) selectedItems[i]
						.getData();
				if (value) {
					myGraph.irqLineChecked(wrapper);
				} else {
					myGraph.irqLineUnchecked(wrapper);

				}
			}

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

	}

	/**
	 * Checks or unchecks all table items
	 * 
	 * @param value
	 *            true if all items are checked
	 */
	private void checkOrUncheckAllItems(boolean value) {
		// go thru all items from thread table and notify graph that threads are
		// checked or unchecked
		TableItem[] allItems = this.table.getItems();
		for (int i = 0; i < allItems.length; i++) {
			if (allItems[i].getData().getClass() == IrqSampleTypeWrapper.class) {
				allItems[i].setChecked(value);
				IrqSampleTypeWrapper wrapper = (IrqSampleTypeWrapper) allItems[i]
						.getData();
				if (value) {
					myGraph.irqLineChecked(wrapper);
				} else {
					myGraph.irqLineUnchecked(wrapper);

				}
			}

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

	}

	/**
	 * Updates item data to table
	 * 
	 * @param setInput
	 *            true if table needs to be refreshed
	 */
	public void updateItemData(boolean setInput) {

		// get sample type wrappers from irq trace
		tableItemData = new Vector<IrqSampleTypeWrapper>();
		Hashtable<Long, IrqSampleTypeWrapper> irqLines = this.myGraph
				.getIrqTrace().getIrqTable();

		// create table item for each sample type wrapper
		Enumeration<Long> k = irqLines.keys();
		while (k.hasMoreElements()) {
			IrqSampleTypeWrapper threadValue = (IrqSampleTypeWrapper) irqLines
					.get(k.nextElement());
			tableItemData.add(threadValue);
		}

		// refresh the table, if needed
		if (setInput)
			refreshTableViewer();
	}

	/**
	 * Refreshes table viewer
	 */
	public void refreshTableViewer() {
		this.tableViewer.setInput(tableItemData);
		this.addColor();

	}

	/**
	 * @return table viewer
	 */
	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() == IrqSampleTypeWrapper.class) {
			IrqSampleTypeWrapper irqLine = (IrqSampleTypeWrapper) event
					.getElement();
			if (event.getChecked()) {
				myGraph.irqLineChecked(irqLine);
			} else {
				myGraph.irqLineUnchecked(irqLine);
			}
			myGraph.repaint();
			myGraph.updateIrqCountsInLegendsAsynch(IrqTraceGraph.TYPE_IRQ);

		}
	}

	/**
	 * Adds colors into irq line table
	 */
	public void addColor() {
		if (this.tableViewer == null)
			return;

		IrqSampleTypeWrapper pGeneric;
		TableItem[] items = this.table.getItems();
		for (int i = 0; i < items.length; i++) {
			if (items[i].getData().getClass() == IrqSampleTypeWrapper.class) {
				pGeneric = (IrqSampleTypeWrapper) items[i].getData();
				items[i].setBackground(COLOR_COLUMN_INDEX, new Color(parent
						.getDisplay(), pGeneric.rgb));
			}
		}

		table.redraw();
	}

	/**
	 * MouseListener for 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.IrqLineTable_4, table
						.getSelectionCount() > 0);

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

				table.setMenu(contextMenu);
			}
		}
	}

	/**
	 * ColumnselectionHandler for irq columns
	 */
	private class ColumnSelectionHandler extends SelectionAdapter {
		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse
		 * .swt.events.SelectionEvent)
		 */
		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 irq 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 COLOR_COLUMN_INDEX: {
					// sort in ascending order
					sortAscending = true;
					break;
				}
				case COLUMN_ID_IRQ_LINE:
				case COLUMN_ID_IRQ_COUNT: {
					// 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;

			IrqSampleTypeWrapper elem1 = (IrqSampleTypeWrapper) e1;
			IrqSampleTypeWrapper elem2 = (IrqSampleTypeWrapper) e2;

			// find the information for the two irq lines

			// compare based on the memory information
			switch (column) {
			case COLOR_COLUMN_INDEX:
				if (tableViewer.getChecked(e1) == true
						&& tableViewer.getChecked(e2) == false) {
					returnCode = -1;
				} else {
					returnCode = 1;
				}
				break;
			case COLUMN_ID_IRQ_LINE:
				returnCode = elem1.getPrototypeSample().getIrqL1Value() > elem2
						.getPrototypeSample().getIrqL1Value() ? 1 : -1;
				break;
			case COLUMN_ID_IRQ_COUNT:
				returnCode = elem1.count > elem2.count ? 1 : -1;
				break;
			default:
				break;
			}

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

			return returnCode;
		}
	}

	/**
	 * Action for opening color dialog for all selected irq lines.
	 */
	private void actionRecolor() {

		// go thru selected items and open color dialog for each.
		TableItem[] selection = table.getSelection();
		for (TableItem item : selection) {

			if (item.getData().getClass() == IrqSampleTypeWrapper.class) {

				IrqSampleTypeWrapper wrapper = (IrqSampleTypeWrapper) item
						.getData();
				ColorDialog colorDialog = new ColorDialog(
						this.table.getShell(), SWT.PRIMARY_MODAL);

				// set name of the irq line as topic of the dialog
				colorDialog.setText(IrqSampleTypeWrapper.getLineText(wrapper
						.getPrototypeSample().getIrqL1Value()));
				RGB color = colorDialog.open();

				// if OK pressed, save new color into trace and set editor as
				// dirty
				if (color != null && color != wrapper.rgb) {

					// ensure that color is not yet assigned for another
					// thread/irq line
					if (!myGraph.getIrqTrace().getColorSet().contains(color)) {

						myGraph.getIrqTrace().changeColorOfThreadOrIRQLine(
								wrapper, color);

					} else {
						// if same color was alreadyassigned for another
						// thread/irq line, show error message
						MessageBox errorDialog = new MessageBox(this.table
								.getShell(), SWT.ICON_ERROR | SWT.OK);
						errorDialog.setText(Messages.IrqLineTable_5);
						errorDialog
								.setMessage(Messages.IrqLineTable_6);
						errorDialog.open();
					}
				}

			}

		}
		this.myGraph.repaint();
		myGraph.getIrqTrace().updateAllTableViewers();
	}

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

}