sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.peccommon/src/com/nokia/carbide/cpp/pi/peccommon/PecCommonLegend.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.peccommon;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.SubMenuManager;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.ide.IIDEActionConstants;

import com.nokia.carbide.cpp.internal.pi.interfaces.ISaveTable;
import com.nokia.carbide.cpp.internal.pi.save.SaveTableWizard;
import com.nokia.carbide.cpp.pi.editors.PIPageEditor;

/**
 * Manages the legend for Performance Counter traces. 
 */
public class PecCommonLegend extends Composite{
	private static final char QUOTE = '"';
	private static final String PI_SAVE_TABLE = "PISaveTable";//$NON-NLS-1$
	private static final String PI_COPY_TABLE = "PICopyTable";//$NON-NLS-1$
	private static final String SAVE_ALL = "saveAll";//$NON-NLS-1$
	
	private final static String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$
	private static final String TAB = "\t"; //$NON-NLS-1$
	private static final String COMMA = ",";//$NON-NLS-1$
	
	/** short description column, such as 'A' */
	public static final int COLUMN_SHORT_TITLE = 0;
	/** performance counter name column */
	public static final int COLUMN_NAME = 1;
	/** average value column */
	public static final int COLUMN_AVERAGE = 2;
	/** sum of values column */
	public static final int COLUMN_SUM = 3;
	/** minimum of values column */
	public static final int COLUMN_MIN = 4;
	/** maximum of values column */
	public static final int COLUMN_MAX = 5;
	
	protected CheckboxTableViewer viewer;
	protected PecCommonTraceGraph graph;
	protected PecCommonTrace trace;
	
    // menu items
	protected Action copyTableAction;
	protected Action copyAction;
	protected Action saveTableAction;
	private IAction checkAllAction;
	private IAction uncheckAllAction;

	
	/**
	 * Constructor
	 * @param graph the graph that this legend belongs to 
	 * @param parent the parent composite
	 * @param title Title for the legend
	 * @param trace The model containing the samples
	 */
	public PecCommonLegend(final PecCommonTraceGraph graph, Composite parent, String title, PecCommonTrace trace){
		super(parent, SWT.NONE);
		this.graph = graph;
		this.trace = trace;
		
		setLayout(GridLayoutFactory.fillDefaults().numColumns(1).spacing(0, 0).create());

		Label label = new Label(this, SWT.CENTER);
		label.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
		//label.setFont(PIPageEditor.helvetica_8);
		label.setText(title);
		label.setLayoutData(GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).grab(true, false).create());
		
		//create table viewer
		final Table table = new Table(this, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
		this.viewer = new CheckboxTableViewer(table);

		PecCommonLegendLabelProvider labelProvider = createLabelProvider();
		viewer.setLabelProvider(labelProvider);
		viewer.setContentProvider(new PecCommonLegendContentProvider(trace));

        PecCommonLegendViewerSorter columnSorter = createLegendSorter();
        createColumns(this.viewer, columnSorter);

		table.setHeaderVisible(true);
		table.setLinesVisible(true);
        columnSorter.setSortColumn(COLUMN_SHORT_TITLE);
        viewer.setComparator(columnSorter);
		
		viewer.addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent arg0) {
				if (copyAction == null)
					return;

				// when selection changes, the ability to copy may change
				copyAction.setEnabled(table.getSelectionCount() > 0);
				PIPageEditor.getActionBars().updateActionBars();
			}
		});
		
		viewer.addCheckStateListener(new ICheckStateListener() {
			
			/* (non-Javadoc)
			 * @see org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged(org.eclipse.jface.viewers.CheckStateChangedEvent)
			 */
			public void checkStateChanged(CheckStateChangedEvent event) {
				PecCommonLegendElement el = (PecCommonLegendElement)event.getElement();
				graph.addOrRemoveSeries(el.getId(), event.getChecked());
			}
		});
		
        viewer.setInput(trace);
        viewer.getTable().setLayoutData(GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).create());
        addActions(viewer);
        viewer.getTable().addFocusListener(new PecCommonLegendFocusListener(viewer));
        addContextMenu(viewer);
        viewer.setAllChecked(true); //default

        PlatformUI.getWorkbench().getHelpSystem().setHelp(this, graph.getContextHelpId());
	}
	


	/**
	 * Creates the LabelProvider for the legend table
	 * @return
	 */
	protected PecCommonLegendLabelProvider createLabelProvider() {
		return new PecCommonLegendLabelProvider();
	}



	/**
	 * Refreshes content of the legend
	 */
	public void refreshLegend(){
		viewer.refresh();
	}
	
	protected void createColumns(final TableViewer aViewer, final PecCommonLegendViewerSorter columnSorter)
 {
		final Table table = aViewer.getTable();

		TableColumn column = new TableColumn(table, SWT.LEFT);
		column.setText(Messages.PecCommonLegend_0);
		column.setWidth(50);
		column.setMoveable(true);
		column.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				columnSorter.setSortColumn(COLUMN_SHORT_TITLE);
				aViewer.refresh();
			}
		});

		column = new TableColumn(table, SWT.LEFT);
		column.setText(Messages.PecCommonLegend_1);
		column.setWidth(150);
		column.setMoveable(true);
		column.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				columnSorter.setSortColumn(COLUMN_NAME);
				aViewer.refresh();
			}
		});

		column = new TableColumn(table, SWT.RIGHT);
		column.setText(String.format(Messages.PecCommonLegend_2, trace.getSamplingInterval()));
		column.setWidth(100);
		column.setMoveable(true);
		column.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				columnSorter.setSortColumn(COLUMN_AVERAGE);
				aViewer.refresh();
			}
		});

		column = new TableColumn(table, SWT.RIGHT);
		column.setText(Messages.PecCommonLegend_3);
		column.setWidth(100);
		column.setMoveable(true);
		column.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				columnSorter.setSortColumn(COLUMN_SUM);
				aViewer.refresh();
			}
		});

		column = new TableColumn(table, SWT.RIGHT);
		column.setText(String.format(Messages.PecCommonLegend_4, trace.getSamplingInterval()));
		column.setWidth(100);
		column.setMoveable(true);
		column.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				columnSorter.setSortColumn(COLUMN_MIN);
				aViewer.refresh();
			}
		});

		column = new TableColumn(table, SWT.RIGHT);
		column.setText(String.format(Messages.PecCommonLegend_5, trace.getSamplingInterval()));
		column.setWidth(100);
		column.setMoveable(true);
		column.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				columnSorter.setSortColumn(COLUMN_MAX);
				aViewer.refresh();
			}
		});
	}

	/**
	 * Maximises or restores the legend table viewer
	 * @param maximise true for maximise, false for restore
	 */
	public void setLegendMaximised(boolean maximise) {
		((SashForm)this.getParent()).setMaximizedControl(maximise ? this : null);		
	}

	/**
	 * Minimises or restores legend view
	 * @param visible true for setting visible, false for hiding
	 */
	public void setLegendVisible(boolean visible) {
		this.setVisible(visible);
		
	}
	
	private void addActions(final TableViewer legendViewer) {	
		
		checkAllAction = new Action(Messages.PecCommonLegend_6){
			@Override
			public void run() {
				viewer.setAllChecked(true);
				graph.showAllSeries();
			}			
		};
		checkAllAction.setEnabled(true);
		checkAllAction.setText(Messages.PecCommonLegend_7);
		
		uncheckAllAction = new Action(Messages.PecCommonLegend_8){
			@Override
			public void run() {
				viewer.setAllChecked(false);
				graph.removeAllSeries();
			}			
		};
		uncheckAllAction.setEnabled(true);
		uncheckAllAction.setText(Messages.PecCommonLegend_9);
		
		copyAction = new Action(Messages.PecCommonLegend_10) {
			@Override
			public void run() {
				copyToClipboard(legendContentToString(((IStructuredSelection)legendViewer.getSelection()).toArray(), false, TAB));
			}
		};
		copyAction.setEnabled(false);
		copyAction.setText(Messages.PecCommonLegend_11);

		copyTableAction = new Action(Messages.PecCommonLegend_12) {
			@Override
			public void run() {
				Object[] elements = ((IStructuredContentProvider)legendViewer.getContentProvider()).getElements(null); 
				legendViewer.getComparator().sort(legendViewer, elements);
				copyToClipboard(legendContentToString(elements, true, TAB));
			}
		};
		copyTableAction.setEnabled(true);
		copyTableAction.setId(PI_COPY_TABLE); 
		copyTableAction.setText(Messages.PecCommonLegend_13);

		saveTableAction = new Action(Messages.PecCommonLegend_14) { 
			@Override
			public void run() {
				
				WizardDialog dialog = new WizardDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(), new SaveTableWizard(new ISaveTable(){
					public String getData() {
						Object[] elements = ((PecCommonLegendContentProvider)legendViewer.getContentProvider()).getElements(null); 
						legendViewer.getComparator().sort(legendViewer, elements);
						return legendContentToString(elements, true, COMMA).toString();
					}
				}));
		    	dialog.open();
			}
		};
		saveTableAction.setEnabled(true);
		saveTableAction.setId(PI_SAVE_TABLE);
		saveTableAction.setText(Messages.PecCommonLegend_15);
		
}
	
	/**
	 * Copies the content of the given StringBuilder to the clipboard. 
	 */
	protected void copyToClipboard(StringBuilder sb) {
		
		if (sb.length() > 0) {
			TextTransfer textTransfer = TextTransfer.getInstance();
			Clipboard cb = new Clipboard(this.getDisplay());
			try {
				cb.setContents(new Object[] { sb.toString() },
						new Transfer[] { textTransfer });
			} finally {
				cb.dispose();
			}
		}
		
	}
	
	/**
	 * Returns the content of the given objects in human-readable format.
	 * Optionally includes column headers. Columns are separated by tabs. Elements are separated
	 * by newlines. 
	 * @param objects Array of objects. Elements of the array are assumed to be of type PecCommonLegendElement
	 * @param includeHeader true if column headers are to be included	 
	 * @return 
	 */
	protected StringBuilder legendContentToString(Object[] objects, boolean includeHeader, String separator) {
		StringBuilder sb = new StringBuilder();
		
		if (includeHeader){
			for (int i = 0; i < viewer.getTable().getColumnCount(); i++) {
				if (i != 0){
					sb.append(separator);
				}
				sb.append(viewer.getTable().getColumn(i).getText());
			}
			sb.append(NEWLINE);
		}
		
		PecCommonLegendLabelProvider labelProvider = (PecCommonLegendLabelProvider)viewer.getLabelProvider();
		for (Object o : objects) {
			PecCommonLegendElement pecLegendElement = (PecCommonLegendElement) o;
			for (int i = 0; i < viewer.getTable().getColumnCount(); i++) {
				if (i != 0){
					sb.append(separator);
				}
				String s = labelProvider.getColumnText(pecLegendElement, i);
				if (s.indexOf(separator) >= 0){
					sb.append(QUOTE).append(s).append(QUOTE);	//quote if the separator occurs in the value string				
				} else {
					sb.append(s);
				}
			}
			sb.append(NEWLINE);
		}
		return sb;
	}


	/**
	 * Updates enabled-state of actions
	 * @param table the table that the actions apply to
	 */
	protected void updateActionStatus(Table table) {
		copyAction.setEnabled(table.getSelectionCount() > 0);
		copyTableAction.setEnabled(table.getItemCount() > 0);
		saveTableAction.setEnabled(table.getItemCount() > 0);		
	}


	private void addContextMenu(final TableViewer aViewer) {
		final MenuManager mgr = new MenuManager();
		mgr.add(new Separator());
		mgr.add(checkAllAction);
		mgr.add(uncheckAllAction);
		mgr.add(new Separator());
		mgr.add(copyAction);
		mgr.add(copyTableAction);
		mgr.add(new Separator());
		mgr.add(saveTableAction);
		aViewer.getControl().setMenu(mgr.createContextMenu(aViewer.getControl()));		
	}
	

	/**
	 * On gaining focus, we add copy / save actions to the top file and edit menu, 
	 * on losing it, we remove those actions again.   
	 *
	 */
	private class PecCommonLegendFocusListener implements FocusListener {
		private TableViewer legendViewer;
		private IAction oldCopyAction;

		public PecCommonLegendFocusListener(TableViewer legendViewer) {
			this.legendViewer = legendViewer;
		}
		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.
		 * swt.events.FocusEvent)
		 */
		public void focusGained(org.eclipse.swt.events.FocusEvent arg0) {
			IActionBars bars = PIPageEditor.getActionBars();

			oldCopyAction = PIPageEditor.getActionBars().getGlobalActionHandler(ActionFactory.COPY.getId());
			bars.setGlobalActionHandler(ActionFactory.COPY.getId(),	copyAction);
			bars.updateActionBars();

			// add copyTableAction to the Edit menu
			IMenuManager editMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_EDIT);

			if (editMenuManager instanceof SubMenuManager) {
				IContributionManager editManager = ((SubMenuManager) editMenuManager).getParent();
				editMenuManager.remove(PI_COPY_TABLE);
				ActionContributionItem item = new ActionContributionItem(copyTableAction);
				item.setVisible(true);
				editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item);
			}

			// add saveTableAction to the File menu
			IMenuManager fileMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_FILE);

			if (fileMenuManager instanceof SubMenuManager) {
				IContributionManager fileManager = ((SubMenuManager) fileMenuManager).getParent();

				fileMenuManager.remove(PI_SAVE_TABLE);
				ActionContributionItem item = new ActionContributionItem(saveTableAction);
				item.setVisible(true);
				fileManager.insertAfter(SAVE_ALL, item);
			}
			
			updateActionStatus(legendViewer.getTable());
		}


		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt
		 * .events.FocusEvent)
		 */
		public void focusLost(org.eclipse.swt.events.FocusEvent arg0) {
			IActionBars bars = PIPageEditor.getActionBars();
			bars.setGlobalActionHandler(ActionFactory.COPY.getId(),
					oldCopyAction);
			bars.updateActionBars();

			SubMenuManager editMenuManager = (SubMenuManager) PIPageEditor
					.getMenuManager().find(IIDEActionConstants.M_EDIT);
			editMenuManager.remove(PI_COPY_TABLE);
			editMenuManager.update();

			SubMenuManager fileMenuManager = (SubMenuManager) PIPageEditor
					.getMenuManager().find(IIDEActionConstants.M_FILE);
			fileMenuManager.remove(PI_SAVE_TABLE);
			fileMenuManager.update();
		}
	}		

	/**
	 * Creates the sorter used for the legend view. Sub classes may override this
	 * @return PecCommonLegendViewerSorter
	 */
	protected PecCommonLegendViewerSorter createLegendSorter(){
		return new PecCommonLegendViewerSorter();
	}
}