-/*******************************************************************************\r
- * Copyright (c) 2012 Ericsson\r
- *\r
- * All rights reserved. This program and the accompanying materials are\r
- * made available under the terms of the Eclipse Public License v1.0 which\r
- * accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * Patrick Tasse - Initial API and implementation\r
- *******************************************************************************/\r
-\r
-package org.eclipse.linuxtools.tmf.ui.widgets.timegraph;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.HashMap;\r
-\r
-import org.eclipse.jface.viewers.ILabelProviderListener;\r
-import org.eclipse.jface.viewers.ISelectionChangedListener;\r
-import org.eclipse.jface.viewers.IStructuredSelection;\r
-import org.eclipse.jface.viewers.ITableLabelProvider;\r
-import org.eclipse.jface.viewers.ITreeContentProvider;\r
-import org.eclipse.jface.viewers.ITreeViewerListener;\r
-import org.eclipse.jface.viewers.SelectionChangedEvent;\r
-import org.eclipse.jface.viewers.StructuredSelection;\r
-import org.eclipse.jface.viewers.TreeExpansionEvent;\r
-import org.eclipse.jface.viewers.TreeViewer;\r
-import org.eclipse.jface.viewers.Viewer;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.custom.SashForm;\r
-import org.eclipse.swt.events.ControlAdapter;\r
-import org.eclipse.swt.events.ControlEvent;\r
-import org.eclipse.swt.events.MouseEvent;\r
-import org.eclipse.swt.events.MouseTrackAdapter;\r
-import org.eclipse.swt.events.MouseWheelListener;\r
-import org.eclipse.swt.events.PaintEvent;\r
-import org.eclipse.swt.events.PaintListener;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.graphics.Image;\r
-import org.eclipse.swt.graphics.Point;\r
-import org.eclipse.swt.layout.FillLayout;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.Event;\r
-import org.eclipse.swt.widgets.Listener;\r
-import org.eclipse.swt.widgets.Slider;\r
-import org.eclipse.swt.widgets.Tree;\r
-import org.eclipse.swt.widgets.TreeColumn;\r
-import org.eclipse.swt.widgets.TreeItem;\r
-\r
-/**\r
- * Time graph "combo" view (with the list/tree on the left and the gantt chart\r
- * on the right)\r
- *\r
- * @version 1.0\r
- * @author Patrick Tasse\r
- */\r
-public class TimeGraphCombo extends Composite {\r
-\r
- // ------------------------------------------------------------------------\r
- // Constants\r
- // ------------------------------------------------------------------------\r
-\r
- private static final Object FILLER = new Object();\r
-\r
- // ------------------------------------------------------------------------\r
- // Fields\r
- // ------------------------------------------------------------------------\r
-\r
- // The tree viewer\r
- private TreeViewer fTreeViewer;\r
-\r
- // The time viewer\r
- private TimeGraphViewer fTimeGraphViewer;\r
-\r
- // The selection listener map\r
- private final HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper> fSelectionListenerMap = new HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper>();\r
-\r
- // Flag to block the tree selection changed listener when triggered by the time graph combo\r
- private boolean fInhibitTreeSelection = false;\r
-\r
- // Number of filler rows used by the tree content provider\r
- private int fNumFillerRows;\r
-\r
- // Calculated item height for Linux workaround\r
- private int fLinuxItemHeight = 0;\r
-\r
- // ------------------------------------------------------------------------\r
- // Classes\r
- // ------------------------------------------------------------------------\r
-\r
- /**\r
- * The TreeContentProviderWrapper is used to insert filler items after\r
- * the elements of the tree's real content provider.\r
- */\r
- private class TreeContentProviderWrapper implements ITreeContentProvider {\r
- private final ITreeContentProvider contentProvider;\r
-\r
- public TreeContentProviderWrapper(ITreeContentProvider contentProvider) {\r
- this.contentProvider = contentProvider;\r
- }\r
-\r
- @Override\r
- public void dispose() {\r
- contentProvider.dispose();\r
- }\r
-\r
- @Override\r
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
- contentProvider.inputChanged(viewer, oldInput, newInput);\r
- }\r
-\r
- @Override\r
- public Object[] getElements(Object inputElement) {\r
- Object[] elements = contentProvider.getElements(inputElement);\r
- // add filler elements to ensure alignment with time analysis viewer\r
- Object[] oElements = Arrays.copyOf(elements, elements.length + fNumFillerRows, new Object[0].getClass());\r
- for (int i = 0; i < fNumFillerRows; i++) {\r
- oElements[elements.length + i] = FILLER;\r
- }\r
- return oElements;\r
- }\r
-\r
- @Override\r
- public Object[] getChildren(Object parentElement) {\r
- if (parentElement instanceof ITimeGraphEntry) {\r
- return contentProvider.getChildren(parentElement);\r
- }\r
- return new Object[0];\r
- }\r
-\r
- @Override\r
- public Object getParent(Object element) {\r
- if (element instanceof ITimeGraphEntry) {\r
- return contentProvider.getParent(element);\r
- }\r
- return null;\r
- }\r
-\r
- @Override\r
- public boolean hasChildren(Object element) {\r
- if (element instanceof ITimeGraphEntry) {\r
- return contentProvider.hasChildren(element);\r
- }\r
- return false;\r
- }\r
- }\r
-\r
- /**\r
- * The TreeLabelProviderWrapper is used to intercept the filler items\r
- * from the calls to the tree's real label provider.\r
- */\r
- private class TreeLabelProviderWrapper implements ITableLabelProvider {\r
- private final ITableLabelProvider labelProvider;\r
-\r
- public TreeLabelProviderWrapper(ITableLabelProvider labelProvider) {\r
- this.labelProvider = labelProvider;\r
- }\r
-\r
- @Override\r
- public void addListener(ILabelProviderListener listener) {\r
- labelProvider.addListener(listener);\r
- }\r
-\r
- @Override\r
- public void dispose() {\r
- labelProvider.dispose();\r
- }\r
-\r
- @Override\r
- public boolean isLabelProperty(Object element, String property) {\r
- if (element instanceof ITimeGraphEntry) {\r
- return labelProvider.isLabelProperty(element, property);\r
- }\r
- return false;\r
- }\r
-\r
- @Override\r
- public void removeListener(ILabelProviderListener listener) {\r
- labelProvider.removeListener(listener);\r
- }\r
-\r
- @Override\r
- public Image getColumnImage(Object element, int columnIndex) {\r
- if (element instanceof ITimeGraphEntry) {\r
- return labelProvider.getColumnImage(element, columnIndex);\r
- }\r
- return null;\r
- }\r
-\r
- @Override\r
- public String getColumnText(Object element, int columnIndex) {\r
- if (element instanceof ITimeGraphEntry) {\r
- return labelProvider.getColumnText(element, columnIndex);\r
- }\r
- return null;\r
- }\r
-\r
- }\r
-\r
- /**\r
- * The SelectionListenerWrapper is used to intercept the filler items from\r
- * the time graph combo's real selection listener, and to prevent double\r
- * notifications from being sent when selection changes in both tree and\r
- * time graph at the same time.\r
- */\r
- private class SelectionListenerWrapper implements ISelectionChangedListener, ITimeGraphSelectionListener {\r
- private final ITimeGraphSelectionListener listener;\r
- private ITimeGraphEntry selection = null;\r
-\r
- public SelectionListenerWrapper(ITimeGraphSelectionListener listener) {\r
- this.listener = listener;\r
- }\r
-\r
- @Override\r
- public void selectionChanged(SelectionChangedEvent event) {\r
- if (fInhibitTreeSelection) {\r
- return;\r
- }\r
- Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();\r
- if (element instanceof ITimeGraphEntry) {\r
- ITimeGraphEntry entry = (ITimeGraphEntry) element;\r
- if (entry != selection) {\r
- selection = entry;\r
- listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public void selectionChanged(TimeGraphSelectionEvent event) {\r
- ITimeGraphEntry entry = event.getSelection();\r
- if (entry != selection) {\r
- selection = entry;\r
- listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));\r
- }\r
- }\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // Constructors\r
- // ------------------------------------------------------------------------\r
-\r
- /**\r
- * Constructs a new instance of this class given its parent\r
- * and a style value describing its behavior and appearance.\r
- *\r
- * @param parent a widget which will be the parent of the new instance (cannot be null)\r
- * @param style the style of widget to construct\r
- */\r
- public TimeGraphCombo(Composite parent, int style) {\r
- super(parent, style);\r
- setLayout(new FillLayout());\r
-\r
- final SashForm sash = new SashForm(this, SWT.NONE);\r
-\r
- fTreeViewer = new TreeViewer(sash, SWT.FULL_SELECTION | SWT.H_SCROLL);\r
- final Tree tree = fTreeViewer.getTree();\r
- tree.setHeaderVisible(true);\r
- tree.setLinesVisible(true);\r
-\r
- fTimeGraphViewer = new TimeGraphViewer(sash, SWT.NONE);\r
- fTimeGraphViewer.setItemHeight(getItemHeight(tree));\r
- fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());\r
- fTimeGraphViewer.setBorderWidth(tree.getBorderWidth());\r
- fTimeGraphViewer.setNameWidthPref(0);\r
-\r
- // Feature in Windows. The tree vertical bar reappears when\r
- // the control is resized so we need to hide it again.\r
- // Bug in Linux. The tree header height is 0 in constructor,\r
- // so we need to reset it later when the control is resized.\r
- tree.addControlListener(new ControlAdapter() {\r
- int depth = 0;\r
- @Override\r
- public void controlResized(ControlEvent e) {\r
- if (depth == 0) {\r
- depth++;\r
- tree.getVerticalBar().setEnabled(false);\r
- // this can trigger controlResized recursively\r
- tree.getVerticalBar().setVisible(false);\r
- depth--;\r
- }\r
- fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());\r
- }\r
- });\r
-\r
- // ensure synchronization of expanded items between tree and time graph\r
- fTreeViewer.addTreeListener(new ITreeViewerListener() {\r
- @Override\r
- public void treeCollapsed(TreeExpansionEvent event) {\r
- fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), false);\r
- }\r
-\r
- @Override\r
- public void treeExpanded(TreeExpansionEvent event) {\r
- fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), true);\r
- }\r
- });\r
-\r
- // ensure synchronization of expanded items between tree and time graph\r
- fTimeGraphViewer.addTreeListener(new ITimeGraphTreeListener() {\r
- @Override\r
- public void treeCollapsed(TimeGraphTreeExpansionEvent event) {\r
- fTreeViewer.setExpandedState(event.getEntry(), false);\r
- }\r
-\r
- @Override\r
- public void treeExpanded(TimeGraphTreeExpansionEvent event) {\r
- fTreeViewer.setExpandedState(event.getEntry(), true);\r
- }\r
- });\r
-\r
- // prevent mouse button from selecting a filler tree item\r
- tree.addListener(SWT.MouseDown, new Listener() {\r
- @Override\r
- public void handleEvent(Event event) {\r
- TreeItem treeItem = tree.getItem(new Point(event.x, event.y));\r
- if (treeItem == null || treeItem.getData() == FILLER) {\r
- event.doit = false;\r
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);\r
- if (treeItems.size() == 0) {\r
- fTreeViewer.setSelection(new StructuredSelection());\r
- fTimeGraphViewer.setSelection(null);\r
- return;\r
- }\r
- // this prevents from scrolling up when selecting\r
- // the partially visible tree item at the bottom\r
- tree.select(treeItems.get(treeItems.size() - 1));\r
- fTreeViewer.setSelection(new StructuredSelection());\r
- fTimeGraphViewer.setSelection(null);\r
- }\r
- }\r
- });\r
-\r
- // prevent mouse wheel from scrolling down into filler tree items\r
- tree.addListener(SWT.MouseWheel, new Listener() {\r
- @Override\r
- public void handleEvent(Event event) {\r
- event.doit = false;\r
- Slider scrollBar = fTimeGraphViewer.getVerticalBar();\r
- fTimeGraphViewer.setTopIndex(scrollBar.getSelection() - event.count);\r
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);\r
- if (treeItems.size() == 0) {\r
- return;\r
- }\r
- TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());\r
- tree.setTopItem(treeItem);\r
- }\r
- });\r
-\r
- // prevent key stroke from selecting a filler tree item\r
- tree.addListener(SWT.KeyDown, new Listener() {\r
- @Override\r
- public void handleEvent(Event event) {\r
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);\r
- if (treeItems.size() == 0) {\r
- fTreeViewer.setSelection(new StructuredSelection());\r
- event.doit = false;\r
- return;\r
- }\r
- if (event.keyCode == SWT.ARROW_DOWN) {\r
- int index = Math.min(fTimeGraphViewer.getSelectionIndex() + 1, treeItems.size() - 1);\r
- fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());\r
- event.doit = false;\r
- } else if (event.keyCode == SWT.PAGE_DOWN) {\r
- int height = tree.getSize().y - tree.getHeaderHeight() - tree.getHorizontalBar().getSize().y;\r
- int countPerPage = height / getItemHeight(tree);\r
- int index = Math.min(fTimeGraphViewer.getSelectionIndex() + countPerPage - 1, treeItems.size() - 1);\r
- fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());\r
- event.doit = false;\r
- } else if (event.keyCode == SWT.END) {\r
- fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(treeItems.size() - 1).getData());\r
- event.doit = false;\r
- }\r
- TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());\r
- tree.setTopItem(treeItem);\r
- if (fTimeGraphViewer.getSelectionIndex() >= 0) {\r
- fTreeViewer.setSelection(new StructuredSelection(fTimeGraphViewer.getSelection()));\r
- } else {\r
- fTreeViewer.setSelection(new StructuredSelection());\r
- }\r
- }\r
- });\r
-\r
- // ensure alignment of top item between tree and time graph\r
- fTimeGraphViewer.getTimeGraphControl().addControlListener(new ControlAdapter() {\r
- @Override\r
- public void controlResized(ControlEvent e) {\r
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);\r
- if (treeItems.size() == 0) {\r
- return;\r
- }\r
- TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());\r
- tree.setTopItem(treeItem);\r
- }\r
- });\r
-\r
- // ensure synchronization of selected item between tree and time graph\r
- fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {\r
- @Override\r
- public void selectionChanged(SelectionChangedEvent event) {\r
- if (fInhibitTreeSelection) {\r
- return;\r
- }\r
- if (event.getSelection() instanceof IStructuredSelection) {\r
- Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();\r
- if (selection instanceof ITimeGraphEntry) {\r
- fTimeGraphViewer.setSelection((ITimeGraphEntry) selection);\r
- }\r
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);\r
- if (treeItems.size() == 0) {\r
- return;\r
- }\r
- TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());\r
- tree.setTopItem(treeItem);\r
- }\r
- }\r
- });\r
-\r
- // ensure synchronization of selected item between tree and time graph\r
- fTimeGraphViewer.addSelectionListener(new ITimeGraphSelectionListener() {\r
- @Override\r
- public void selectionChanged(TimeGraphSelectionEvent event) {\r
- ITimeGraphEntry entry = fTimeGraphViewer.getSelection();\r
- fInhibitTreeSelection = true; // block the tree selection changed listener\r
- if (entry != null) {\r
- StructuredSelection selection = new StructuredSelection(entry);\r
- fTreeViewer.setSelection(selection);\r
- } else {\r
- fTreeViewer.setSelection(new StructuredSelection());\r
- }\r
- fInhibitTreeSelection = false;\r
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);\r
- if (treeItems.size() == 0) {\r
- return;\r
- }\r
- TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());\r
- tree.setTopItem(treeItem);\r
- }\r
- });\r
-\r
- // ensure alignment of top item between tree and time graph\r
- fTimeGraphViewer.getVerticalBar().addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);\r
- if (treeItems.size() == 0) {\r
- return;\r
- }\r
- TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());\r
- tree.setTopItem(treeItem);\r
- }\r
- });\r
-\r
- // ensure alignment of top item between tree and time graph\r
- fTimeGraphViewer.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {\r
- @Override\r
- public void mouseScrolled(MouseEvent e) {\r
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);\r
- if (treeItems.size() == 0) {\r
- return;\r
- }\r
- TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());\r
- tree.setTopItem(treeItem);\r
- }\r
- });\r
-\r
- // ensure the tree has focus control when mouse is over it if the time graph had control\r
- fTreeViewer.getControl().addMouseTrackListener(new MouseTrackAdapter() {\r
- @Override\r
- public void mouseEnter(MouseEvent e) {\r
- if (fTimeGraphViewer.getTimeGraphControl().isFocusControl()) {\r
- fTreeViewer.getControl().setFocus();\r
- }\r
- }\r
- });\r
-\r
- // ensure the time graph has focus control when mouse is over it if the tree had control\r
- fTimeGraphViewer.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {\r
- @Override\r
- public void mouseEnter(MouseEvent e) {\r
- if (fTreeViewer.getControl().isFocusControl()) {\r
- fTimeGraphViewer.getTimeGraphControl().setFocus();\r
- }\r
- }\r
- });\r
- fTimeGraphViewer.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {\r
- @Override\r
- public void mouseEnter(MouseEvent e) {\r
- if (fTreeViewer.getControl().isFocusControl()) {\r
- fTimeGraphViewer.getTimeGraphControl().setFocus();\r
- }\r
- }\r
- });\r
-\r
- // The filler rows are required to ensure alignment when the tree does not have a\r
- // visible horizontal scroll bar. The tree does not allow its top item to be set\r
- // to a value that would cause blank space to be drawn at the bottom of the tree.\r
- fNumFillerRows = Display.getDefault().getBounds().height / getItemHeight(tree);\r
-\r
- sash.setWeights(new int[] { 1, 1 });\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // Accessors\r
- // ------------------------------------------------------------------------\r
-\r
- /**\r
- * Returns this time graph combo's tree viewer.\r
- *\r
- * @return the tree viewer\r
- */\r
- public TreeViewer getTreeViewer() {\r
- return fTreeViewer;\r
- }\r
-\r
- /**\r
- * Returns this time graph combo's time graph viewer.\r
- *\r
- * @return the time graph viewer\r
- */\r
- public TimeGraphViewer getTimeGraphViewer() {\r
- return fTimeGraphViewer;\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // Control\r
- // ------------------------------------------------------------------------\r
-\r
- /* (non-Javadoc)\r
- * @see org.eclipse.swt.widgets.Control#redraw()\r
- */\r
- @Override\r
- public void redraw() {\r
- fTimeGraphViewer.getControl().redraw();\r
- super.redraw();\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // Operations\r
- // ------------------------------------------------------------------------\r
-\r
- /**\r
- * Sets the tree content provider used by this time graph combo.\r
- *\r
- * @param contentProvider the tree content provider\r
- */\r
- public void setTreeContentProvider(ITreeContentProvider contentProvider) {\r
- fTreeViewer.setContentProvider(new TreeContentProviderWrapper(contentProvider));\r
- }\r
-\r
- /**\r
- * Sets the tree label provider used by this time graph combo.\r
- *\r
- * @param labelProvider the tree label provider\r
- */\r
- public void setTreeLabelProvider(ITableLabelProvider labelProvider) {\r
- fTreeViewer.setLabelProvider(new TreeLabelProviderWrapper(labelProvider));\r
- }\r
-\r
- /**\r
- * Sets the tree columns for this time graph combo.\r
- *\r
- * @param columnNames the tree column names\r
- */\r
- public void setTreeColumns(String[] columnNames) {\r
- final Tree tree = fTreeViewer.getTree();\r
- for (String columnName : columnNames) {\r
- TreeColumn column = new TreeColumn(tree, SWT.LEFT);\r
- column.setText(columnName);\r
- column.pack();\r
- }\r
- }\r
-\r
-\r
- /**\r
- * Sets the time graph provider used by this time graph combo.\r
- *\r
- * @param timeGraphProvider the time graph provider\r
- */\r
- public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {\r
- fTimeGraphViewer.setTimeGraphProvider(timeGraphProvider);\r
- }\r
-\r
- /**\r
- * Sets or clears the input for this time graph combo.\r
- * The input array should only contain top-level elements.\r
- *\r
- * @param input the input of this time graph combo, or <code>null</code> if none\r
- */\r
- public void setInput(ITimeGraphEntry[] input) {\r
- fInhibitTreeSelection = true;\r
- fTreeViewer.setInput(input);\r
- for (SelectionListenerWrapper listenerWrapper : fSelectionListenerMap.values()) {\r
- listenerWrapper.selection = null;\r
- }\r
- fInhibitTreeSelection = false;\r
- fTreeViewer.expandAll();\r
- fTreeViewer.getTree().getVerticalBar().setEnabled(false);\r
- fTreeViewer.getTree().getVerticalBar().setVisible(false);\r
- fTimeGraphViewer.setItemHeight(getItemHeight(fTreeViewer.getTree()));\r
- fTimeGraphViewer.setInput(input);\r
- }\r
-\r
- /**\r
- * Refreshes this time graph completely with information freshly obtained from its model.\r
- */\r
- public void refresh() {\r
- fTreeViewer.refresh();\r
- fTimeGraphViewer.refresh();\r
- }\r
-\r
- /**\r
- * Adds a listener for selection changes in this time graph combo.\r
- *\r
- * @param listener a selection listener\r
- */\r
- public void addSelectionListener(ITimeGraphSelectionListener listener) {\r
- SelectionListenerWrapper listenerWrapper = new SelectionListenerWrapper(listener);\r
- fTreeViewer.addSelectionChangedListener(listenerWrapper);\r
- fSelectionListenerMap.put(listener, listenerWrapper);\r
- fTimeGraphViewer.addSelectionListener(listenerWrapper);\r
- }\r
-\r
- /**\r
- * Removes the given selection listener from this time graph combo.\r
- *\r
- * @param listener a selection changed listener\r
- */\r
- public void removeSelectionListener(ITimeGraphSelectionListener listener) {\r
- SelectionListenerWrapper listenerWrapper = fSelectionListenerMap.remove(listener);\r
- fTreeViewer.removeSelectionChangedListener(listenerWrapper);\r
- fTimeGraphViewer.removeSelectionListener(listenerWrapper);\r
- }\r
-\r
- /**\r
- * Sets the current selection for this time graph combo.\r
- *\r
- * @param selection the new selection\r
- */\r
- public void setSelection(ITimeGraphEntry selection) {\r
- fTimeGraphViewer.setSelection(selection);\r
- fInhibitTreeSelection = true; // block the tree selection changed listener\r
- if (selection != null) {\r
- StructuredSelection structuredSelection = new StructuredSelection(selection);\r
- fTreeViewer.setSelection(structuredSelection);\r
- } else {\r
- fTreeViewer.setSelection(new StructuredSelection());\r
- }\r
- fInhibitTreeSelection = false;\r
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(fTreeViewer.getTree());\r
- if (treeItems.size() == 0) {\r
- return;\r
- }\r
- TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());\r
- fTreeViewer.getTree().setTopItem(treeItem);\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // Internal\r
- // ------------------------------------------------------------------------\r
-\r
- private ArrayList<TreeItem> getVisibleExpandedItems(Tree tree) {\r
- ArrayList<TreeItem> items = new ArrayList<TreeItem>();\r
- for (TreeItem item : tree.getItems()) {\r
- if (item.getData() == FILLER) {\r
- break;\r
- }\r
- items.add(item);\r
- if (item.getExpanded()) {\r
- items.addAll(getVisibleExpandedItems(item));\r
- }\r
- }\r
- return items;\r
- }\r
-\r
- private ArrayList<TreeItem> getVisibleExpandedItems(TreeItem treeItem) {\r
- ArrayList<TreeItem> items = new ArrayList<TreeItem>();\r
- for (TreeItem item : treeItem.getItems()) {\r
- items.add(item);\r
- if (item.getExpanded()) {\r
- items.addAll(getVisibleExpandedItems(item));\r
- }\r
- }\r
- return items;\r
- }\r
-\r
- private int getItemHeight(final Tree tree) {\r
- /*\r
- * Bug in Linux. The method getItemHeight doesn't always return the correct value.\r
- */\r
- if (fLinuxItemHeight >= 0 && System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$\r
- if (fLinuxItemHeight != 0) {\r
- return fLinuxItemHeight;\r
- }\r
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);\r
- if (treeItems.size() > 1) {\r
- final TreeItem treeItem0 = treeItems.get(0);\r
- final TreeItem treeItem1 = treeItems.get(1);\r
- PaintListener paintListener = new PaintListener() {\r
- @Override\r
- public void paintControl(PaintEvent e) {\r
- tree.removePaintListener(this);\r
- int y0 = treeItem0.getBounds().y;\r
- int y1 = treeItem1.getBounds().y;\r
- int itemHeight = y1 - y0;\r
- if (itemHeight > 0) {\r
- fLinuxItemHeight = itemHeight;\r
- fTimeGraphViewer.setItemHeight(itemHeight);\r
- }\r
- }\r
- };\r
- tree.addPaintListener(paintListener);\r
- }\r
- } else {\r
- fLinuxItemHeight = -1; // Not Linux, don't perform os.name check anymore\r
- }\r
- return tree.getItemHeight();\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.widgets.timegraph;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ITreeViewerListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeExpansionEvent;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseTrackAdapter;
+import org.eclipse.swt.events.MouseWheelListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Slider;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+
+/**
+ * Time graph "combo" view (with the list/tree on the left and the gantt chart
+ * on the right)
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class TimeGraphCombo extends Composite {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ private static final Object FILLER = new Object();
+
+ // ------------------------------------------------------------------------
+ // Fields
+ // ------------------------------------------------------------------------
+
+ // The tree viewer
+ private TreeViewer fTreeViewer;
+
+ // The time viewer
+ private TimeGraphViewer fTimeGraphViewer;
+
+ // The selection listener map
+ private final HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper> fSelectionListenerMap = new HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper>();
+
+ // Flag to block the tree selection changed listener when triggered by the time graph combo
+ private boolean fInhibitTreeSelection = false;
+
+ // Number of filler rows used by the tree content provider
+ private int fNumFillerRows;
+
+ // Calculated item height for Linux workaround
+ private int fLinuxItemHeight = 0;
+
+ // ------------------------------------------------------------------------
+ // Classes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The TreeContentProviderWrapper is used to insert filler items after
+ * the elements of the tree's real content provider.
+ */
+ private class TreeContentProviderWrapper implements ITreeContentProvider {
+ private final ITreeContentProvider contentProvider;
+
+ public TreeContentProviderWrapper(ITreeContentProvider contentProvider) {
+ this.contentProvider = contentProvider;
+ }
+
+ @Override
+ public void dispose() {
+ contentProvider.dispose();
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ contentProvider.inputChanged(viewer, oldInput, newInput);
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ Object[] elements = contentProvider.getElements(inputElement);
+ // add filler elements to ensure alignment with time analysis viewer
+ Object[] oElements = Arrays.copyOf(elements, elements.length + fNumFillerRows, new Object[0].getClass());
+ for (int i = 0; i < fNumFillerRows; i++) {
+ oElements[elements.length + i] = FILLER;
+ }
+ return oElements;
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ if (parentElement instanceof ITimeGraphEntry) {
+ return contentProvider.getChildren(parentElement);
+ }
+ return new Object[0];
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ if (element instanceof ITimeGraphEntry) {
+ return contentProvider.getParent(element);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ if (element instanceof ITimeGraphEntry) {
+ return contentProvider.hasChildren(element);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * The TreeLabelProviderWrapper is used to intercept the filler items
+ * from the calls to the tree's real label provider.
+ */
+ private class TreeLabelProviderWrapper implements ITableLabelProvider {
+ private final ITableLabelProvider labelProvider;
+
+ public TreeLabelProviderWrapper(ITableLabelProvider labelProvider) {
+ this.labelProvider = labelProvider;
+ }
+
+ @Override
+ public void addListener(ILabelProviderListener listener) {
+ labelProvider.addListener(listener);
+ }
+
+ @Override
+ public void dispose() {
+ labelProvider.dispose();
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property) {
+ if (element instanceof ITimeGraphEntry) {
+ return labelProvider.isLabelProperty(element, property);
+ }
+ return false;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener) {
+ labelProvider.removeListener(listener);
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ if (element instanceof ITimeGraphEntry) {
+ return labelProvider.getColumnImage(element, columnIndex);
+ }
+ return null;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (element instanceof ITimeGraphEntry) {
+ return labelProvider.getColumnText(element, columnIndex);
+ }
+ return null;
+ }
+
+ }
+
+ /**
+ * The SelectionListenerWrapper is used to intercept the filler items from
+ * the time graph combo's real selection listener, and to prevent double
+ * notifications from being sent when selection changes in both tree and
+ * time graph at the same time.
+ */
+ private class SelectionListenerWrapper implements ISelectionChangedListener, ITimeGraphSelectionListener {
+ private final ITimeGraphSelectionListener listener;
+ private ITimeGraphEntry selection = null;
+
+ public SelectionListenerWrapper(ITimeGraphSelectionListener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ if (fInhibitTreeSelection) {
+ return;
+ }
+ Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
+ if (element instanceof ITimeGraphEntry) {
+ ITimeGraphEntry entry = (ITimeGraphEntry) element;
+ if (entry != selection) {
+ selection = entry;
+ listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));
+ }
+ }
+ }
+
+ @Override
+ public void selectionChanged(TimeGraphSelectionEvent event) {
+ ITimeGraphEntry entry = event.getSelection();
+ if (entry != selection) {
+ selection = entry;
+ listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ *
+ * @param parent a widget which will be the parent of the new instance (cannot be null)
+ * @param style the style of widget to construct
+ */
+ public TimeGraphCombo(Composite parent, int style) {
+ super(parent, style);
+ setLayout(new FillLayout());
+
+ final SashForm sash = new SashForm(this, SWT.NONE);
+
+ fTreeViewer = new TreeViewer(sash, SWT.FULL_SELECTION | SWT.H_SCROLL);
+ final Tree tree = fTreeViewer.getTree();
+ tree.setHeaderVisible(true);
+ tree.setLinesVisible(true);
+
+ fTimeGraphViewer = new TimeGraphViewer(sash, SWT.NONE);
+ fTimeGraphViewer.setItemHeight(getItemHeight(tree));
+ fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
+ fTimeGraphViewer.setBorderWidth(tree.getBorderWidth());
+ fTimeGraphViewer.setNameWidthPref(0);
+
+ // Feature in Windows. The tree vertical bar reappears when
+ // the control is resized so we need to hide it again.
+ // Bug in Linux. The tree header height is 0 in constructor,
+ // so we need to reset it later when the control is resized.
+ tree.addControlListener(new ControlAdapter() {
+ int depth = 0;
+ @Override
+ public void controlResized(ControlEvent e) {
+ if (depth == 0) {
+ depth++;
+ tree.getVerticalBar().setEnabled(false);
+ // this can trigger controlResized recursively
+ tree.getVerticalBar().setVisible(false);
+ depth--;
+ }
+ fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
+ }
+ });
+
+ // ensure synchronization of expanded items between tree and time graph
+ fTreeViewer.addTreeListener(new ITreeViewerListener() {
+ @Override
+ public void treeCollapsed(TreeExpansionEvent event) {
+ fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), false);
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() == 0) {
+ return;
+ }
+ TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
+ tree.setTopItem(treeItem);
+ }
+
+ @Override
+ public void treeExpanded(TreeExpansionEvent event) {
+ fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), true);
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() == 0) {
+ return;
+ }
+ final TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
+ // queue the top item update because the tree can change its top item
+ // autonomously immediately after the listeners have been notified
+ getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ tree.setTopItem(treeItem);
+ }});
+ }
+ });
+
+ // ensure synchronization of expanded items between tree and time graph
+ fTimeGraphViewer.addTreeListener(new ITimeGraphTreeListener() {
+ @Override
+ public void treeCollapsed(TimeGraphTreeExpansionEvent event) {
+ fTreeViewer.setExpandedState(event.getEntry(), false);
+ }
+
+ @Override
+ public void treeExpanded(TimeGraphTreeExpansionEvent event) {
+ fTreeViewer.setExpandedState(event.getEntry(), true);
+ }
+ });
+
+ // prevent mouse button from selecting a filler tree item
+ tree.addListener(SWT.MouseDown, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ TreeItem treeItem = tree.getItem(new Point(event.x, event.y));
+ if (treeItem == null || treeItem.getData() == FILLER) {
+ event.doit = false;
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() == 0) {
+ fTreeViewer.setSelection(new StructuredSelection());
+ fTimeGraphViewer.setSelection(null);
+ return;
+ }
+ // this prevents from scrolling up when selecting
+ // the partially visible tree item at the bottom
+ tree.select(treeItems.get(treeItems.size() - 1));
+ fTreeViewer.setSelection(new StructuredSelection());
+ fTimeGraphViewer.setSelection(null);
+ }
+ }
+ });
+
+ // prevent mouse wheel from scrolling down into filler tree items
+ tree.addListener(SWT.MouseWheel, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ event.doit = false;
+ Slider scrollBar = fTimeGraphViewer.getVerticalBar();
+ fTimeGraphViewer.setTopIndex(scrollBar.getSelection() - event.count);
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() == 0) {
+ return;
+ }
+ TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
+ tree.setTopItem(treeItem);
+ }
+ });
+
+ // prevent key stroke from selecting a filler tree item
+ tree.addListener(SWT.KeyDown, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() == 0) {
+ fTreeViewer.setSelection(new StructuredSelection());
+ event.doit = false;
+ return;
+ }
+ if (event.keyCode == SWT.ARROW_DOWN) {
+ int index = Math.min(fTimeGraphViewer.getSelectionIndex() + 1, treeItems.size() - 1);
+ fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
+ event.doit = false;
+ } else if (event.keyCode == SWT.PAGE_DOWN) {
+ int height = tree.getSize().y - tree.getHeaderHeight() - tree.getHorizontalBar().getSize().y;
+ int countPerPage = height / getItemHeight(tree);
+ int index = Math.min(fTimeGraphViewer.getSelectionIndex() + countPerPage - 1, treeItems.size() - 1);
+ fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
+ event.doit = false;
+ } else if (event.keyCode == SWT.END) {
+ fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(treeItems.size() - 1).getData());
+ event.doit = false;
+ }
+ TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
+ tree.setTopItem(treeItem);
+ if (fTimeGraphViewer.getSelectionIndex() >= 0) {
+ fTreeViewer.setSelection(new StructuredSelection(fTimeGraphViewer.getSelection()));
+ } else {
+ fTreeViewer.setSelection(new StructuredSelection());
+ }
+ }
+ });
+
+ // ensure alignment of top item between tree and time graph
+ fTimeGraphViewer.getTimeGraphControl().addControlListener(new ControlAdapter() {
+ @Override
+ public void controlResized(ControlEvent e) {
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() == 0) {
+ return;
+ }
+ TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
+ tree.setTopItem(treeItem);
+ }
+ });
+
+ // ensure synchronization of selected item between tree and time graph
+ fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ if (fInhibitTreeSelection) {
+ return;
+ }
+ if (event.getSelection() instanceof IStructuredSelection) {
+ Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
+ if (selection instanceof ITimeGraphEntry) {
+ fTimeGraphViewer.setSelection((ITimeGraphEntry) selection);
+ }
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() == 0) {
+ return;
+ }
+ TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
+ tree.setTopItem(treeItem);
+ }
+ }
+ });
+
+ // ensure synchronization of selected item between tree and time graph
+ fTimeGraphViewer.addSelectionListener(new ITimeGraphSelectionListener() {
+ @Override
+ public void selectionChanged(TimeGraphSelectionEvent event) {
+ ITimeGraphEntry entry = fTimeGraphViewer.getSelection();
+ fInhibitTreeSelection = true; // block the tree selection changed listener
+ if (entry != null) {
+ StructuredSelection selection = new StructuredSelection(entry);
+ fTreeViewer.setSelection(selection);
+ } else {
+ fTreeViewer.setSelection(new StructuredSelection());
+ }
+ fInhibitTreeSelection = false;
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() == 0) {
+ return;
+ }
+ TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
+ tree.setTopItem(treeItem);
+ }
+ });
+
+ // ensure alignment of top item between tree and time graph
+ fTimeGraphViewer.getVerticalBar().addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() == 0) {
+ return;
+ }
+ TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
+ tree.setTopItem(treeItem);
+ }
+ });
+
+ // ensure alignment of top item between tree and time graph
+ fTimeGraphViewer.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
+ @Override
+ public void mouseScrolled(MouseEvent e) {
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() == 0) {
+ return;
+ }
+ TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
+ tree.setTopItem(treeItem);
+ }
+ });
+
+ // ensure the tree has focus control when mouse is over it if the time graph had control
+ fTreeViewer.getControl().addMouseTrackListener(new MouseTrackAdapter() {
+ @Override
+ public void mouseEnter(MouseEvent e) {
+ if (fTimeGraphViewer.getTimeGraphControl().isFocusControl()) {
+ fTreeViewer.getControl().setFocus();
+ }
+ }
+ });
+
+ // ensure the time graph has focus control when mouse is over it if the tree had control
+ fTimeGraphViewer.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
+ @Override
+ public void mouseEnter(MouseEvent e) {
+ if (fTreeViewer.getControl().isFocusControl()) {
+ fTimeGraphViewer.getTimeGraphControl().setFocus();
+ }
+ }
+ });
+ fTimeGraphViewer.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
+ @Override
+ public void mouseEnter(MouseEvent e) {
+ if (fTreeViewer.getControl().isFocusControl()) {
+ fTimeGraphViewer.getTimeGraphControl().setFocus();
+ }
+ }
+ });
+
+ // The filler rows are required to ensure alignment when the tree does not have a
+ // visible horizontal scroll bar. The tree does not allow its top item to be set
+ // to a value that would cause blank space to be drawn at the bottom of the tree.
+ fNumFillerRows = Display.getDefault().getBounds().height / getItemHeight(tree);
+
+ sash.setWeights(new int[] { 1, 1 });
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns this time graph combo's tree viewer.
+ *
+ * @return the tree viewer
+ */
+ public TreeViewer getTreeViewer() {
+ return fTreeViewer;
+ }
+
+ /**
+ * Returns this time graph combo's time graph viewer.
+ *
+ * @return the time graph viewer
+ */
+ public TimeGraphViewer getTimeGraphViewer() {
+ return fTimeGraphViewer;
+ }
+
+ // ------------------------------------------------------------------------
+ // Control
+ // ------------------------------------------------------------------------
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Control#redraw()
+ */
+ @Override
+ public void redraw() {
+ fTimeGraphViewer.getControl().redraw();
+ super.redraw();
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ /**
+ * Sets the tree content provider used by this time graph combo.
+ *
+ * @param contentProvider the tree content provider
+ */
+ public void setTreeContentProvider(ITreeContentProvider contentProvider) {
+ fTreeViewer.setContentProvider(new TreeContentProviderWrapper(contentProvider));
+ }
+
+ /**
+ * Sets the tree label provider used by this time graph combo.
+ *
+ * @param labelProvider the tree label provider
+ */
+ public void setTreeLabelProvider(ITableLabelProvider labelProvider) {
+ fTreeViewer.setLabelProvider(new TreeLabelProviderWrapper(labelProvider));
+ }
+
+ /**
+ * Sets the tree columns for this time graph combo.
+ *
+ * @param columnNames the tree column names
+ */
+ public void setTreeColumns(String[] columnNames) {
+ final Tree tree = fTreeViewer.getTree();
+ for (String columnName : columnNames) {
+ TreeColumn column = new TreeColumn(tree, SWT.LEFT);
+ column.setText(columnName);
+ column.pack();
+ }
+ }
+
+ /**
+ * Sets the time graph provider used by this time graph combo.
+ *
+ * @param timeGraphProvider the time graph provider
+ */
+ public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
+ fTimeGraphViewer.setTimeGraphProvider(timeGraphProvider);
+ }
+
+ /**
+ * Sets or clears the input for this time graph combo.
+ * The input array should only contain top-level elements.
+ *
+ * @param input the input of this time graph combo, or <code>null</code> if none
+ */
+ public void setInput(ITimeGraphEntry[] input) {
+ fInhibitTreeSelection = true;
+ fTreeViewer.setInput(input);
+ for (SelectionListenerWrapper listenerWrapper : fSelectionListenerMap.values()) {
+ listenerWrapper.selection = null;
+ }
+ fInhibitTreeSelection = false;
+ fTreeViewer.expandAll();
+ fTreeViewer.getTree().getVerticalBar().setEnabled(false);
+ fTreeViewer.getTree().getVerticalBar().setVisible(false);
+ fTimeGraphViewer.setItemHeight(getItemHeight(fTreeViewer.getTree()));
+ fTimeGraphViewer.setInput(input);
+ }
+
+ /**
+ * Refreshes this time graph completely with information freshly obtained from its model.
+ */
+ public void refresh() {
+ fInhibitTreeSelection = true;
+ fTreeViewer.refresh();
+ fTimeGraphViewer.refresh();
+ fInhibitTreeSelection = false;
+ }
+
+ /**
+ * Adds a listener for selection changes in this time graph combo.
+ *
+ * @param listener a selection listener
+ */
+ public void addSelectionListener(ITimeGraphSelectionListener listener) {
+ SelectionListenerWrapper listenerWrapper = new SelectionListenerWrapper(listener);
+ fTreeViewer.addSelectionChangedListener(listenerWrapper);
+ fSelectionListenerMap.put(listener, listenerWrapper);
+ fTimeGraphViewer.addSelectionListener(listenerWrapper);
+ }
+
+ /**
+ * Removes the given selection listener from this time graph combo.
+ *
+ * @param listener a selection changed listener
+ */
+ public void removeSelectionListener(ITimeGraphSelectionListener listener) {
+ SelectionListenerWrapper listenerWrapper = fSelectionListenerMap.remove(listener);
+ fTreeViewer.removeSelectionChangedListener(listenerWrapper);
+ fTimeGraphViewer.removeSelectionListener(listenerWrapper);
+ }
+
+ /**
+ * Sets the current selection for this time graph combo.
+ *
+ * @param selection the new selection
+ */
+ public void setSelection(ITimeGraphEntry selection) {
+ fTimeGraphViewer.setSelection(selection);
+ fInhibitTreeSelection = true; // block the tree selection changed listener
+ if (selection != null) {
+ StructuredSelection structuredSelection = new StructuredSelection(selection);
+ fTreeViewer.setSelection(structuredSelection);
+ } else {
+ fTreeViewer.setSelection(new StructuredSelection());
+ }
+ fInhibitTreeSelection = false;
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(fTreeViewer.getTree());
+ if (treeItems.size() == 0) {
+ return;
+ }
+ TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
+ fTreeViewer.getTree().setTopItem(treeItem);
+ }
+
+ /**
+ * Set the expanded state of an entry
+ *
+ * @param entry
+ * The entry to expand/collapse
+ * @param expanded
+ * True for expanded, false for collapsed
+ *
+ * @since 2.0
+ */
+ public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
+ fTimeGraphViewer.setExpandedState(entry, expanded);
+ fTreeViewer.setExpandedState(entry, expanded);
+ }
+
+ /**
+ * Collapses all nodes of the viewer's tree, starting with the root.
+ *
+ * @since 2.0
+ */
+ public void collapseAll() {
+ fTimeGraphViewer.collapseAll();
+ fTreeViewer.collapseAll();
+ }
+
+ /**
+ * Expands all nodes of the viewer's tree, starting with the root.
+ *
+ * @since 2.0
+ */
+ public void expandAll() {
+ fTimeGraphViewer.expandAll();
+ fTreeViewer.expandAll();
+ }
+
+ // ------------------------------------------------------------------------
+ // Internal
+ // ------------------------------------------------------------------------
+
+ private ArrayList<TreeItem> getVisibleExpandedItems(Tree tree) {
+ ArrayList<TreeItem> items = new ArrayList<TreeItem>();
+ for (TreeItem item : tree.getItems()) {
+ if (item.getData() == FILLER) {
+ break;
+ }
+ items.add(item);
+ if (item.getExpanded()) {
+ items.addAll(getVisibleExpandedItems(item));
+ }
+ }
+ return items;
+ }
+
+ private ArrayList<TreeItem> getVisibleExpandedItems(TreeItem treeItem) {
+ ArrayList<TreeItem> items = new ArrayList<TreeItem>();
+ for (TreeItem item : treeItem.getItems()) {
+ items.add(item);
+ if (item.getExpanded()) {
+ items.addAll(getVisibleExpandedItems(item));
+ }
+ }
+ return items;
+ }
+
+ private int getItemHeight(final Tree tree) {
+ /*
+ * Bug in Linux. The method getItemHeight doesn't always return the correct value.
+ */
+ if (fLinuxItemHeight >= 0 && System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
+ if (fLinuxItemHeight != 0) {
+ return fLinuxItemHeight;
+ }
+ ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ if (treeItems.size() > 1) {
+ final TreeItem treeItem0 = treeItems.get(0);
+ final TreeItem treeItem1 = treeItems.get(1);
+ PaintListener paintListener = new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent e) {
+ tree.removePaintListener(this);
+ int y0 = treeItem0.getBounds().y;
+ int y1 = treeItem1.getBounds().y;
+ int itemHeight = y1 - y0;
+ if (itemHeight > 0) {
+ fLinuxItemHeight = itemHeight;
+ fTimeGraphViewer.setItemHeight(itemHeight);
+ }
+ }
+ };
+ tree.addPaintListener(paintListener);
+ }
+ } else {
+ fLinuxItemHeight = -1; // Not Linux, don't perform os.name check anymore
+ }
+ return tree.getItemHeight();
+ }
+
+}
-/*****************************************************************************\r
- * Copyright (c) 2007, 2008 Intel Corporation, 2009, 2010, 2011, 2012 Ericsson.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * Intel Corporation - Initial API and implementation\r
- * Ruslan A. Scherbakov, Intel - Initial API and implementation\r
- * Alexander N. Alexeev, Intel - Add monitors statistics support\r
- * Alvaro Sanchez-Leon - Adapted for TMF\r
- * Patrick Tasse - Refactoring\r
- *\r
- *****************************************************************************/\r
-\r
-package org.eclipse.linuxtools.tmf.ui.widgets.timegraph;\r
-\r
-import java.util.ArrayList;\r
-\r
-import org.eclipse.jface.action.Action;\r
-import org.eclipse.jface.viewers.ISelectionProvider;\r
-import org.eclipse.linuxtools.internal.tmf.ui.Activator;\r
-import org.eclipse.linuxtools.internal.tmf.ui.ITmfImageConstants;\r
-import org.eclipse.linuxtools.internal.tmf.ui.Messages;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.dialogs.TimeGraphLegend;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.ITimeDataProvider;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphColorScheme;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphScale;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphTooltipHandler;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.events.ControlAdapter;\r
-import org.eclipse.swt.events.ControlEvent;\r
-import org.eclipse.swt.events.KeyAdapter;\r
-import org.eclipse.swt.events.KeyEvent;\r
-import org.eclipse.swt.events.MouseEvent;\r
-import org.eclipse.swt.events.MouseWheelListener;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.events.SelectionListener;\r
-import org.eclipse.swt.graphics.Rectangle;\r
-import org.eclipse.swt.layout.FillLayout;\r
-import org.eclipse.swt.layout.GridData;\r
-import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Control;\r
-import org.eclipse.swt.widgets.ScrollBar;\r
-import org.eclipse.swt.widgets.Slider;\r
-\r
-/**\r
- * Generic time graph viewer implementation\r
- *\r
- * @version 1.0\r
- * @author Patrick Tasse, and others\r
- */\r
-public class TimeGraphViewer implements ITimeDataProvider, SelectionListener {\r
-\r
- /** vars */\r
- private long _minTimeInterval;\r
- private long _selectedTime;\r
- private ITimeGraphEntry _selectedEntry;\r
- private long _beginTime;\r
- private long _endTime;\r
- private long _time0;\r
- private long _time1;\r
- private long _time0_;\r
- private long _time1_;\r
- private long _time0_extSynch = 0;\r
- private long _time1_extSynch = 0;\r
- private boolean _timeRangeFixed;\r
- private int _nameWidthPref = 200;\r
- private int _minNameWidth = 6;\r
- private int _nameWidth;\r
- private Composite _dataViewer;\r
-\r
- private TimeGraphControl _stateCtrl;\r
- private TimeGraphScale _timeScaleCtrl;\r
- private Slider _verticalScrollBar;\r
- private TimeGraphTooltipHandler _threadTip;\r
- private TimeGraphColorScheme _colors;\r
- private ITimeGraphPresentationProvider fTimeGraphProvider;\r
-\r
- ArrayList<ITimeGraphSelectionListener> fSelectionListeners = new ArrayList<ITimeGraphSelectionListener>();\r
- ArrayList<ITimeGraphTimeListener> fTimeListeners = new ArrayList<ITimeGraphTimeListener>();\r
- ArrayList<ITimeGraphRangeListener> fRangeListeners = new ArrayList<ITimeGraphRangeListener>();\r
-\r
- // Calender Time format, using Epoch reference or Relative time\r
- // format(default\r
- private boolean calendarTimeFormat = false;\r
- private int borderWidth = 0;\r
- private int timeScaleHeight = 22;\r
-\r
- private Action resetScale;\r
- private Action showLegendAction;\r
- private Action nextEventAction;\r
- private Action prevEventAction;\r
- private Action nextItemAction;\r
- private Action previousItemAction;\r
- private Action zoomInAction;\r
- private Action zoomOutAction;\r
-\r
- /**\r
- * Standard constructor\r
- *\r
- * @param parent\r
- * The parent UI composite object\r
- * @param style\r
- * The style to use\r
- */\r
- public TimeGraphViewer(Composite parent, int style) {\r
- createDataViewer(parent, style);\r
- }\r
-\r
- /**\r
- * Sets the timegraph provider used by this timegraph viewer.\r
- *\r
- * @param timeGraphProvider the timegraph provider\r
- */\r
- public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {\r
- fTimeGraphProvider = timeGraphProvider;\r
- _stateCtrl.setTimeGraphProvider(timeGraphProvider);\r
- _threadTip = new TimeGraphTooltipHandler(_dataViewer.getShell(), fTimeGraphProvider, this);\r
- _threadTip.activateHoverHelp(_stateCtrl);\r
- }\r
-\r
- /**\r
- * Sets or clears the input for this time graph viewer.\r
- * The input array should only contain top-level elements.\r
- *\r
- * @param input the input of this time graph viewer, or <code>null</code> if none\r
- */\r
- public void setInput(ITimeGraphEntry[] input) {\r
- if (null != _stateCtrl) {\r
- if (null == input) {\r
- input = new ITimeGraphEntry[0];\r
- }\r
- setTimeRange(input);\r
- _verticalScrollBar.setEnabled(true);\r
- setTopIndex(0);\r
- _selectedTime = 0;\r
- _selectedEntry = null;\r
- refreshAllData(input);\r
- }\r
- }\r
-\r
- /**\r
- * Refresh the view\r
- */\r
- public void refresh() {\r
- setInput(_stateCtrl.getTraces());\r
- }\r
-\r
- /**\r
- * Callback for when the control is moved\r
- *\r
- * @param e\r
- * The caller event\r
- */\r
- public void controlMoved(ControlEvent e) {\r
- }\r
-\r
- /**\r
- * Callback for when the control is resized\r
- *\r
- * @param e\r
- * The caller event\r
- */\r
- public void controlResized(ControlEvent e) {\r
- resizeControls();\r
- }\r
-\r
- /**\r
- * Handler for when the model is updated. Called from the display order in\r
- * the API\r
- *\r
- * @param traces\r
- * The traces in the model\r
- * @param start\r
- * The start time\r
- * @param end\r
- * The end time\r
- * @param updateTimeBounds\r
- * Should we updated the time bounds too\r
- */\r
- public void modelUpdate(ITimeGraphEntry[] traces, long start,\r
- long end, boolean updateTimeBounds) {\r
- if (null != _stateCtrl) {\r
- //loadOptions();\r
- updateInternalData(traces, start, end);\r
- if (updateTimeBounds) {\r
- _timeRangeFixed = true;\r
- // set window to match limits\r
- setStartFinishTime(_time0_, _time1_);\r
- } else {\r
- _stateCtrl.redraw();\r
- _timeScaleCtrl.redraw();\r
- }\r
- }\r
- }\r
-\r
- protected String getViewTypeStr() {\r
- return "viewoption.threads"; //$NON-NLS-1$\r
- }\r
-\r
- int getMarginWidth(int idx) {\r
- return 0;\r
- }\r
-\r
- int getMarginHeight(int idx) {\r
- return 0;\r
- }\r
-\r
- void loadOptions() {\r
- _minTimeInterval = 1;\r
- _selectedTime = -1;\r
- _nameWidth = Utils.loadIntOption(getPreferenceString("namewidth"), //$NON-NLS-1$\r
- _nameWidthPref, _minNameWidth, 1000);\r
- }\r
-\r
- void saveOptions() {\r
- Utils.saveIntOption(getPreferenceString("namewidth"), _nameWidth); //$NON-NLS-1$\r
- }\r
-\r
- protected Control createDataViewer(Composite parent, int style) {\r
- loadOptions();\r
- _colors = new TimeGraphColorScheme();\r
- _dataViewer = new Composite(parent, style) {\r
- @Override\r
- public void redraw() {\r
- _timeScaleCtrl.redraw();\r
- _stateCtrl.redraw();\r
- super.redraw();\r
- }\r
- };\r
- GridLayout gl = new GridLayout(2, false);\r
- gl.marginHeight = borderWidth;\r
- gl.marginWidth = 0;\r
- gl.verticalSpacing = 0;\r
- gl.horizontalSpacing = 0;\r
- _dataViewer.setLayout(gl);\r
-\r
- _timeScaleCtrl = new TimeGraphScale(_dataViewer, _colors);\r
- _timeScaleCtrl.setTimeProvider(this);\r
- _timeScaleCtrl.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false));\r
- _timeScaleCtrl.setHeight(timeScaleHeight);\r
-\r
- _verticalScrollBar = new Slider(_dataViewer, SWT.VERTICAL | SWT.NO_FOCUS);\r
- _verticalScrollBar.setLayoutData(new GridData(SWT.DEFAULT, SWT.FILL, false, true, 1, 2));\r
- _verticalScrollBar.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- setTopIndex(_verticalScrollBar.getSelection());\r
- }\r
- });\r
- _verticalScrollBar.setEnabled(false);\r
-\r
- _stateCtrl = createTimeGraphControl();\r
-\r
- _stateCtrl.setTimeProvider(this);\r
- _stateCtrl.addSelectionListener(this);\r
- _stateCtrl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2));\r
- _stateCtrl.addMouseWheelListener(new MouseWheelListener() {\r
- @Override\r
- public void mouseScrolled(MouseEvent e) {\r
- adjustVerticalScrollBar();\r
- }\r
- });\r
- _stateCtrl.addKeyListener(new KeyAdapter() {\r
- @Override\r
- public void keyPressed(KeyEvent e) {\r
- adjustVerticalScrollBar();\r
- }\r
- });\r
-\r
- Composite filler = new Composite(_dataViewer, SWT.NONE);\r
- GridData gd = new GridData(SWT.DEFAULT, SWT.DEFAULT, false, false);\r
- gd.heightHint = _stateCtrl.getHorizontalBar().getSize().y;\r
- filler.setLayoutData(gd);\r
- filler.setLayout(new FillLayout());\r
-\r
- _stateCtrl.addControlListener(new ControlAdapter() {\r
- @Override\r
- public void controlResized(ControlEvent event) {\r
- resizeControls();\r
- }\r
- });\r
- resizeControls();\r
- _dataViewer.update();\r
- adjustVerticalScrollBar();\r
- return _dataViewer;\r
- }\r
-\r
- /**\r
- * Dispose the view.\r
- */\r
- public void dispose() {\r
- saveOptions();\r
- _stateCtrl.dispose();\r
- _dataViewer.dispose();\r
- _colors.dispose();\r
- }\r
-\r
- protected TimeGraphControl createTimeGraphControl() {\r
- return new TimeGraphControl(_dataViewer, _colors);\r
- }\r
-\r
- /**\r
- * Resize the controls\r
- */\r
- public void resizeControls() {\r
- Rectangle r = _dataViewer.getClientArea();\r
- if (r.isEmpty()) {\r
- return;\r
- }\r
-\r
- int width = r.width;\r
- if (_nameWidth > width - _minNameWidth) {\r
- _nameWidth = width - _minNameWidth;\r
- }\r
- if (_nameWidth < _minNameWidth) {\r
- _nameWidth = _minNameWidth;\r
- }\r
- adjustVerticalScrollBar();\r
- }\r
-\r
- /**\r
- * Try to set most convenient time range for display.\r
- *\r
- * @param traces\r
- * The traces in the model\r
- */\r
- public void setTimeRange(ITimeGraphEntry traces[]) {\r
- _endTime = 0;\r
- _beginTime = -1;\r
- for (int i = 0; i < traces.length; i++) {\r
- ITimeGraphEntry entry = traces[i];\r
- if (entry.getEndTime() >= entry.getStartTime() && entry.getEndTime() > 0) {\r
- if (_beginTime < 0 || entry.getStartTime() < _beginTime) {\r
- _beginTime = entry.getStartTime();\r
- }\r
- if (entry.getEndTime() > _endTime) {\r
- _endTime = entry.getEndTime();\r
- }\r
- }\r
- }\r
-\r
- if (_beginTime < 0) {\r
- _beginTime = 0;\r
- }\r
- }\r
-\r
- /**\r
- * Recalculate the time bounds\r
- */\r
- public void setTimeBounds() {\r
- //_time0_ = _beginTime - (long) ((_endTime - _beginTime) * 0.02);\r
- _time0_ = _beginTime;\r
- if (_time0_ < 0) {\r
- _time0_ = 0;\r
- }\r
- // _time1_ = _time0_ + (_endTime - _time0_) * 1.05;\r
- _time1_ = _endTime;\r
- // _time0_ = Math.floor(_time0_);\r
- // _time1_ = Math.ceil(_time1_);\r
- if (!_timeRangeFixed) {\r
- _time0 = _time0_;\r
- _time1 = _time1_;\r
- }\r
- if (_time1 - _time0 < _minTimeInterval) {\r
- _time1 = Math.min(_time1_, _time0 + _minTimeInterval);\r
- }\r
- }\r
-\r
- /**\r
- * @param traces\r
- * @param start\r
- * @param end\r
- */\r
- void updateInternalData(ITimeGraphEntry[] traces, long start, long end) {\r
- if (null == traces) {\r
- traces = new ITimeGraphEntry[0];\r
- }\r
- if ((start == 0 && end == 0) || start < 0 || end < 0) {\r
- // Start and end time are unspecified and need to be determined from\r
- // individual processes\r
- setTimeRange(traces);\r
- } else {\r
- _beginTime = start;\r
- _endTime = end;\r
- }\r
-\r
- refreshAllData(traces);\r
- }\r
-\r
- /**\r
- * @param traces\r
- */\r
- private void refreshAllData(ITimeGraphEntry[] traces) {\r
- setTimeBounds();\r
- if (_selectedTime < _beginTime) {\r
- _selectedTime = _beginTime;\r
- } else if (_selectedTime > _endTime) {\r
- _selectedTime = _endTime;\r
- }\r
- _stateCtrl.refreshData(traces);\r
- _timeScaleCtrl.redraw();\r
- adjustVerticalScrollBar();\r
- }\r
-\r
- /**\r
- * Callback for when this view is focused\r
- */\r
- public void setFocus() {\r
- if (null != _stateCtrl) {\r
- _stateCtrl.setFocus();\r
- }\r
- }\r
-\r
- /**\r
- * Get the current focus status of this view.\r
- *\r
- * @return If the view is currently focused, or not\r
- */\r
- public boolean isInFocus() {\r
- return _stateCtrl.isInFocus();\r
- }\r
-\r
- /**\r
- * Get the view's current selection\r
- *\r
- * @return The entry that is selected\r
- */\r
- public ITimeGraphEntry getSelection() {\r
- return _stateCtrl.getSelectedTrace();\r
- }\r
-\r
- /**\r
- * Get the index of the current selection\r
- *\r
- * @return The index\r
- */\r
- public int getSelectionIndex() {\r
- return _stateCtrl.getSelectedIndex();\r
- }\r
-\r
- @Override\r
- public long getTime0() {\r
- return _time0;\r
- }\r
-\r
- @Override\r
- public long getTime1() {\r
- return _time1;\r
- }\r
-\r
- @Override\r
- public long getMinTimeInterval() {\r
- return _minTimeInterval;\r
- }\r
-\r
- @Override\r
- public int getNameSpace() {\r
- return _nameWidth;\r
- }\r
-\r
- @Override\r
- public void setNameSpace(int width) {\r
- _nameWidth = width;\r
- width = _stateCtrl.getClientArea().width;\r
- if (_nameWidth > width - 6) {\r
- _nameWidth = width - 6;\r
- }\r
- if (_nameWidth < 6) {\r
- _nameWidth = 6;\r
- }\r
- _stateCtrl.adjustScrolls();\r
- _stateCtrl.redraw();\r
- _timeScaleCtrl.redraw();\r
- }\r
-\r
- @Override\r
- public int getTimeSpace() {\r
- int w = _stateCtrl.getClientArea().width;\r
- return w - _nameWidth;\r
- }\r
-\r
- @Override\r
- public long getSelectedTime() {\r
- return _selectedTime;\r
- }\r
-\r
- @Override\r
- public long getBeginTime() {\r
- return _beginTime;\r
- }\r
-\r
- @Override\r
- public long getEndTime() {\r
- return _endTime;\r
- }\r
-\r
- @Override\r
- public long getMaxTime() {\r
- return _time1_;\r
- }\r
-\r
- @Override\r
- public long getMinTime() {\r
- return _time0_;\r
- }\r
-\r
- /*\r
- * (non-Javadoc)\r
- *\r
- * @see\r
- * org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets.ITimeDataProvider\r
- * #setStartFinishTimeNotify(long, long)\r
- */\r
- @Override\r
- public void setStartFinishTimeNotify(long time0, long time1) {\r
- setStartFinishTime(time0, time1);\r
- notifyRangeListeners(time0, time1);\r
- }\r
-\r
-\r
- /* (non-Javadoc)\r
- * @see org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets.ITimeDataProvider#notifyStartFinishTime()\r
- */\r
- @Override\r
- public void notifyStartFinishTime() {\r
- notifyRangeListeners(_time0, _time1);\r
- }\r
-\r
- /*\r
- * (non-Javadoc)\r
- *\r
- * @see\r
- * org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets.ITimeDataProvider\r
- * #setStartFinishTime(long, long)\r
- */\r
- @Override\r
- public void setStartFinishTime(long time0, long time1) {\r
- _time0 = time0;\r
- if (_time0 < _time0_) {\r
- _time0 = _time0_;\r
- }\r
- if (_time0 > _time1_) {\r
- _time0 = _time1_;\r
- }\r
- _time1 = time1;\r
- if (_time1 < _time0_) {\r
- _time1 = _time0_;\r
- }\r
- if (_time1 > _time1_) {\r
- _time1 = _time1_;\r
- }\r
- if (_time1 - _time0 < _minTimeInterval) {\r
- _time1 = Math.min(_time1_, _time0 + _minTimeInterval);\r
- }\r
- _timeRangeFixed = true;\r
- _stateCtrl.adjustScrolls();\r
- _stateCtrl.redraw();\r
- _timeScaleCtrl.redraw();\r
- }\r
-\r
- /**\r
- * Set the time bounds to the provided values\r
- *\r
- * @param beginTime\r
- * The start time of the window\r
- * @param endTime\r
- * The end time\r
- */\r
- public void setTimeBounds(long beginTime, long endTime) {\r
- _beginTime = beginTime;\r
- _endTime = endTime;\r
- _time0_ = beginTime;\r
- _time1_ = endTime;\r
- _stateCtrl.adjustScrolls();\r
- }\r
-\r
- @Override\r
- public void resetStartFinishTime() {\r
- setStartFinishTimeNotify(_time0_, _time1_);\r
- _timeRangeFixed = false;\r
- }\r
-\r
- @Override\r
- public void setSelectedTimeNotify(long time, boolean ensureVisible) {\r
- setSelectedTimeInt(time, ensureVisible, true);\r
- }\r
-\r
- @Override\r
- public void setSelectedTime(long time, boolean ensureVisible) {\r
- setSelectedTimeInt(time, ensureVisible, false);\r
- }\r
-\r
- private void setSelectedTimeInt(long time, boolean ensureVisible, boolean doNotify) {\r
- long time0 = _time0;\r
- long time1 = _time1;\r
- if (ensureVisible) {\r
- long timeSpace = (long) ((_time1 - _time0) * .02);\r
- long timeMid = (long) ((_time1 - _time0) * .5);\r
- if (time < _time0 + timeSpace) {\r
- long dt = _time0 - time + timeMid;\r
- _time0 -= dt;\r
- _time1 -= dt;\r
- } else if (time > _time1 - timeSpace) {\r
- long dt = time - _time1 + timeMid;\r
- _time0 += dt;\r
- _time1 += dt;\r
- }\r
- if (_time0 < _time0_) {\r
- _time1 = Math.min(_time1_, _time1 + (_time0_ - _time0));\r
- _time0 = _time0_;\r
- } else if (_time1 > _time1_) {\r
- _time0 = Math.max(_time0_, _time0 - (_time1 - _time1_));\r
- _time1 = _time1_;\r
- }\r
- }\r
- if (_time1 - _time0 < _minTimeInterval) {\r
- _time1 = Math.min(_time1_, _time0 + _minTimeInterval);\r
- }\r
- _stateCtrl.adjustScrolls();\r
- _stateCtrl.redraw();\r
- _timeScaleCtrl.redraw();\r
-\r
-\r
- boolean notifySelectedTime = (time != _selectedTime);\r
- _selectedTime = time;\r
-\r
- if (doNotify && ((time0 != _time0) || (time1 != _time1))) {\r
- notifyRangeListeners(_time0, _time1);\r
- }\r
-\r
- if (doNotify && notifySelectedTime) {\r
- notifyTimeListeners(_selectedTime);\r
- }\r
- }\r
-\r
- @Override\r
- public void widgetDefaultSelected(SelectionEvent e) {\r
- if (_selectedEntry != getSelection()) {\r
- _selectedEntry = getSelection();\r
- notifySelectionListeners(_selectedEntry);\r
- }\r
- }\r
-\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- if (_selectedEntry != getSelection()) {\r
- _selectedEntry = getSelection();\r
- notifySelectionListeners(_selectedEntry);\r
- }\r
- }\r
-\r
- /**\r
- * Callback for when the next event is selected\r
- */\r
- public void selectNextEvent() {\r
- _stateCtrl.selectNextEvent();\r
- adjustVerticalScrollBar();\r
- }\r
-\r
- /**\r
- * Callback for when the previous event is selected\r
- */\r
- public void selectPrevEvent() {\r
- _stateCtrl.selectPrevEvent();\r
- adjustVerticalScrollBar();\r
- }\r
-\r
- /**\r
- * Callback for when the next item is selected\r
- */\r
- public void selectNextItem() {\r
- _stateCtrl.selectNextTrace();\r
- adjustVerticalScrollBar();\r
- }\r
-\r
- /**\r
- * Callback for when the previous item is selected\r
- */\r
- public void selectPrevItem() {\r
- _stateCtrl.selectPrevTrace();\r
- adjustVerticalScrollBar();\r
- }\r
-\r
- /**\r
- * Callback for the show legend action\r
- */\r
- public void showLegend() {\r
- if (_dataViewer == null || _dataViewer.isDisposed()) {\r
- return;\r
- }\r
-\r
- TimeGraphLegend.open(_dataViewer.getShell(), fTimeGraphProvider);\r
- }\r
-\r
- /**\r
- * Callback for the Zoom In action\r
- */\r
- public void zoomIn() {\r
- _stateCtrl.zoomIn();\r
- }\r
-\r
- /**\r
- * Callback for the Zoom Out action\r
- */\r
- public void zoomOut() {\r
- _stateCtrl.zoomOut();\r
- }\r
-\r
- private String getPreferenceString(String string) {\r
- return getViewTypeStr() + "." + string; //$NON-NLS-1$\r
- }\r
-\r
- /**\r
- * Add a selection listener\r
- *\r
- * @param listener\r
- * The listener to add\r
- */\r
- public void addSelectionListener(ITimeGraphSelectionListener listener) {\r
- fSelectionListeners.add(listener);\r
- }\r
-\r
- /**\r
- * Remove a selection listener\r
- *\r
- * @param listener\r
- * The listener to remove\r
- */\r
- public void removeSelectionListener(ITimeGraphSelectionListener listener) {\r
- fSelectionListeners.remove(listener);\r
- }\r
-\r
- private void notifySelectionListeners(ITimeGraphEntry selection) {\r
- TimeGraphSelectionEvent event = new TimeGraphSelectionEvent(this, selection);\r
-\r
- for (ITimeGraphSelectionListener listener : fSelectionListeners) {\r
- listener.selectionChanged(event);\r
- }\r
- }\r
-\r
- /**\r
- * Add a time listener\r
- *\r
- * @param listener\r
- * The listener to add\r
- */\r
- public void addTimeListener(ITimeGraphTimeListener listener) {\r
- fTimeListeners.add(listener);\r
- }\r
-\r
- /**\r
- * Remove a time listener\r
- *\r
- * @param listener\r
- * The listener to remove\r
- */\r
- public void removeTimeListener(ITimeGraphTimeListener listener) {\r
- fTimeListeners.remove(listener);\r
- }\r
-\r
- private void notifyTimeListeners(long time) {\r
- TimeGraphTimeEvent event = new TimeGraphTimeEvent(this, time);\r
-\r
- for (ITimeGraphTimeListener listener : fTimeListeners) {\r
- listener.timeSelected(event);\r
- }\r
- }\r
-\r
- /**\r
- * Add a range listener\r
- *\r
- * @param listener\r
- * The listener to add\r
- */\r
- public void addRangeListener(ITimeGraphRangeListener listener) {\r
- fRangeListeners.add(listener);\r
- }\r
-\r
- /**\r
- * Remove a range listener\r
- *\r
- * @param listener\r
- * The listener to remove\r
- */\r
- public void removeRangeListener(ITimeGraphRangeListener listener) {\r
- fRangeListeners.remove(listener);\r
- }\r
-\r
- private void notifyRangeListeners(long startTime, long endTime) {\r
- // Check if the time has actually changed from last notification\r
- if (startTime != _time0_extSynch || endTime != _time1_extSynch) {\r
- // Notify Time Scale Selection Listeners\r
- TimeGraphRangeUpdateEvent event = new TimeGraphRangeUpdateEvent(this, startTime, endTime);\r
-\r
- for (ITimeGraphRangeListener listener : fRangeListeners) {\r
- listener.timeRangeUpdated(event);\r
- }\r
-\r
- // update external synch timers\r
- updateExtSynchTimers();\r
- }\r
- }\r
-\r
- /**\r
- * Callback to set a selected event in the view\r
- *\r
- * @param event\r
- * The event that was selected\r
- * @param source\r
- * The source of this selection event\r
- */\r
- public void setSelectedEvent(ITimeEvent event, Object source) {\r
- if (event == null || source == this) {\r
- return;\r
- }\r
- _selectedEntry = event.getEntry();\r
- _stateCtrl.selectItem(_selectedEntry, false);\r
-\r
- setSelectedTimeInt(event.getTime(), true, true);\r
- adjustVerticalScrollBar();\r
- }\r
-\r
- /**\r
- * Set the seeked time of a trace\r
- *\r
- * @param trace\r
- * The trace that was seeked\r
- * @param time\r
- * The target time\r
- * @param source\r
- * The source of this seek event\r
- */\r
- public void setSelectedTraceTime(ITimeGraphEntry trace, long time, Object source) {\r
- if (trace == null || source == this) {\r
- return;\r
- }\r
- _selectedEntry = trace;\r
- _stateCtrl.selectItem(trace, false);\r
-\r
- setSelectedTimeInt(time, true, true);\r
- }\r
-\r
- /**\r
- * Callback for a trace selection\r
- *\r
- * @param trace\r
- * The trace that was selected\r
- */\r
- public void setSelection(ITimeGraphEntry trace) {\r
- _selectedEntry = trace;\r
- _stateCtrl.selectItem(trace, false);\r
- adjustVerticalScrollBar();\r
- }\r
-\r
- /**\r
- * Callback for a time window selection\r
- *\r
- * @param time0\r
- * Start time of the range\r
- * @param time1\r
- * End time of the range\r
- * @param source\r
- * Source of the event\r
- */\r
- public void setSelectVisTimeWindow(long time0, long time1, Object source) {\r
- if (source == this) {\r
- return;\r
- }\r
-\r
- setStartFinishTime(time0, time1);\r
-\r
- // update notification time values since we are now in synch with the\r
- // external application\r
- updateExtSynchTimers();\r
- }\r
-\r
- /**\r
- * update the cache timers used to identify the need to send a time window\r
- * update to external registered listeners\r
- */\r
- private void updateExtSynchTimers() {\r
- // last time notification cache\r
- _time0_extSynch = _time0;\r
- _time1_extSynch = _time1;\r
- }\r
-\r
- /**\r
- * Set the calendar format\r
- *\r
- * @param toAbsoluteCaltime\r
- * True for absolute time, false for relative\r
- */\r
- public void setTimeCalendarFormat(boolean toAbsoluteCaltime) {\r
- calendarTimeFormat = toAbsoluteCaltime;\r
- }\r
-\r
- @Override\r
- public boolean isCalendarFormat() {\r
- return calendarTimeFormat;\r
- }\r
-\r
- /**\r
- * Retrieve the border width\r
- *\r
- * @return The width\r
- */\r
- public int getBorderWidth() {\r
- return borderWidth;\r
- }\r
-\r
- /**\r
- * Set the border width\r
- *\r
- * @param borderWidth\r
- * The width\r
- */\r
- public void setBorderWidth(int borderWidth) {\r
- if (borderWidth > -1) {\r
- this.borderWidth = borderWidth;\r
- GridLayout gl = (GridLayout)_dataViewer.getLayout();\r
- gl.marginHeight = borderWidth;\r
- }\r
- }\r
-\r
- /**\r
- * Retrieve the height of the header\r
- *\r
- * @return The height\r
- */\r
- public int getHeaderHeight() {\r
- return timeScaleHeight;\r
- }\r
-\r
- /**\r
- * Set the height of the header\r
- *\r
- * @param headerHeight\r
- * The height to set\r
- */\r
- public void setHeaderHeight(int headerHeight) {\r
- if (headerHeight > -1) {\r
- this.timeScaleHeight = headerHeight;\r
- _timeScaleCtrl.setHeight(headerHeight);\r
- }\r
- }\r
-\r
- /**\r
- * Retrieve the height of an item row\r
- *\r
- * @return The height\r
- */\r
- public int getItemHeight() {\r
- if (_stateCtrl != null) {\r
- return _stateCtrl.getItemHeight();\r
- }\r
- return 0;\r
- }\r
-\r
- /**\r
- * Set the height of an item row\r
- *\r
- * @param rowHeight\r
- * The height to set\r
- */\r
- public void setItemHeight(int rowHeight) {\r
- if (_stateCtrl != null) {\r
- _stateCtrl.setItemHeight(rowHeight);\r
- }\r
- }\r
-\r
- /**\r
- * Set the minimum item width\r
- *\r
- * @param width\r
- * The min width\r
- */\r
- public void setMinimumItemWidth(int width) {\r
- if (_stateCtrl != null) {\r
- _stateCtrl.setMinimumItemWidth(width);\r
- }\r
- }\r
-\r
- /**\r
- * Set the width for the name column\r
- *\r
- * @param width The width\r
- */\r
- public void setNameWidthPref(int width) {\r
- _nameWidthPref = width;\r
- if (width == 0) {\r
- _minNameWidth = 0;\r
- _nameWidth = 0;\r
- }\r
- }\r
-\r
- /**\r
- * Retrieve the configure width for the name column\r
- *\r
- * @param width\r
- * Unused?\r
- * @return The width\r
- */\r
- public int getNameWidthPref(int width) {\r
- return _nameWidthPref;\r
- }\r
-\r
- /**\r
- * Returns the primary control associated with this viewer.\r
- *\r
- * @return the SWT control which displays this viewer's content\r
- */\r
- public Control getControl() {\r
- return _dataViewer;\r
- }\r
-\r
- /**\r
- * Returns the time graph control associated with this viewer.\r
- *\r
- * @return the time graph control\r
- */\r
- TimeGraphControl getTimeGraphControl() {\r
- return _stateCtrl;\r
- }\r
-\r
- /**\r
- * Returns the time graph scale associated with this viewer.\r
- *\r
- * @return the time graph scale\r
- */\r
- TimeGraphScale getTimeGraphScale() {\r
- return _timeScaleCtrl;\r
- }\r
-\r
- /**\r
- * Get the selection provider\r
- *\r
- * @return the selection provider\r
- */\r
- public ISelectionProvider getSelectionProvider() {\r
- return _stateCtrl;\r
- }\r
-\r
- /**\r
- * Wait for the cursor\r
- *\r
- * @param waitInd\r
- * Wait indefinitely?\r
- */\r
- public void waitCursor(boolean waitInd) {\r
- _stateCtrl.waitCursor(waitInd);\r
- }\r
-\r
- /**\r
- * Get the horizontal scroll bar object\r
- *\r
- * @return The scroll bar\r
- */\r
- public ScrollBar getHorizontalBar() {\r
- return _stateCtrl.getHorizontalBar();\r
- }\r
-\r
- /**\r
- * Get the vertical scroll bar object\r
- *\r
- * @return The scroll bar\r
- */\r
- public Slider getVerticalBar() {\r
- return _verticalScrollBar;\r
- }\r
-\r
- /**\r
- * Set the given index as the top one\r
- *\r
- * @param index\r
- * The index that will go to the top\r
- */\r
- public void setTopIndex(int index) {\r
- _stateCtrl.setTopIndex(index);\r
- adjustVerticalScrollBar();\r
- }\r
-\r
- /**\r
- * Retrieve the current top index\r
- *\r
- * @return The top index\r
- */\r
- public int getTopIndex() {\r
- return _stateCtrl.getTopIndex();\r
- }\r
-\r
- /**\r
- * Set the expanded state of an entry\r
- *\r
- * @param entry\r
- * The entry to expand/collapse\r
- * @param expanded\r
- * True for expanded, false for collapsed\r
- */\r
- public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {\r
- _stateCtrl.setExpandedState(entry, expanded);\r
- adjustVerticalScrollBar();\r
- }\r
-\r
- /**\r
- * Get the number of sub-elements when expanded\r
- *\r
- * @return The element count\r
- */\r
- public int getExpandedElementCount() {\r
- return _stateCtrl.getExpandedElementCount();\r
- }\r
-\r
- /**\r
- * Get the sub-elements\r
- *\r
- * @return The array of entries that are below this one\r
- */\r
- public ITimeGraphEntry[] getExpandedElements() {\r
- return _stateCtrl.getExpandedElements();\r
- }\r
-\r
- /**\r
- * Add a tree listener\r
- *\r
- * @param listener\r
- * The listener to add\r
- */\r
- public void addTreeListener(ITimeGraphTreeListener listener) {\r
- _stateCtrl.addTreeListener(listener);\r
- }\r
-\r
- /**\r
- * Remove a tree listener\r
- *\r
- * @param listener\r
- * The listener to remove\r
- */\r
- public void removeTreeListener(ITimeGraphTreeListener listener) {\r
- _stateCtrl.removeTreeListener(listener);\r
- }\r
-\r
- /**\r
- * Get the reset scale action.\r
- *\r
- * @return The Action object\r
- */\r
- public Action getResetScaleAction() {\r
- if (resetScale == null) {\r
- // resetScale\r
- resetScale = new Action() {\r
- @Override\r
- public void run() {\r
- resetStartFinishTime();\r
- }\r
- };\r
- resetScale.setText(Messages.TmfTimeGraphViewer_ResetScaleActionNameText);\r
- resetScale.setToolTipText(Messages.TmfTimeGraphViewer_ResetScaleActionToolTipText);\r
- resetScale.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_HOME_MENU));\r
- }\r
- return resetScale;\r
- }\r
-\r
- /**\r
- * Get the show legend action.\r
- *\r
- * @return The Action object\r
- */\r
- public Action getShowLegendAction() {\r
- if (showLegendAction == null) {\r
- // showLegend\r
- showLegendAction = new Action() {\r
- @Override\r
- public void run() {\r
- showLegend();\r
- }\r
- };\r
- showLegendAction.setText(Messages.TmfTimeGraphViewer_LegendActionNameText);\r
- showLegendAction.setToolTipText(Messages.TmfTimeGraphViewer_LegendActionToolTipText);\r
- showLegendAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SHOW_LEGEND));\r
- }\r
-\r
- return showLegendAction;\r
- }\r
-\r
- /**\r
- * Get the the next event action.\r
- *\r
- * @return The action object\r
- */\r
- public Action getNextEventAction() {\r
- if (nextEventAction == null) {\r
- nextEventAction = new Action() {\r
- @Override\r
- public void run() {\r
- selectNextEvent();\r
- }\r
- };\r
-\r
- nextEventAction.setText(Messages.TmfTimeGraphViewer_NextEventActionNameText);\r
- nextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextEventActionToolTipText);\r
- nextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_EVENT));\r
- }\r
-\r
- return nextEventAction;\r
- }\r
-\r
- /**\r
- * Get the previous event action.\r
- *\r
- * @return The Action object\r
- */\r
- public Action getPreviousEventAction() {\r
- if (prevEventAction == null) {\r
- prevEventAction = new Action() {\r
- @Override\r
- public void run() {\r
- selectPrevEvent();\r
- }\r
- };\r
-\r
- prevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousEventActionNameText);\r
- prevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousEventActionToolTipText);\r
- prevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_EVENT));\r
- }\r
-\r
- return prevEventAction;\r
- }\r
-\r
- /**\r
- * Get the next item action.\r
- *\r
- * @return The Action object\r
- */\r
- public Action getNextItemAction() {\r
- if (nextItemAction == null) {\r
-\r
- nextItemAction = new Action() {\r
- @Override\r
- public void run() {\r
- selectNextItem();\r
- }\r
- };\r
- nextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText);\r
- nextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText);\r
- nextItemAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_ITEM));\r
- }\r
- return nextItemAction;\r
- }\r
-\r
- /**\r
- * Get the previous item action.\r
- *\r
- * @return The Action object\r
- */\r
- public Action getPreviousItemAction() {\r
- if (previousItemAction == null) {\r
-\r
- previousItemAction = new Action() {\r
- @Override\r
- public void run() {\r
- selectPrevItem();\r
- }\r
- };\r
- previousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);\r
- previousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText);\r
- previousItemAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_ITEM));\r
- }\r
- return previousItemAction;\r
- }\r
-\r
- /**\r
- * Get the zoom in action\r
- *\r
- * @return The Action object\r
- */\r
- public Action getZoomInAction() {\r
- if (zoomInAction == null) {\r
- zoomInAction = new Action() {\r
- @Override\r
- public void run() {\r
- zoomIn();\r
- }\r
- };\r
- zoomInAction.setText(Messages.TmfTimeGraphViewer_ZoomInActionNameText);\r
- zoomInAction.setToolTipText(Messages.TmfTimeGraphViewer_ZoomInActionToolTipText);\r
- zoomInAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ZOOM_IN_MENU));\r
- }\r
- return zoomInAction;\r
- }\r
-\r
- /**\r
- * Get the zoom out action\r
- *\r
- * @return The Action object\r
- */\r
- public Action getZoomOutAction() {\r
- if (zoomOutAction == null) {\r
- zoomOutAction = new Action() {\r
- @Override\r
- public void run() {\r
- zoomOut();\r
- }\r
- };\r
- zoomOutAction.setText(Messages.TmfTimeGraphViewer_ZoomOutActionNameText);\r
- zoomOutAction.setToolTipText(Messages.TmfTimeGraphViewer_ZoomOutActionToolTipText);\r
- zoomOutAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ZOOM_OUT_MENU));\r
- }\r
- return zoomOutAction;\r
- }\r
-\r
-\r
- private void adjustVerticalScrollBar() {\r
- int topIndex = _stateCtrl.getTopIndex();\r
- int countPerPage = _stateCtrl.countPerPage();\r
- int expandedElementCount = _stateCtrl.getExpandedElementCount();\r
- if (topIndex + countPerPage > expandedElementCount) {\r
- _stateCtrl.setTopIndex(Math.max(0, expandedElementCount - countPerPage));\r
- }\r
-\r
- int selection = _stateCtrl.getTopIndex();\r
- int min = 0;\r
- int max = Math.max(1, expandedElementCount - 1);\r
- int thumb = Math.min(max, Math.max(1, countPerPage - 1));\r
- int increment = 1;\r
- int pageIncrement = Math.max(1, countPerPage);\r
- _verticalScrollBar.setValues(selection, min, max, thumb, increment, pageIncrement);\r
- }\r
-\r
-\r
-\r
-}\r
+/*****************************************************************************
+ * Copyright (c) 2007, 2008 Intel Corporation, 2009, 2010, 2011, 2012 Ericsson.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Intel Corporation - Initial API and implementation
+ * Ruslan A. Scherbakov, Intel - Initial API and implementation
+ * Alexander N. Alexeev, Intel - Add monitors statistics support
+ * Alvaro Sanchez-Leon - Adapted for TMF
+ * Patrick Tasse - Refactoring
+ *
+ *****************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.widgets.timegraph;
+
+import java.util.ArrayList;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.linuxtools.internal.tmf.ui.Activator;
+import org.eclipse.linuxtools.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.linuxtools.internal.tmf.ui.Messages;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.dialogs.TimeGraphLegend;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.ITimeDataProvider;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphColorScheme;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphScale;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphTooltipHandler;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseWheelListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Slider;
+
+/**
+ * Generic time graph viewer implementation
+ *
+ * @version 1.0
+ * @author Patrick Tasse, and others
+ */
+public class TimeGraphViewer implements ITimeDataProvider, SelectionListener {
+
+ /** vars */
+ private long _minTimeInterval;
+ private long _selectedTime;
+ private ITimeGraphEntry _selectedEntry;
+ private long _beginTime;
+ private long _endTime;
+ private long _time0;
+ private long _time1;
+ private long _time0_;
+ private long _time1_;
+ private long _time0_extSynch = 0;
+ private long _time1_extSynch = 0;
+ private boolean _timeRangeFixed;
+ private int _nameWidthPref = 200;
+ private int _minNameWidth = 6;
+ private int _nameWidth;
+ private Composite _dataViewer;
+
+ private TimeGraphControl _stateCtrl;
+ private TimeGraphScale _timeScaleCtrl;
+ private Slider _verticalScrollBar;
+ private TimeGraphTooltipHandler _threadTip;
+ private TimeGraphColorScheme _colors;
+ private ITimeGraphPresentationProvider fTimeGraphProvider;
+
+ ArrayList<ITimeGraphSelectionListener> fSelectionListeners = new ArrayList<ITimeGraphSelectionListener>();
+ ArrayList<ITimeGraphTimeListener> fTimeListeners = new ArrayList<ITimeGraphTimeListener>();
+ ArrayList<ITimeGraphRangeListener> fRangeListeners = new ArrayList<ITimeGraphRangeListener>();
+
+ // Calender Time format, using Epoch reference or Relative time
+ // format(default
+ private boolean calendarTimeFormat = false;
+ private int borderWidth = 0;
+ private int timeScaleHeight = 22;
+
+ private Action resetScale;
+ private Action showLegendAction;
+ private Action nextEventAction;
+ private Action prevEventAction;
+ private Action nextItemAction;
+ private Action previousItemAction;
+ private Action zoomInAction;
+ private Action zoomOutAction;
+
+ /**
+ * Standard constructor
+ *
+ * @param parent
+ * The parent UI composite object
+ * @param style
+ * The style to use
+ */
+ public TimeGraphViewer(Composite parent, int style) {
+ createDataViewer(parent, style);
+ }
+
+ /**
+ * Sets the timegraph provider used by this timegraph viewer.
+ *
+ * @param timeGraphProvider the timegraph provider
+ */
+ public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
+ fTimeGraphProvider = timeGraphProvider;
+ _stateCtrl.setTimeGraphProvider(timeGraphProvider);
+ _threadTip = new TimeGraphTooltipHandler(_dataViewer.getShell(), fTimeGraphProvider, this);
+ _threadTip.activateHoverHelp(_stateCtrl);
+ }
+
+ /**
+ * Sets or clears the input for this time graph viewer.
+ * The input array should only contain top-level elements.
+ *
+ * @param input the input of this time graph viewer, or <code>null</code> if none
+ */
+ public void setInput(ITimeGraphEntry[] input) {
+ if (null != _stateCtrl) {
+ if (null == input) {
+ input = new ITimeGraphEntry[0];
+ }
+ setTimeRange(input);
+ _verticalScrollBar.setEnabled(true);
+ setTopIndex(0);
+ _selectedTime = 0;
+ _selectedEntry = null;
+ refreshAllData(input);
+ }
+ }
+
+ /**
+ * Refresh the view
+ */
+ public void refresh() {
+ setInput(_stateCtrl.getTraces());
+ }
+
+ /**
+ * Callback for when the control is moved
+ *
+ * @param e
+ * The caller event
+ */
+ public void controlMoved(ControlEvent e) {
+ }
+
+ /**
+ * Callback for when the control is resized
+ *
+ * @param e
+ * The caller event
+ */
+ public void controlResized(ControlEvent e) {
+ resizeControls();
+ }
+
+ /**
+ * Handler for when the model is updated. Called from the display order in
+ * the API
+ *
+ * @param traces
+ * The traces in the model
+ * @param start
+ * The start time
+ * @param end
+ * The end time
+ * @param updateTimeBounds
+ * Should we updated the time bounds too
+ */
+ public void modelUpdate(ITimeGraphEntry[] traces, long start,
+ long end, boolean updateTimeBounds) {
+ if (null != _stateCtrl) {
+ //loadOptions();
+ updateInternalData(traces, start, end);
+ if (updateTimeBounds) {
+ _timeRangeFixed = true;
+ // set window to match limits
+ setStartFinishTime(_time0_, _time1_);
+ } else {
+ _stateCtrl.redraw();
+ _timeScaleCtrl.redraw();
+ }
+ }
+ }
+
+ protected String getViewTypeStr() {
+ return "viewoption.threads"; //$NON-NLS-1$
+ }
+
+ int getMarginWidth(int idx) {
+ return 0;
+ }
+
+ int getMarginHeight(int idx) {
+ return 0;
+ }
+
+ void loadOptions() {
+ _minTimeInterval = 1;
+ _selectedTime = -1;
+ _nameWidth = Utils.loadIntOption(getPreferenceString("namewidth"), //$NON-NLS-1$
+ _nameWidthPref, _minNameWidth, 1000);
+ }
+
+ void saveOptions() {
+ Utils.saveIntOption(getPreferenceString("namewidth"), _nameWidth); //$NON-NLS-1$
+ }
+
+ protected Control createDataViewer(Composite parent, int style) {
+ loadOptions();
+ _colors = new TimeGraphColorScheme();
+ _dataViewer = new Composite(parent, style) {
+ @Override
+ public void redraw() {
+ _timeScaleCtrl.redraw();
+ _stateCtrl.redraw();
+ super.redraw();
+ }
+ };
+ GridLayout gl = new GridLayout(2, false);
+ gl.marginHeight = borderWidth;
+ gl.marginWidth = 0;
+ gl.verticalSpacing = 0;
+ gl.horizontalSpacing = 0;
+ _dataViewer.setLayout(gl);
+
+ _timeScaleCtrl = new TimeGraphScale(_dataViewer, _colors);
+ _timeScaleCtrl.setTimeProvider(this);
+ _timeScaleCtrl.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false));
+ _timeScaleCtrl.setHeight(timeScaleHeight);
+
+ _verticalScrollBar = new Slider(_dataViewer, SWT.VERTICAL | SWT.NO_FOCUS);
+ _verticalScrollBar.setLayoutData(new GridData(SWT.DEFAULT, SWT.FILL, false, true, 1, 2));
+ _verticalScrollBar.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ setTopIndex(_verticalScrollBar.getSelection());
+ }
+ });
+ _verticalScrollBar.setEnabled(false);
+
+ _stateCtrl = createTimeGraphControl();
+
+ _stateCtrl.setTimeProvider(this);
+ _stateCtrl.addSelectionListener(this);
+ _stateCtrl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2));
+ _stateCtrl.addMouseWheelListener(new MouseWheelListener() {
+ @Override
+ public void mouseScrolled(MouseEvent e) {
+ adjustVerticalScrollBar();
+ }
+ });
+ _stateCtrl.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ adjustVerticalScrollBar();
+ }
+ });
+
+ Composite filler = new Composite(_dataViewer, SWT.NONE);
+ GridData gd = new GridData(SWT.DEFAULT, SWT.DEFAULT, false, false);
+ gd.heightHint = _stateCtrl.getHorizontalBar().getSize().y;
+ filler.setLayoutData(gd);
+ filler.setLayout(new FillLayout());
+
+ _stateCtrl.addControlListener(new ControlAdapter() {
+ @Override
+ public void controlResized(ControlEvent event) {
+ resizeControls();
+ }
+ });
+ resizeControls();
+ _dataViewer.update();
+ adjustVerticalScrollBar();
+ return _dataViewer;
+ }
+
+ /**
+ * Dispose the view.
+ */
+ public void dispose() {
+ saveOptions();
+ _stateCtrl.dispose();
+ _dataViewer.dispose();
+ _colors.dispose();
+ }
+
+ protected TimeGraphControl createTimeGraphControl() {
+ return new TimeGraphControl(_dataViewer, _colors);
+ }
+
+ /**
+ * Resize the controls
+ */
+ public void resizeControls() {
+ Rectangle r = _dataViewer.getClientArea();
+ if (r.isEmpty()) {
+ return;
+ }
+
+ int width = r.width;
+ if (_nameWidth > width - _minNameWidth) {
+ _nameWidth = width - _minNameWidth;
+ }
+ if (_nameWidth < _minNameWidth) {
+ _nameWidth = _minNameWidth;
+ }
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Try to set most convenient time range for display.
+ *
+ * @param traces
+ * The traces in the model
+ */
+ public void setTimeRange(ITimeGraphEntry traces[]) {
+ _endTime = 0;
+ _beginTime = -1;
+ for (int i = 0; i < traces.length; i++) {
+ ITimeGraphEntry entry = traces[i];
+ if (entry.getEndTime() >= entry.getStartTime() && entry.getEndTime() > 0) {
+ if (_beginTime < 0 || entry.getStartTime() < _beginTime) {
+ _beginTime = entry.getStartTime();
+ }
+ if (entry.getEndTime() > _endTime) {
+ _endTime = entry.getEndTime();
+ }
+ }
+ }
+
+ if (_beginTime < 0) {
+ _beginTime = 0;
+ }
+ }
+
+ /**
+ * Recalculate the time bounds
+ */
+ public void setTimeBounds() {
+ //_time0_ = _beginTime - (long) ((_endTime - _beginTime) * 0.02);
+ _time0_ = _beginTime;
+ if (_time0_ < 0) {
+ _time0_ = 0;
+ }
+ // _time1_ = _time0_ + (_endTime - _time0_) * 1.05;
+ _time1_ = _endTime;
+ // _time0_ = Math.floor(_time0_);
+ // _time1_ = Math.ceil(_time1_);
+ if (!_timeRangeFixed) {
+ _time0 = _time0_;
+ _time1 = _time1_;
+ }
+ if (_time1 - _time0 < _minTimeInterval) {
+ _time1 = Math.min(_time1_, _time0 + _minTimeInterval);
+ }
+ }
+
+ /**
+ * @param traces
+ * @param start
+ * @param end
+ */
+ void updateInternalData(ITimeGraphEntry[] traces, long start, long end) {
+ if (null == traces) {
+ traces = new ITimeGraphEntry[0];
+ }
+ if ((start == 0 && end == 0) || start < 0 || end < 0) {
+ // Start and end time are unspecified and need to be determined from
+ // individual processes
+ setTimeRange(traces);
+ } else {
+ _beginTime = start;
+ _endTime = end;
+ }
+
+ refreshAllData(traces);
+ }
+
+ /**
+ * @param traces
+ */
+ private void refreshAllData(ITimeGraphEntry[] traces) {
+ setTimeBounds();
+ if (_selectedTime < _beginTime) {
+ _selectedTime = _beginTime;
+ } else if (_selectedTime > _endTime) {
+ _selectedTime = _endTime;
+ }
+ _stateCtrl.refreshData(traces);
+ _timeScaleCtrl.redraw();
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Callback for when this view is focused
+ */
+ public void setFocus() {
+ if (null != _stateCtrl) {
+ _stateCtrl.setFocus();
+ }
+ }
+
+ /**
+ * Get the current focus status of this view.
+ *
+ * @return If the view is currently focused, or not
+ */
+ public boolean isInFocus() {
+ return _stateCtrl.isInFocus();
+ }
+
+ /**
+ * Get the view's current selection
+ *
+ * @return The entry that is selected
+ */
+ public ITimeGraphEntry getSelection() {
+ return _stateCtrl.getSelectedTrace();
+ }
+
+ /**
+ * Get the index of the current selection
+ *
+ * @return The index
+ */
+ public int getSelectionIndex() {
+ return _stateCtrl.getSelectedIndex();
+ }
+
+ @Override
+ public long getTime0() {
+ return _time0;
+ }
+
+ @Override
+ public long getTime1() {
+ return _time1;
+ }
+
+ @Override
+ public long getMinTimeInterval() {
+ return _minTimeInterval;
+ }
+
+ @Override
+ public int getNameSpace() {
+ return _nameWidth;
+ }
+
+ @Override
+ public void setNameSpace(int width) {
+ _nameWidth = width;
+ width = _stateCtrl.getClientArea().width;
+ if (_nameWidth > width - 6) {
+ _nameWidth = width - 6;
+ }
+ if (_nameWidth < 6) {
+ _nameWidth = 6;
+ }
+ _stateCtrl.adjustScrolls();
+ _stateCtrl.redraw();
+ _timeScaleCtrl.redraw();
+ }
+
+ @Override
+ public int getTimeSpace() {
+ int w = _stateCtrl.getClientArea().width;
+ return w - _nameWidth;
+ }
+
+ @Override
+ public long getSelectedTime() {
+ return _selectedTime;
+ }
+
+ @Override
+ public long getBeginTime() {
+ return _beginTime;
+ }
+
+ @Override
+ public long getEndTime() {
+ return _endTime;
+ }
+
+ @Override
+ public long getMaxTime() {
+ return _time1_;
+ }
+
+ @Override
+ public long getMinTime() {
+ return _time0_;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets.ITimeDataProvider
+ * #setStartFinishTimeNotify(long, long)
+ */
+ @Override
+ public void setStartFinishTimeNotify(long time0, long time1) {
+ setStartFinishTime(time0, time1);
+ notifyRangeListeners(time0, time1);
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets.ITimeDataProvider#notifyStartFinishTime()
+ */
+ @Override
+ public void notifyStartFinishTime() {
+ notifyRangeListeners(_time0, _time1);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets.ITimeDataProvider
+ * #setStartFinishTime(long, long)
+ */
+ @Override
+ public void setStartFinishTime(long time0, long time1) {
+ _time0 = time0;
+ if (_time0 < _time0_) {
+ _time0 = _time0_;
+ }
+ if (_time0 > _time1_) {
+ _time0 = _time1_;
+ }
+ _time1 = time1;
+ if (_time1 < _time0_) {
+ _time1 = _time0_;
+ }
+ if (_time1 > _time1_) {
+ _time1 = _time1_;
+ }
+ if (_time1 - _time0 < _minTimeInterval) {
+ _time1 = Math.min(_time1_, _time0 + _minTimeInterval);
+ }
+ _timeRangeFixed = true;
+ _stateCtrl.adjustScrolls();
+ _stateCtrl.redraw();
+ _timeScaleCtrl.redraw();
+ }
+
+ /**
+ * Set the time bounds to the provided values
+ *
+ * @param beginTime
+ * The start time of the window
+ * @param endTime
+ * The end time
+ */
+ public void setTimeBounds(long beginTime, long endTime) {
+ _beginTime = beginTime;
+ _endTime = endTime;
+ _time0_ = beginTime;
+ _time1_ = endTime;
+ _stateCtrl.adjustScrolls();
+ }
+
+ @Override
+ public void resetStartFinishTime() {
+ setStartFinishTimeNotify(_time0_, _time1_);
+ _timeRangeFixed = false;
+ }
+
+ @Override
+ public void setSelectedTimeNotify(long time, boolean ensureVisible) {
+ setSelectedTimeInt(time, ensureVisible, true);
+ }
+
+ @Override
+ public void setSelectedTime(long time, boolean ensureVisible) {
+ setSelectedTimeInt(time, ensureVisible, false);
+ }
+
+ private void setSelectedTimeInt(long time, boolean ensureVisible, boolean doNotify) {
+ long time0 = _time0;
+ long time1 = _time1;
+ if (ensureVisible) {
+ long timeSpace = (long) ((_time1 - _time0) * .02);
+ long timeMid = (long) ((_time1 - _time0) * .5);
+ if (time < _time0 + timeSpace) {
+ long dt = _time0 - time + timeMid;
+ _time0 -= dt;
+ _time1 -= dt;
+ } else if (time > _time1 - timeSpace) {
+ long dt = time - _time1 + timeMid;
+ _time0 += dt;
+ _time1 += dt;
+ }
+ if (_time0 < _time0_) {
+ _time1 = Math.min(_time1_, _time1 + (_time0_ - _time0));
+ _time0 = _time0_;
+ } else if (_time1 > _time1_) {
+ _time0 = Math.max(_time0_, _time0 - (_time1 - _time1_));
+ _time1 = _time1_;
+ }
+ }
+ if (_time1 - _time0 < _minTimeInterval) {
+ _time1 = Math.min(_time1_, _time0 + _minTimeInterval);
+ }
+ _stateCtrl.adjustScrolls();
+ _stateCtrl.redraw();
+ _timeScaleCtrl.redraw();
+
+
+ boolean notifySelectedTime = (time != _selectedTime);
+ _selectedTime = time;
+
+ if (doNotify && ((time0 != _time0) || (time1 != _time1))) {
+ notifyRangeListeners(_time0, _time1);
+ }
+
+ if (doNotify && notifySelectedTime) {
+ notifyTimeListeners(_selectedTime);
+ }
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ if (_selectedEntry != getSelection()) {
+ _selectedEntry = getSelection();
+ notifySelectionListeners(_selectedEntry);
+ }
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (_selectedEntry != getSelection()) {
+ _selectedEntry = getSelection();
+ notifySelectionListeners(_selectedEntry);
+ }
+ }
+
+ /**
+ * Callback for when the next event is selected
+ */
+ public void selectNextEvent() {
+ _stateCtrl.selectNextEvent();
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Callback for when the previous event is selected
+ */
+ public void selectPrevEvent() {
+ _stateCtrl.selectPrevEvent();
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Callback for when the next item is selected
+ */
+ public void selectNextItem() {
+ _stateCtrl.selectNextTrace();
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Callback for when the previous item is selected
+ */
+ public void selectPrevItem() {
+ _stateCtrl.selectPrevTrace();
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Callback for the show legend action
+ */
+ public void showLegend() {
+ if (_dataViewer == null || _dataViewer.isDisposed()) {
+ return;
+ }
+
+ TimeGraphLegend.open(_dataViewer.getShell(), fTimeGraphProvider);
+ }
+
+ /**
+ * Callback for the Zoom In action
+ */
+ public void zoomIn() {
+ _stateCtrl.zoomIn();
+ }
+
+ /**
+ * Callback for the Zoom Out action
+ */
+ public void zoomOut() {
+ _stateCtrl.zoomOut();
+ }
+
+ private String getPreferenceString(String string) {
+ return getViewTypeStr() + "." + string; //$NON-NLS-1$
+ }
+
+ /**
+ * Add a selection listener
+ *
+ * @param listener
+ * The listener to add
+ */
+ public void addSelectionListener(ITimeGraphSelectionListener listener) {
+ fSelectionListeners.add(listener);
+ }
+
+ /**
+ * Remove a selection listener
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeSelectionListener(ITimeGraphSelectionListener listener) {
+ fSelectionListeners.remove(listener);
+ }
+
+ private void notifySelectionListeners(ITimeGraphEntry selection) {
+ TimeGraphSelectionEvent event = new TimeGraphSelectionEvent(this, selection);
+
+ for (ITimeGraphSelectionListener listener : fSelectionListeners) {
+ listener.selectionChanged(event);
+ }
+ }
+
+ /**
+ * Add a time listener
+ *
+ * @param listener
+ * The listener to add
+ */
+ public void addTimeListener(ITimeGraphTimeListener listener) {
+ fTimeListeners.add(listener);
+ }
+
+ /**
+ * Remove a time listener
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeTimeListener(ITimeGraphTimeListener listener) {
+ fTimeListeners.remove(listener);
+ }
+
+ private void notifyTimeListeners(long time) {
+ TimeGraphTimeEvent event = new TimeGraphTimeEvent(this, time);
+
+ for (ITimeGraphTimeListener listener : fTimeListeners) {
+ listener.timeSelected(event);
+ }
+ }
+
+ /**
+ * Add a range listener
+ *
+ * @param listener
+ * The listener to add
+ */
+ public void addRangeListener(ITimeGraphRangeListener listener) {
+ fRangeListeners.add(listener);
+ }
+
+ /**
+ * Remove a range listener
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeRangeListener(ITimeGraphRangeListener listener) {
+ fRangeListeners.remove(listener);
+ }
+
+ private void notifyRangeListeners(long startTime, long endTime) {
+ // Check if the time has actually changed from last notification
+ if (startTime != _time0_extSynch || endTime != _time1_extSynch) {
+ // Notify Time Scale Selection Listeners
+ TimeGraphRangeUpdateEvent event = new TimeGraphRangeUpdateEvent(this, startTime, endTime);
+
+ for (ITimeGraphRangeListener listener : fRangeListeners) {
+ listener.timeRangeUpdated(event);
+ }
+
+ // update external synch timers
+ updateExtSynchTimers();
+ }
+ }
+
+ /**
+ * Callback to set a selected event in the view
+ *
+ * @param event
+ * The event that was selected
+ * @param source
+ * The source of this selection event
+ */
+ public void setSelectedEvent(ITimeEvent event, Object source) {
+ if (event == null || source == this) {
+ return;
+ }
+ _selectedEntry = event.getEntry();
+ _stateCtrl.selectItem(_selectedEntry, false);
+
+ setSelectedTimeInt(event.getTime(), true, true);
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Set the seeked time of a trace
+ *
+ * @param trace
+ * The trace that was seeked
+ * @param time
+ * The target time
+ * @param source
+ * The source of this seek event
+ */
+ public void setSelectedTraceTime(ITimeGraphEntry trace, long time, Object source) {
+ if (trace == null || source == this) {
+ return;
+ }
+ _selectedEntry = trace;
+ _stateCtrl.selectItem(trace, false);
+
+ setSelectedTimeInt(time, true, true);
+ }
+
+ /**
+ * Callback for a trace selection
+ *
+ * @param trace
+ * The trace that was selected
+ */
+ public void setSelection(ITimeGraphEntry trace) {
+ _selectedEntry = trace;
+ _stateCtrl.selectItem(trace, false);
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Callback for a time window selection
+ *
+ * @param time0
+ * Start time of the range
+ * @param time1
+ * End time of the range
+ * @param source
+ * Source of the event
+ */
+ public void setSelectVisTimeWindow(long time0, long time1, Object source) {
+ if (source == this) {
+ return;
+ }
+
+ setStartFinishTime(time0, time1);
+
+ // update notification time values since we are now in synch with the
+ // external application
+ updateExtSynchTimers();
+ }
+
+ /**
+ * update the cache timers used to identify the need to send a time window
+ * update to external registered listeners
+ */
+ private void updateExtSynchTimers() {
+ // last time notification cache
+ _time0_extSynch = _time0;
+ _time1_extSynch = _time1;
+ }
+
+ /**
+ * Set the calendar format
+ *
+ * @param toAbsoluteCaltime
+ * True for absolute time, false for relative
+ */
+ public void setTimeCalendarFormat(boolean toAbsoluteCaltime) {
+ calendarTimeFormat = toAbsoluteCaltime;
+ }
+
+ @Override
+ public boolean isCalendarFormat() {
+ return calendarTimeFormat;
+ }
+
+ /**
+ * Retrieve the border width
+ *
+ * @return The width
+ */
+ public int getBorderWidth() {
+ return borderWidth;
+ }
+
+ /**
+ * Set the border width
+ *
+ * @param borderWidth
+ * The width
+ */
+ public void setBorderWidth(int borderWidth) {
+ if (borderWidth > -1) {
+ this.borderWidth = borderWidth;
+ GridLayout gl = (GridLayout)_dataViewer.getLayout();
+ gl.marginHeight = borderWidth;
+ }
+ }
+
+ /**
+ * Retrieve the height of the header
+ *
+ * @return The height
+ */
+ public int getHeaderHeight() {
+ return timeScaleHeight;
+ }
+
+ /**
+ * Set the height of the header
+ *
+ * @param headerHeight
+ * The height to set
+ */
+ public void setHeaderHeight(int headerHeight) {
+ if (headerHeight > -1) {
+ this.timeScaleHeight = headerHeight;
+ _timeScaleCtrl.setHeight(headerHeight);
+ }
+ }
+
+ /**
+ * Retrieve the height of an item row
+ *
+ * @return The height
+ */
+ public int getItemHeight() {
+ if (_stateCtrl != null) {
+ return _stateCtrl.getItemHeight();
+ }
+ return 0;
+ }
+
+ /**
+ * Set the height of an item row
+ *
+ * @param rowHeight
+ * The height to set
+ */
+ public void setItemHeight(int rowHeight) {
+ if (_stateCtrl != null) {
+ _stateCtrl.setItemHeight(rowHeight);
+ }
+ }
+
+ /**
+ * Set the minimum item width
+ *
+ * @param width
+ * The min width
+ */
+ public void setMinimumItemWidth(int width) {
+ if (_stateCtrl != null) {
+ _stateCtrl.setMinimumItemWidth(width);
+ }
+ }
+
+ /**
+ * Set the width for the name column
+ *
+ * @param width The width
+ */
+ public void setNameWidthPref(int width) {
+ _nameWidthPref = width;
+ if (width == 0) {
+ _minNameWidth = 0;
+ _nameWidth = 0;
+ }
+ }
+
+ /**
+ * Retrieve the configure width for the name column
+ *
+ * @param width
+ * Unused?
+ * @return The width
+ */
+ public int getNameWidthPref(int width) {
+ return _nameWidthPref;
+ }
+
+ /**
+ * Returns the primary control associated with this viewer.
+ *
+ * @return the SWT control which displays this viewer's content
+ */
+ public Control getControl() {
+ return _dataViewer;
+ }
+
+ /**
+ * Returns the time graph control associated with this viewer.
+ *
+ * @return the time graph control
+ */
+ TimeGraphControl getTimeGraphControl() {
+ return _stateCtrl;
+ }
+
+ /**
+ * Returns the time graph scale associated with this viewer.
+ *
+ * @return the time graph scale
+ */
+ TimeGraphScale getTimeGraphScale() {
+ return _timeScaleCtrl;
+ }
+
+ /**
+ * Get the selection provider
+ *
+ * @return the selection provider
+ */
+ public ISelectionProvider getSelectionProvider() {
+ return _stateCtrl;
+ }
+
+ /**
+ * Wait for the cursor
+ *
+ * @param waitInd
+ * Wait indefinitely?
+ */
+ public void waitCursor(boolean waitInd) {
+ _stateCtrl.waitCursor(waitInd);
+ }
+
+ /**
+ * Get the horizontal scroll bar object
+ *
+ * @return The scroll bar
+ */
+ public ScrollBar getHorizontalBar() {
+ return _stateCtrl.getHorizontalBar();
+ }
+
+ /**
+ * Get the vertical scroll bar object
+ *
+ * @return The scroll bar
+ */
+ public Slider getVerticalBar() {
+ return _verticalScrollBar;
+ }
+
+ /**
+ * Set the given index as the top one
+ *
+ * @param index
+ * The index that will go to the top
+ */
+ public void setTopIndex(int index) {
+ _stateCtrl.setTopIndex(index);
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Retrieve the current top index
+ *
+ * @return The top index
+ */
+ public int getTopIndex() {
+ return _stateCtrl.getTopIndex();
+ }
+
+ /**
+ * Set the expanded state of an entry
+ *
+ * @param entry
+ * The entry to expand/collapse
+ * @param expanded
+ * True for expanded, false for collapsed
+ */
+ public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
+ _stateCtrl.setExpandedState(entry, expanded);
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Collapses all nodes of the viewer's tree, starting with the root.
+ *
+ * @since 2.0
+ */
+ public void collapseAll() {
+ _stateCtrl.collapseAll();
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Expands all nodes of the viewer's tree, starting with the root.
+ *
+ * @since 2.0
+ */
+ public void expandAll() {
+ _stateCtrl.expandAll();
+ adjustVerticalScrollBar();
+ }
+
+ /**
+ * Get the number of sub-elements when expanded
+ *
+ * @return The element count
+ */
+ public int getExpandedElementCount() {
+ return _stateCtrl.getExpandedElementCount();
+ }
+
+ /**
+ * Get the sub-elements
+ *
+ * @return The array of entries that are below this one
+ */
+ public ITimeGraphEntry[] getExpandedElements() {
+ return _stateCtrl.getExpandedElements();
+ }
+
+ /**
+ * Add a tree listener
+ *
+ * @param listener
+ * The listener to add
+ */
+ public void addTreeListener(ITimeGraphTreeListener listener) {
+ _stateCtrl.addTreeListener(listener);
+ }
+
+ /**
+ * Remove a tree listener
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeTreeListener(ITimeGraphTreeListener listener) {
+ _stateCtrl.removeTreeListener(listener);
+ }
+
+ /**
+ * Get the reset scale action.
+ *
+ * @return The Action object
+ */
+ public Action getResetScaleAction() {
+ if (resetScale == null) {
+ // resetScale
+ resetScale = new Action() {
+ @Override
+ public void run() {
+ resetStartFinishTime();
+ }
+ };
+ resetScale.setText(Messages.TmfTimeGraphViewer_ResetScaleActionNameText);
+ resetScale.setToolTipText(Messages.TmfTimeGraphViewer_ResetScaleActionToolTipText);
+ resetScale.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_HOME_MENU));
+ }
+ return resetScale;
+ }
+
+ /**
+ * Get the show legend action.
+ *
+ * @return The Action object
+ */
+ public Action getShowLegendAction() {
+ if (showLegendAction == null) {
+ // showLegend
+ showLegendAction = new Action() {
+ @Override
+ public void run() {
+ showLegend();
+ }
+ };
+ showLegendAction.setText(Messages.TmfTimeGraphViewer_LegendActionNameText);
+ showLegendAction.setToolTipText(Messages.TmfTimeGraphViewer_LegendActionToolTipText);
+ showLegendAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SHOW_LEGEND));
+ }
+
+ return showLegendAction;
+ }
+
+ /**
+ * Get the the next event action.
+ *
+ * @return The action object
+ */
+ public Action getNextEventAction() {
+ if (nextEventAction == null) {
+ nextEventAction = new Action() {
+ @Override
+ public void run() {
+ selectNextEvent();
+ }
+ };
+
+ nextEventAction.setText(Messages.TmfTimeGraphViewer_NextEventActionNameText);
+ nextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextEventActionToolTipText);
+ nextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_EVENT));
+ }
+
+ return nextEventAction;
+ }
+
+ /**
+ * Get the previous event action.
+ *
+ * @return The Action object
+ */
+ public Action getPreviousEventAction() {
+ if (prevEventAction == null) {
+ prevEventAction = new Action() {
+ @Override
+ public void run() {
+ selectPrevEvent();
+ }
+ };
+
+ prevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousEventActionNameText);
+ prevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousEventActionToolTipText);
+ prevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_EVENT));
+ }
+
+ return prevEventAction;
+ }
+
+ /**
+ * Get the next item action.
+ *
+ * @return The Action object
+ */
+ public Action getNextItemAction() {
+ if (nextItemAction == null) {
+
+ nextItemAction = new Action() {
+ @Override
+ public void run() {
+ selectNextItem();
+ }
+ };
+ nextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText);
+ nextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText);
+ nextItemAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_ITEM));
+ }
+ return nextItemAction;
+ }
+
+ /**
+ * Get the previous item action.
+ *
+ * @return The Action object
+ */
+ public Action getPreviousItemAction() {
+ if (previousItemAction == null) {
+
+ previousItemAction = new Action() {
+ @Override
+ public void run() {
+ selectPrevItem();
+ }
+ };
+ previousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);
+ previousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText);
+ previousItemAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_ITEM));
+ }
+ return previousItemAction;
+ }
+
+ /**
+ * Get the zoom in action
+ *
+ * @return The Action object
+ */
+ public Action getZoomInAction() {
+ if (zoomInAction == null) {
+ zoomInAction = new Action() {
+ @Override
+ public void run() {
+ zoomIn();
+ }
+ };
+ zoomInAction.setText(Messages.TmfTimeGraphViewer_ZoomInActionNameText);
+ zoomInAction.setToolTipText(Messages.TmfTimeGraphViewer_ZoomInActionToolTipText);
+ zoomInAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ZOOM_IN_MENU));
+ }
+ return zoomInAction;
+ }
+
+ /**
+ * Get the zoom out action
+ *
+ * @return The Action object
+ */
+ public Action getZoomOutAction() {
+ if (zoomOutAction == null) {
+ zoomOutAction = new Action() {
+ @Override
+ public void run() {
+ zoomOut();
+ }
+ };
+ zoomOutAction.setText(Messages.TmfTimeGraphViewer_ZoomOutActionNameText);
+ zoomOutAction.setToolTipText(Messages.TmfTimeGraphViewer_ZoomOutActionToolTipText);
+ zoomOutAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ZOOM_OUT_MENU));
+ }
+ return zoomOutAction;
+ }
+
+
+ private void adjustVerticalScrollBar() {
+ int topIndex = _stateCtrl.getTopIndex();
+ int countPerPage = _stateCtrl.countPerPage();
+ int expandedElementCount = _stateCtrl.getExpandedElementCount();
+ if (topIndex + countPerPage > expandedElementCount) {
+ _stateCtrl.setTopIndex(Math.max(0, expandedElementCount - countPerPage));
+ }
+
+ int selection = _stateCtrl.getTopIndex();
+ int min = 0;
+ int max = Math.max(1, expandedElementCount - 1);
+ int thumb = Math.min(max, Math.max(1, countPerPage - 1));
+ int increment = 1;
+ int pageIncrement = Math.max(1, countPerPage);
+ _verticalScrollBar.setValues(selection, min, max, thumb, increment, pageIncrement);
+ }
+
+
+
+}
-/*****************************************************************************\r
- * Copyright (c) 2007, 2008 Intel Corporation, 2009, 2010, 2011, 2012 Ericsson.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * Intel Corporation - Initial API and implementation\r
- * Ruslan A. Scherbakov, Intel - Initial API and implementation\r
- * Alvaro Sanchez-Leon - Updated for TMF\r
- * Patrick Tasse - Refactoring\r
- *\r
- *****************************************************************************/\r
-\r
-package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Vector;\r
-\r
-import org.eclipse.jface.resource.JFaceResources;\r
-import org.eclipse.jface.resource.LocalResourceManager;\r
-import org.eclipse.jface.viewers.ISelection;\r
-import org.eclipse.jface.viewers.ISelectionChangedListener;\r
-import org.eclipse.jface.viewers.ISelectionProvider;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTreeListener;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.StateItem;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTreeExpansionEvent;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.events.ControlEvent;\r
-import org.eclipse.swt.events.ControlListener;\r
-import org.eclipse.swt.events.FocusEvent;\r
-import org.eclipse.swt.events.FocusListener;\r
-import org.eclipse.swt.events.KeyEvent;\r
-import org.eclipse.swt.events.KeyListener;\r
-import org.eclipse.swt.events.MouseEvent;\r
-import org.eclipse.swt.events.MouseListener;\r
-import org.eclipse.swt.events.MouseMoveListener;\r
-import org.eclipse.swt.events.MouseTrackListener;\r
-import org.eclipse.swt.events.MouseWheelListener;\r
-import org.eclipse.swt.events.PaintEvent;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.events.SelectionListener;\r
-import org.eclipse.swt.events.TraverseEvent;\r
-import org.eclipse.swt.events.TraverseListener;\r
-import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.graphics.Cursor;\r
-import org.eclipse.swt.graphics.GC;\r
-import org.eclipse.swt.graphics.Image;\r
-import org.eclipse.swt.graphics.Point;\r
-import org.eclipse.swt.graphics.Rectangle;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.Event;\r
-import org.eclipse.swt.widgets.Listener;\r
-import org.eclipse.swt.widgets.ScrollBar;\r
-\r
-/**\r
- * Time graph control implementation\r
- *\r
- * @version 1.0\r
- * @author Alvaro Sanchez-Leon\r
- * @author Patrick Tasse\r
- */\r
-public class TimeGraphControl extends TimeGraphBaseControl implements FocusListener, KeyListener, MouseMoveListener, MouseListener, MouseWheelListener, ControlListener, SelectionListener, MouseTrackListener, TraverseListener, ISelectionProvider {\r
-\r
- private static final int DRAG_NONE = 0;\r
- private static final int DRAG_TRACE_ITEM = 1;\r
- private static final int DRAG_SPLIT_LINE = 2;\r
- public static final boolean DEFAULT_DRAW_THREAD_JOIN = true;\r
- public static final boolean DEFAULT_DRAW_THREAD_WAIT = true;\r
- public static final boolean DEFAULT_DRAW_THREAD_RELEASE = true;\r
- public static final int H_SCROLLBAR_MAX = Integer.MAX_VALUE - 1;\r
- private static final int CUSTOM_ITEM_HEIGHT = -1; // get item height from provider\r
-\r
- private static final double zoomCoeff = 1.5;\r
-\r
- private ITimeDataProvider _timeProvider;\r
- private boolean _isInFocus = false;\r
- private boolean _isDragCursor3 = false;\r
- private boolean _isWaitCursor = true;\r
- private boolean _mouseOverSplitLine = false;\r
- private int _itemHeight = CUSTOM_ITEM_HEIGHT;\r
- private int _minimumItemWidth = 0;\r
- private int _topIndex = 0;\r
- private int _dragState = DRAG_NONE;\r
- private int _dragX0 = 0;\r
- private int _dragX = 0;\r
- private int _idealNameSpace = 0;\r
- // private double _timeStep = 10000000;\r
- private long _time0bak;\r
- private long _time1bak;\r
- private ITimeGraphPresentationProvider fTimeGraphProvider = null;\r
- private ItemData _data = null;\r
- private List<SelectionListener> _selectionListeners;\r
- private final List<ISelectionChangedListener> _selectionChangedListeners = new ArrayList<ISelectionChangedListener>();\r
- private final List<ITimeGraphTreeListener> _treeListeners = new ArrayList<ITimeGraphTreeListener>();\r
- private final Cursor _dragCursor3;\r
- private final Cursor _WaitCursor;\r
-\r
- // Vertical formatting formatting for the state control view\r
- private final boolean _visibleVerticalScroll = true;\r
- private int _borderWidth = 0;\r
- private int _headerHeight = 0;\r
-\r
- private Listener mouseScrollFilterListener;\r
-\r
- protected LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());\r
- protected Color[] fEventColorMap = null;\r
-\r
- private MouseScrollNotifier fMouseScrollNotifier;\r
- private final Object fMouseScrollNotifierLock = new Object();\r
- private class MouseScrollNotifier extends Thread {\r
- private final static long DELAY = 400L;\r
- private final static long POLLING_INTERVAL = 10L;\r
- private long fLastScrollTime = Long.MAX_VALUE;\r
-\r
- @Override\r
- public void run() {\r
- while ((System.currentTimeMillis() - fLastScrollTime) < DELAY) {\r
- try {\r
- Thread.sleep(POLLING_INTERVAL);\r
- } catch (Exception e) {\r
- return;\r
- }\r
- }\r
- if (!isInterrupted()) {\r
- Display.getDefault().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- if (isDisposed()) {\r
- return;\r
- }\r
- _timeProvider.notifyStartFinishTime();\r
- }\r
- });\r
- }\r
- synchronized (fMouseScrollNotifierLock) {\r
- fMouseScrollNotifier = null;\r
- }\r
- }\r
-\r
- public void mouseScrolled() {\r
- fLastScrollTime = System.currentTimeMillis();\r
- }\r
- }\r
-\r
- /**\r
- * Standard constructor\r
- *\r
- * @param parent\r
- * The parent composite object\r
- * @param colors\r
- * The color scheme to use\r
- */\r
- public TimeGraphControl(Composite parent, TimeGraphColorScheme colors) {\r
-\r
- super(parent, colors, SWT.NO_BACKGROUND | SWT.H_SCROLL | SWT.DOUBLE_BUFFERED);\r
-\r
- _data = new ItemData();\r
-\r
- addFocusListener(this);\r
- addMouseListener(this);\r
- addMouseMoveListener(this);\r
- addMouseTrackListener(this);\r
- addMouseWheelListener(this);\r
- addTraverseListener(this);\r
- addKeyListener(this);\r
- addControlListener(this);\r
- ScrollBar scrollHor = getHorizontalBar();\r
-\r
- if (scrollHor != null) {\r
- scrollHor.addSelectionListener(this);\r
- }\r
-\r
- _dragCursor3 = new Cursor(super.getDisplay(), SWT.CURSOR_SIZEWE);\r
- _WaitCursor = new Cursor(super.getDisplay(), SWT.CURSOR_WAIT);\r
- }\r
-\r
- @Override\r
- public void dispose() {\r
- super.dispose();\r
- _dragCursor3.dispose();\r
- _WaitCursor.dispose();\r
- fResourceManager.dispose();\r
- }\r
-\r
- /**\r
- * Sets the timegraph provider used by this timegraph viewer.\r
- *\r
- * @param timeGraphProvider the timegraph provider\r
- */\r
- public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {\r
- fTimeGraphProvider = timeGraphProvider;\r
- _data.provider = timeGraphProvider;\r
-\r
- if (fEventColorMap != null) {\r
- for (Color color : fEventColorMap) {\r
- fResourceManager.destroyColor(color.getRGB());\r
- }\r
- }\r
- StateItem[] stateItems = fTimeGraphProvider.getStateTable();\r
- if (stateItems != null) {\r
- fEventColorMap = new Color[stateItems.length];\r
- for (int i = 0; i < stateItems.length; i++) {\r
- fEventColorMap[i] = fResourceManager.createColor(stateItems[i].getStateColor());\r
- }\r
- } else {\r
- fEventColorMap = new Color[] { };\r
- }\r
- }\r
-\r
- /**\r
- * Assign the given time provider\r
- *\r
- * @param timeProvider\r
- * The time provider\r
- */\r
- public void setTimeProvider(ITimeDataProvider timeProvider) {\r
- _timeProvider = timeProvider;\r
- adjustScrolls();\r
- redraw();\r
- }\r
-\r
- /**\r
- * Add a selection listener\r
- *\r
- * @param listener\r
- * The listener to add\r
- */\r
- public void addSelectionListener(SelectionListener listener) {\r
- if (listener == null) {\r
- SWT.error(SWT.ERROR_NULL_ARGUMENT);\r
- }\r
- if (null == _selectionListeners) {\r
- _selectionListeners = new ArrayList<SelectionListener>();\r
- }\r
- _selectionListeners.add(listener);\r
- }\r
-\r
- /**\r
- * Remove a selection listener\r
- *\r
- * @param listener\r
- * The listener to remove\r
- */\r
- public void removeSelectionListener(SelectionListener listener) {\r
- if (null != _selectionListeners) {\r
- _selectionListeners.remove(listener);\r
- }\r
- }\r
-\r
- /**\r
- * Selection changed callback\r
- */\r
- public void fireSelectionChanged() {\r
- if (null != _selectionListeners) {\r
- Iterator<SelectionListener> it = _selectionListeners.iterator();\r
- while (it.hasNext()) {\r
- SelectionListener listener = it.next();\r
- listener.widgetSelected(null);\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * Default selection callback\r
- */\r
- public void fireDefaultSelection() {\r
- if (null != _selectionListeners) {\r
- Iterator<SelectionListener> it = _selectionListeners.iterator();\r
- while (it.hasNext()) {\r
- SelectionListener listener = it.next();\r
- listener.widgetDefaultSelected(null);\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * Get the traces in the model\r
- *\r
- * @return The array of traces\r
- */\r
- public ITimeGraphEntry[] getTraces() {\r
- return _data.getTraces();\r
- }\r
-\r
- /**\r
- * Get the on/off trace filters\r
- *\r
- * @return The array of filters\r
- */\r
- public boolean[] getTraceFilter() {\r
- return _data.getTraceFilter();\r
- }\r
-\r
- /**\r
- * Refresh the data for the thing\r
- */\r
- public void refreshData() {\r
- _data.refreshData();\r
- adjustScrolls();\r
- redraw();\r
- }\r
-\r
- /**\r
- * Refresh data for the given traces\r
- *\r
- * @param traces\r
- * The traces to refresh\r
- */\r
- public void refreshData(ITimeGraphEntry[] traces) {\r
- _data.refreshData(traces);\r
- adjustScrolls();\r
- redraw();\r
- }\r
-\r
- /**\r
- * Adjust the scoll bars\r
- */\r
- public void adjustScrolls() {\r
- if (null == _timeProvider) {\r
- getHorizontalBar().setValues(0, 1, 1, 1, 1, 1);\r
- return;\r
- }\r
-\r
- // HORIZONTAL BAR\r
- // Visible window\r
- long time0 = _timeProvider.getTime0();\r
- long time1 = _timeProvider.getTime1();\r
- // Time boundaries\r
- long timeMin = _timeProvider.getMinTime();\r
- long timeMax = _timeProvider.getMaxTime();\r
-\r
- long delta = timeMax - timeMin;\r
-\r
- int timePos = 0;\r
- int thumb = H_SCROLLBAR_MAX;\r
-\r
- if (delta != 0) {\r
- // Thumb size (page size)\r
- thumb = Math.max(1, (int) (H_SCROLLBAR_MAX * ((double) (time1 - time0) / delta)));\r
- // At the beginning of visible window\r
- timePos = (int) (H_SCROLLBAR_MAX * ((double) (time0 - timeMin) / delta));\r
- }\r
-\r
- // position, minimum, maximum, thumb size, increment (half page)t, page\r
- // increment size (full page)\r
- getHorizontalBar().setValues(timePos, 0, H_SCROLLBAR_MAX, thumb, Math.max(1, thumb / 2), Math.max(2, thumb));\r
- }\r
-\r
- boolean ensureVisibleItem(int idx, boolean redraw) {\r
- boolean changed = false;\r
- if (idx < 0) {\r
- for (idx = 0; idx < _data._expandedItems.length; idx++) {\r
- if (_data._expandedItems[idx]._selected) {\r
- break;\r
- }\r
- }\r
- }\r
- if (idx >= _data._expandedItems.length) {\r
- return changed;\r
- }\r
- if (idx < _topIndex) {\r
- setTopIndex(idx);\r
- //FIXME:getVerticalBar().setSelection(_topItem);\r
- if (redraw) {\r
- redraw();\r
- }\r
- changed = true;\r
- } else {\r
- int page = countPerPage();\r
- if (idx >= _topIndex + page) {\r
- setTopIndex(idx - page + 1);\r
- //FIXME:getVerticalBar().setSelection(_topItem);\r
- if (redraw) {\r
- redraw();\r
- }\r
- changed = true;\r
- }\r
- }\r
- return changed;\r
- }\r
-\r
- /**\r
- * Assign the given index as the top one\r
- *\r
- * @param idx\r
- * The index\r
- */\r
- public void setTopIndex(int idx) {\r
- idx = Math.min(idx, _data._expandedItems.length - countPerPage());\r
- idx = Math.max(0, idx);\r
- _topIndex = idx;\r
- redraw();\r
- }\r
-\r
- /**\r
- * Set the expanded state of a given entry\r
- *\r
- * @param entry\r
- * The entry\r
- * @param expanded\r
- * True if expanded, false if collapsed\r
- */\r
- public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {\r
- Item item = _data.findItem(entry);\r
- if (item != null && item._expanded != expanded) {\r
- item._expanded = expanded;\r
- _data.updateExpandedItems();\r
- redraw();\r
- }\r
- }\r
-\r
- /**\r
- * Add a tree listener\r
- *\r
- * @param listener\r
- * The listener to add\r
- */\r
- public void addTreeListener(ITimeGraphTreeListener listener) {\r
- if (!_treeListeners.contains(listener)) {\r
- _treeListeners.add(listener);\r
- }\r
- }\r
-\r
- /**\r
- * Remove a tree listener\r
- *\r
- * @param listener\r
- * The listener to remove\r
- */\r
- public void removeTreeListener(ITimeGraphTreeListener listener) {\r
- if (_treeListeners.contains(listener)) {\r
- _treeListeners.remove(listener);\r
- }\r
- }\r
-\r
- /**\r
- * Tree event callback\r
- *\r
- * @param entry\r
- * The affected entry\r
- * @param expanded\r
- * The expanded state (true for expanded, false for collapsed)\r
- */\r
- public void fireTreeEvent(ITimeGraphEntry entry, boolean expanded) {\r
- TimeGraphTreeExpansionEvent event = new TimeGraphTreeExpansionEvent(this, entry);\r
- for (ITimeGraphTreeListener listener : _treeListeners) {\r
- if (expanded) {\r
- listener.treeExpanded(event);\r
- } else {\r
- listener.treeCollapsed(event);\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public ISelection getSelection() {\r
- TimeGraphSelection sel = new TimeGraphSelection();\r
- ITimeGraphEntry trace = getSelectedTrace();\r
- if (null != trace && null != _timeProvider) {\r
- long selectedTime = _timeProvider.getSelectedTime();\r
- ITimeEvent event = Utils.findEvent(trace, selectedTime, 0);\r
- if (event != null) {\r
- sel.add(event);\r
- } else {\r
- sel.add(trace);\r
- }\r
- }\r
- return sel;\r
- }\r
-\r
- /**\r
- * Get the selection object\r
- *\r
- * @return The selection\r
- */\r
- public ISelection getSelectionTrace() {\r
- TimeGraphSelection sel = new TimeGraphSelection();\r
- ITimeGraphEntry trace = getSelectedTrace();\r
- if (null != trace) {\r
- sel.add(trace);\r
- }\r
- return sel;\r
- }\r
-\r
- /**\r
- * Enable/disable one of the traces in the model\r
- *\r
- * @param n\r
- * 1 to enable it, -1 to disable. The method returns immediately\r
- * if another value is used.\r
- */\r
- public void selectTrace(int n) {\r
- if ((n != 1) && (n != -1)) {\r
- return;\r
- }\r
-\r
- boolean changed = false;\r
- int lastSelection = -1;\r
- for (int i = 0; i < _data._expandedItems.length; i++) {\r
- Item item = _data._expandedItems[i];\r
- if (item._selected) {\r
- lastSelection = i;\r
- if ((1 == n) && (i < _data._expandedItems.length - 1)) {\r
- item._selected = false;\r
- item = _data._expandedItems[i + 1];\r
- item._selected = true;\r
- changed = true;\r
- } else if ((-1 == n) && (i > 0)) {\r
- item._selected = false;\r
- item = _data._expandedItems[i - 1];\r
- item._selected = true;\r
- changed = true;\r
- }\r
- break;\r
- }\r
- }\r
-\r
- if (lastSelection < 0 && _data._expandedItems.length > 0) {\r
- Item item = _data._expandedItems[0];\r
- item._selected = true;\r
- changed = true;\r
- }\r
-\r
- if (changed) {\r
- ensureVisibleItem(-1, false);\r
- redraw();\r
- fireSelectionChanged();\r
- }\r
- }\r
-\r
- /**\r
- * Select an event\r
- *\r
- * @param n\r
- * 1 for next event, -1 for previous event\r
- */\r
- public void selectEvent(int n) {\r
- if (null == _timeProvider) {\r
- return;\r
- }\r
- ITimeGraphEntry trace = getSelectedTrace();\r
- if (trace == null) {\r
- return;\r
- }\r
- long selectedTime = _timeProvider.getSelectedTime();\r
- long endTime = _timeProvider.getEndTime();\r
- ITimeEvent nextEvent;\r
- if (-1 == n && selectedTime > endTime) {\r
- nextEvent = Utils.findEvent(trace, selectedTime, 0);\r
- } else {\r
- nextEvent = Utils.findEvent(trace, selectedTime, n);\r
- }\r
- if (null == nextEvent && -1 == n) {\r
- nextEvent = Utils.getFirstEvent(trace);\r
- }\r
- if (null != nextEvent) {\r
- long nextTime = nextEvent.getTime();\r
- // If last event detected e.g. going back or not moving to a next\r
- // event\r
- if (nextTime <= selectedTime && n == 1) {\r
- // Select to the end of this last event\r
- nextTime = nextEvent.getTime() + nextEvent.getDuration();\r
- // but not beyond the end of the trace\r
- if (nextTime > endTime) {\r
- nextTime = endTime;\r
- }\r
- } else if (n == -1) {\r
- // for previous event go to its end time unless we were already there\r
- if (nextEvent.getTime() + nextEvent.getDuration() < selectedTime) {\r
- nextTime = nextEvent.getTime() + nextEvent.getDuration();\r
- }\r
- }\r
- _timeProvider.setSelectedTimeNotify(nextTime, true);\r
- fireSelectionChanged();\r
- } else if (1 == n) {\r
- _timeProvider.setSelectedTimeNotify(endTime, true);\r
- fireSelectionChanged();\r
- }\r
- }\r
-\r
- /**\r
- * Select the next event\r
- */\r
- public void selectNextEvent() {\r
- selectEvent(1);\r
- // Notify if visible time window has been adjusted\r
- _timeProvider.setStartFinishTimeNotify(_timeProvider.getTime0(), _timeProvider.getTime1());\r
- }\r
-\r
- /**\r
- * Select the previous event\r
- */\r
- public void selectPrevEvent() {\r
- selectEvent(-1);\r
- // Notify if visible time window has been adjusted\r
- _timeProvider.setStartFinishTimeNotify(_timeProvider.getTime0(), _timeProvider.getTime1());\r
- }\r
-\r
- /**\r
- * Select the next trace\r
- */\r
- public void selectNextTrace() {\r
- selectTrace(1);\r
- }\r
-\r
- /**\r
- * Select the previous trace\r
- */\r
- public void selectPrevTrace() {\r
- selectTrace(-1);\r
- }\r
-\r
- /**\r
- * Zoom based on mouse cursor location with mouse scrolling\r
- *\r
- * @param zoomIn true to zoom in, false to zoom out\r
- */\r
- public void zoom(boolean zoomIn) {\r
- int globalX = getDisplay().getCursorLocation().x;\r
- Point p = toControl(globalX, 0);\r
- int nameSpace = _timeProvider.getNameSpace();\r
- int timeSpace = _timeProvider.getTimeSpace();\r
- int xPos = Math.max(nameSpace, Math.min(nameSpace + timeSpace, p.x));\r
- long time0 = _timeProvider.getTime0();\r
- long time1 = _timeProvider.getTime1();\r
- long interval = time1 - time0;\r
- if (interval == 0) {\r
- interval = 1;\r
- } // to allow getting out of single point interval\r
- long newInterval;\r
- if (zoomIn) {\r
- newInterval = Math.max(Math.round(interval * 0.8), _timeProvider.getMinTimeInterval());\r
- } else {\r
- newInterval = (long) Math.ceil(interval * 1.25);\r
- }\r
- long center = time0 + Math.round(((double) (xPos - nameSpace) / timeSpace * interval));\r
- long newTime0 = center - Math.round((double) newInterval * (center - time0) / interval);\r
- long newTime1 = newTime0 + newInterval;\r
- _timeProvider.setStartFinishTime(newTime0, newTime1);\r
- synchronized (fMouseScrollNotifierLock) {\r
- if (fMouseScrollNotifier == null) {\r
- fMouseScrollNotifier = new MouseScrollNotifier();\r
- fMouseScrollNotifier.start();\r
- }\r
- fMouseScrollNotifier.mouseScrolled();\r
- }\r
- }\r
-\r
- /**\r
- * zoom in using single click\r
- */\r
- public void zoomIn() {\r
- long _time0 = _timeProvider.getTime0();\r
- long _time1 = _timeProvider.getTime1();\r
- long _range = _time1 - _time0;\r
- long selTime = _timeProvider.getSelectedTime();\r
- if (selTime <= _time0 || selTime >= _time1) {\r
- selTime = (_time0 + _time1) / 2;\r
- }\r
- long time0 = selTime - (long) ((selTime - _time0) / zoomCoeff);\r
- long time1 = selTime + (long) ((_time1 - selTime) / zoomCoeff);\r
-\r
- long inaccuracy = (_timeProvider.getMaxTime() - _timeProvider.getMinTime()) - (time1 - time0);\r
-\r
- // Trace.debug("selTime:" + selTime + " time0:" + time0 + " time1:"\r
- // + time1 + " inaccuracy:" + inaccuracy);\r
-\r
- if (inaccuracy > 0 && inaccuracy < 100) {\r
- _timeProvider.setStartFinishTimeNotify(_timeProvider.getMinTime(), _timeProvider.getMaxTime());\r
- return;\r
- }\r
-\r
- long m = _timeProvider.getMinTimeInterval();\r
- if ((time1 - time0) < m) {\r
- time0 = selTime - (selTime - _time0) * m / _range;\r
- time1 = time0 + m;\r
- }\r
-\r
- _timeProvider.setStartFinishTimeNotify(time0, time1);\r
- }\r
-\r
- /**\r
- * zoom out using single click\r
- */\r
- public void zoomOut() {\r
- long _time0 = _timeProvider.getTime0();\r
- long _time1 = _timeProvider.getTime1();\r
- long selTime = _timeProvider.getSelectedTime();\r
- if (selTime <= _time0 || selTime >= _time1) {\r
- selTime = (_time0 + _time1) / 2;\r
- }\r
- long time0 = (long) (selTime - (selTime - _time0) * zoomCoeff);\r
- long time1 = (long) (selTime + (_time1 - selTime) * zoomCoeff);\r
-\r
- long inaccuracy = (_timeProvider.getMaxTime() - _timeProvider.getMinTime()) - (time1 - time0);\r
- if (inaccuracy > 0 && inaccuracy < 100) {\r
- _timeProvider.setStartFinishTimeNotify(_timeProvider.getMinTime(), _timeProvider.getMaxTime());\r
- return;\r
- }\r
-\r
- _timeProvider.setStartFinishTimeNotify(time0, time1);\r
- }\r
-\r
- /**\r
- * Return the currently selected trace\r
- *\r
- * @return The entry matching the trace\r
- */\r
- public ITimeGraphEntry getSelectedTrace() {\r
- ITimeGraphEntry trace = null;\r
- int idx = getSelectedIndex();\r
- if (idx >= 0) {\r
- trace = _data._expandedItems[idx]._trace;\r
- }\r
- return trace;\r
- }\r
-\r
- /**\r
- * Retrieve the index of the currently selected item\r
- *\r
- * @return The index\r
- */\r
- public int getSelectedIndex() {\r
- int idx = -1;\r
- for (int i = 0; i < _data._expandedItems.length; i++) {\r
- Item item = _data._expandedItems[i];\r
- if (item._selected) {\r
- idx = i;\r
- break;\r
- }\r
- }\r
- return idx;\r
- }\r
-\r
- boolean toggle(int idx) {\r
- boolean toggled = false;\r
- if (idx >= 0 && idx < _data._expandedItems.length) {\r
- Item item = _data._expandedItems[idx];\r
- if (item._hasChildren) {\r
- item._expanded = !item._expanded;\r
- _data.updateExpandedItems();\r
- adjustScrolls();\r
- redraw();\r
- toggled = true;\r
- fireTreeEvent(item._trace, item._expanded);\r
- }\r
- }\r
- return toggled;\r
- }\r
-\r
- int getItemIndexAtY(int y) {\r
- if (y < 0) {\r
- return -1;\r
- }\r
- if (_itemHeight == CUSTOM_ITEM_HEIGHT) {\r
- int ySum = 0;\r
- for (int idx = _topIndex; idx < _data._expandedItems.length; idx++) {\r
- ySum += _data._expandedItems[idx].itemHeight;\r
- if (y < ySum) {\r
- return idx;\r
- }\r
- }\r
- return -1;\r
- }\r
- int idx = y / _itemHeight;\r
- idx += _topIndex;\r
- if (idx < _data._expandedItems.length) {\r
- return idx;\r
- }\r
- return -1;\r
- }\r
-\r
- boolean isOverSplitLine(int x) {\r
- if (x < 0 || null == _timeProvider) {\r
- return false;\r
- }\r
- int w = 4;\r
- int nameWidth = _timeProvider.getNameSpace();\r
- if (x > nameWidth - w && x < nameWidth + w) {\r
- return true;\r
- }\r
- return false;\r
- }\r
-\r
- ITimeGraphEntry getEntry(Point pt) {\r
- int idx = getItemIndexAtY(pt.y);\r
- return idx >= 0 ? _data._expandedItems[idx]._trace : null;\r
- }\r
-\r
- long getTimeAtX(int x) {\r
- if (null == _timeProvider) {\r
- return -1;\r
- }\r
- long hitTime = -1;\r
- Point size = getCtrlSize();\r
- long time0 = _timeProvider.getTime0();\r
- long time1 = _timeProvider.getTime1();\r
- int nameWidth = _timeProvider.getNameSpace();\r
- x -= nameWidth;\r
- int timeWidth = size.x - nameWidth - RIGHT_MARGIN;\r
- if (x >= 0 && size.x >= nameWidth) {\r
- if (time1 - time0 > timeWidth) {\r
- // nanosecond smaller than one pixel: use the first integer nanosecond of this pixel's time range\r
- hitTime = time0 + (long) Math.ceil((time1 - time0) * ((double) x / timeWidth));\r
- } else {\r
- // nanosecond greater than one pixel: use the nanosecond that covers this pixel start position\r
- hitTime = time0 + (long) Math.floor((time1 - time0) * ((double) x / timeWidth));\r
- }\r
- }\r
- return hitTime;\r
- }\r
-\r
- void selectItem(int idx, boolean addSelection) {\r
- boolean changed = false;\r
- if (addSelection) {\r
- if (idx >= 0 && idx < _data._expandedItems.length) {\r
- Item item = _data._expandedItems[idx];\r
- changed = (item._selected == false);\r
- item._selected = true;\r
- }\r
- } else {\r
- for (int i = 0; i < _data._expandedItems.length; i++) {\r
- Item item = _data._expandedItems[i];\r
- if ((i == idx && !item._selected) || (idx == -1 && item._selected)) {\r
- changed = true;\r
- }\r
- item._selected = i == idx;\r
- }\r
- }\r
- changed |= ensureVisibleItem(idx, true);\r
- if (changed) {\r
- redraw();\r
- }\r
- }\r
-\r
- /**\r
- * Callback for item selection\r
- *\r
- * @param trace\r
- * The entry matching the trace\r
- * @param addSelection\r
- * If the selection is added or removed\r
- */\r
- public void selectItem(ITimeGraphEntry trace, boolean addSelection) {\r
- int idx = _data.findItemIndex(trace);\r
- selectItem(idx, addSelection);\r
- }\r
-\r
- /**\r
- * Retrieve the number of entries shown per page.\r
- *\r
- * @return The count\r
- */\r
- public int countPerPage() {\r
- int height = getCtrlSize().y;\r
- int count = 0;\r
- if (_itemHeight == CUSTOM_ITEM_HEIGHT) {\r
- int ySum = 0;\r
- for (int idx = _topIndex; idx < _data._expandedItems.length; idx++) {\r
- ySum += _data._expandedItems[idx].itemHeight;\r
- if (ySum >= height) {\r
- return count;\r
- }\r
- count++;\r
- }\r
- for (int idx = _topIndex - 1; idx >= 0; idx--) {\r
- ySum += _data._expandedItems[idx].itemHeight;\r
- if (ySum >= height) {\r
- return count;\r
- }\r
- count++;\r
- }\r
- return count;\r
- }\r
- if (height > 0) {\r
- count = height / _itemHeight;\r
- }\r
- return count;\r
- }\r
-\r
- /**\r
- * Get the index of the top element\r
- *\r
- * @return The index\r
- */\r
- public int getTopIndex() {\r
- return _topIndex;\r
- }\r
-\r
- /**\r
- * Get the number of expanded items\r
- *\r
- * @return The count of expanded items\r
- */\r
- public int getExpandedElementCount() {\r
- return _data._expandedItems.length;\r
- }\r
-\r
- /**\r
- * Get an array of all expanded elements\r
- *\r
- * @return The expanded elements\r
- */\r
- public ITimeGraphEntry[] getExpandedElements() {\r
- ArrayList<ITimeGraphEntry> elements = new ArrayList<ITimeGraphEntry>();\r
- for (Item item : _data._expandedItems) {\r
- elements.add(item._trace);\r
- }\r
- return elements.toArray(new ITimeGraphEntry[0]);\r
- }\r
-\r
- Point getCtrlSize() {\r
- Point size = getSize();\r
- if (getHorizontalBar().isVisible()) {\r
- size.y -= getHorizontalBar().getSize().y;\r
- }\r
- return size;\r
- }\r
-\r
- Rectangle getNameRect(Rectangle bound, int idx, int nameWidth) {\r
- int x = bound.x;\r
- int y = bound.y + (idx - _topIndex) * _itemHeight;\r
- int width = nameWidth;\r
- int height = _itemHeight;\r
- if (_itemHeight == CUSTOM_ITEM_HEIGHT) {\r
- int ySum = 0;\r
- for (int i = _topIndex; i < idx; i++) {\r
- ySum += _data._expandedItems[i].itemHeight;\r
- }\r
- y = bound.y + ySum;\r
- height = _data._expandedItems[idx].itemHeight;\r
- }\r
- return new Rectangle(x, y, width, height);\r
- }\r
-\r
- Rectangle getStatesRect(Rectangle bound, int idx, int nameWidth) {\r
- int x = bound.x + nameWidth;\r
- int y = bound.y + (idx - _topIndex) * _itemHeight;\r
- int width = bound.width - x;\r
- int height = _itemHeight;\r
- if (_itemHeight == CUSTOM_ITEM_HEIGHT) {\r
- int ySum = 0;\r
- for (int i = _topIndex; i < idx; i++) {\r
- ySum += _data._expandedItems[i].itemHeight;\r
- }\r
- y = bound.y + ySum;\r
- height = _data._expandedItems[idx].itemHeight;\r
- }\r
- return new Rectangle(x, y, width, height);\r
- }\r
-\r
- @Override\r
- void paint(Rectangle bounds, PaintEvent e) {\r
- GC gc = e.gc;\r
- gc.setBackground(_colors.getColor(TimeGraphColorScheme.BACKGROUND));\r
- drawBackground(gc, bounds.x, bounds.y, bounds.width, bounds.height);\r
-\r
- if (bounds.width < 2 || bounds.height < 2 || null == _timeProvider) {\r
- return;\r
- }\r
-\r
- _idealNameSpace = 0;\r
- int nameSpace = _timeProvider.getNameSpace();\r
-\r
- // draw empty name space background\r
- gc.setBackground(_colors.getBkColor(false, false, true));\r
- drawBackground(gc, bounds.x, bounds.y, nameSpace, bounds.height);\r
-\r
- drawItems(bounds, _timeProvider, _data._expandedItems, _topIndex, nameSpace, gc);\r
-\r
- // draw selected time\r
- long time0 = _timeProvider.getTime0();\r
- long time1 = _timeProvider.getTime1();\r
- long selectedTime = _timeProvider.getSelectedTime();\r
- double pixelsPerNanoSec = (bounds.width - nameSpace <= RIGHT_MARGIN) ? 0 : (double) (bounds.width - nameSpace - RIGHT_MARGIN) / (time1 - time0);\r
- int x = bounds.x + nameSpace + (int) ((selectedTime - time0) * pixelsPerNanoSec);\r
- if (x >= nameSpace && x < bounds.x + bounds.width) {\r
- gc.setForeground(_colors.getColor(TimeGraphColorScheme.SELECTED_TIME));\r
- gc.drawLine(x, bounds.y, x, bounds.y + bounds.height);\r
- }\r
-\r
- // draw drag line, no line if name space is 0.\r
- if (DRAG_SPLIT_LINE == _dragState) {\r
- gc.setForeground(_colors.getColor(TimeGraphColorScheme.BLACK));\r
- gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);\r
- } else if (DRAG_NONE == _dragState && _mouseOverSplitLine && _timeProvider.getNameSpace() > 0) {\r
- gc.setForeground(_colors.getColor(TimeGraphColorScheme.RED));\r
- gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);\r
- }\r
- }\r
-\r
- /**\r
- * Draw many items at once\r
- *\r
- * @param bounds\r
- * The rectangle of the area\r
- * @param timeProvider\r
- * The time provider\r
- * @param items\r
- * The array items to draw\r
- * @param topIndex\r
- * The index of the first element to draw\r
- * @param nameSpace\r
- * The width reserved for the names\r
- * @param gc\r
- * Reference to the SWT GC object\r
- */\r
- public void drawItems(Rectangle bounds, ITimeDataProvider timeProvider,\r
- Item[] items, int topIndex, int nameSpace, GC gc) {\r
- for (int i = topIndex; i < items.length; i++) {\r
- Item item = items[i];\r
- drawItem(item, bounds, timeProvider, i, nameSpace, gc);\r
- }\r
- fTimeGraphProvider.postDrawControl(bounds, gc);\r
- }\r
-\r
- /**\r
- * Draws the item\r
- *\r
- * @param item the item to draw\r
- * @param bounds the container rectangle\r
- * @param i the item index\r
- * @param nameSpace the name space\r
- * @param gc\r
- */\r
- protected void drawItem(Item item, Rectangle bounds, ITimeDataProvider timeProvider, int i, int nameSpace, GC gc) {\r
- ITimeGraphEntry entry = item._trace;\r
- long time0 = timeProvider.getTime0();\r
- long time1 = timeProvider.getTime1();\r
- long selectedTime = timeProvider.getSelectedTime();\r
-\r
- Rectangle nameRect = getNameRect(bounds, i, nameSpace);\r
- if (nameRect.y >= bounds.y + bounds.height) {\r
- return;\r
- }\r
-\r
- if (! item._trace.hasTimeEvents()) {\r
- Rectangle statesRect = getStatesRect(bounds, i, nameSpace);\r
- nameRect.width += statesRect.width;\r
- drawName(item, nameRect, gc);\r
- } else {\r
- drawName(item, nameRect, gc);\r
- }\r
- Rectangle rect = getStatesRect(bounds, i, nameSpace);\r
- if (rect.isEmpty()) {\r
- fTimeGraphProvider.postDrawEntry(entry, rect, gc);\r
- return;\r
- }\r
- if (time1 <= time0) {\r
- gc.setBackground(_colors.getBkColor(false, false, false));\r
- gc.fillRectangle(rect);\r
- fTimeGraphProvider.postDrawEntry(entry, rect, gc);\r
- return;\r
- }\r
-\r
- // Initialize _rect1 to same values as enclosing rectangle rect\r
- Rectangle stateRect = Utils.clone(rect);\r
- boolean selected = item._selected;\r
- // K pixels per second\r
- double pixelsPerNanoSec = (rect.width <= RIGHT_MARGIN) ? 0 : (double) (rect.width - RIGHT_MARGIN) / (time1 - time0);\r
-\r
- if (item._trace.hasTimeEvents()) {\r
- fillSpace(rect, gc, selected);\r
- // Drawing rectangle is smaller than reserved space\r
- stateRect.y += 3;\r
- stateRect.height -= 6;\r
-\r
- long maxDuration = (timeProvider.getTimeSpace() == 0) ? Long.MAX_VALUE : 1 * (time1 - time0) / timeProvider.getTimeSpace();\r
- Iterator<ITimeEvent> iterator = entry.getTimeEventsIterator(time0, time1, maxDuration);\r
-\r
- int lastX = -1;\r
- while (iterator.hasNext()) {\r
- ITimeEvent event = iterator.next();\r
- int x = rect.x + (int) ((event.getTime() - time0) * pixelsPerNanoSec);\r
- int xEnd = rect.x + (int) ((event.getTime() + event.getDuration() - time0) * pixelsPerNanoSec);\r
- if (x >= rect.x + rect.width || xEnd < rect.x) {\r
- // event is out of bounds\r
- continue;\r
- }\r
- xEnd = Math.min(rect.x + rect.width, xEnd);\r
- stateRect.x = Math.max(rect.x, x);\r
- stateRect.width = Math.max(0, xEnd - stateRect.x + 1);\r
- if (stateRect.x == lastX) {\r
- stateRect.width -= 1;\r
- if (stateRect.width > 0) {\r
- gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));\r
- gc.drawPoint(stateRect.x, stateRect.y - 2);\r
- stateRect.x += 1;\r
- }\r
- } else {\r
- lastX = x;\r
- }\r
- boolean timeSelected = selectedTime >= event.getTime() && selectedTime < event.getTime() + event.getDuration();\r
- drawState(_colors, event, stateRect, gc, selected, timeSelected);\r
- }\r
- }\r
- fTimeGraphProvider.postDrawEntry(entry, rect, gc);\r
- }\r
-\r
- protected void drawName(Item item, Rectangle bounds, GC gc) {\r
- boolean hasTimeEvents = item._trace.hasTimeEvents();\r
- if (! hasTimeEvents) {\r
- gc.setBackground(_colors.getBkColorGroup(item._selected, _isInFocus));\r
- gc.fillRectangle(bounds);\r
- if (item._selected && _isInFocus) {\r
- gc.setForeground(_colors.getBkColor(item._selected, _isInFocus, false));\r
- gc.drawRectangle(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);\r
- }\r
- } else {\r
- gc.setBackground(_colors.getBkColor(item._selected, _isInFocus, true));\r
- gc.setForeground(_colors.getFgColor(item._selected, _isInFocus));\r
- gc.fillRectangle(bounds);\r
- }\r
-\r
- // No name to be drawn\r
- if (_timeProvider.getNameSpace() == 0) {\r
- return;\r
- }\r
-\r
- int leftMargin = MARGIN + item.level * EXPAND_SIZE;\r
- if (item._hasChildren) {\r
- gc.setForeground(_colors.getFgColorGroup(false, false));\r
- gc.setBackground(_colors.getBkColor(false, false, false));\r
- Rectangle rect = Utils.clone(bounds);\r
- rect.x += leftMargin;\r
- rect.y += (bounds.height - EXPAND_SIZE) / 2;\r
- rect.width = EXPAND_SIZE;\r
- rect.height = EXPAND_SIZE;\r
- gc.fillRectangle(rect);\r
- gc.drawRectangle(rect.x, rect.y, rect.width - 1, rect.height - 1);\r
- int midy = rect.y + rect.height / 2;\r
- gc.drawLine(rect.x + 2, midy, rect.x + rect.width - 3, midy);\r
- if (!item._expanded) {\r
- int midx = rect.x + rect.width / 2;\r
- gc.drawLine(midx, rect.y + 2, midx, rect.y + rect.height - 3);\r
- }\r
- }\r
- leftMargin += EXPAND_SIZE + MARGIN;\r
-\r
- Image img = fTimeGraphProvider.getItemImage(item._trace);\r
- if (img != null) {\r
- // draw icon\r
- int imgHeight = img.getImageData().height;\r
- int imgWidth = img.getImageData().width;\r
- int x = leftMargin;\r
- int y = bounds.y + (bounds.height - imgHeight) / 2;\r
- gc.drawImage(img, x, y);\r
- leftMargin += imgWidth + MARGIN;\r
- }\r
- String name = item._name;\r
- Point size = gc.stringExtent(name);\r
- if (_idealNameSpace < leftMargin + size.x + MARGIN) {\r
- _idealNameSpace = leftMargin + size.x + MARGIN;\r
- }\r
- if (hasTimeEvents) {\r
- // cut long string with "..."\r
- int width = bounds.width - leftMargin;\r
- int cuts = 0;\r
- while (size.x > width && name.length() > 1) {\r
- cuts++;\r
- name = name.substring(0, name.length() - 1);\r
- size = gc.stringExtent(name + "..."); //$NON-NLS-1$\r
- }\r
- if (cuts > 0) {\r
- name += "..."; //$NON-NLS-1$\r
- }\r
- }\r
- Rectangle rect = Utils.clone(bounds);\r
- rect.x += leftMargin;\r
- rect.width -= leftMargin;\r
- // draw text\r
- if (rect.width > 0) {\r
- rect.y += (bounds.height - gc.stringExtent(name).y) / 2;\r
- gc.setForeground(_colors.getFgColor(item._selected, _isInFocus));\r
- int textWidth = Utils.drawText(gc, name, rect, true);\r
- leftMargin += textWidth + MARGIN;\r
- rect.y -= 2;\r
-\r
- if (hasTimeEvents) {\r
- // draw middle line\r
- int x = bounds.x + leftMargin;\r
- int width = bounds.width - x;\r
- int midy = bounds.y + bounds.height / 2;\r
- gc.setForeground(_colors.getColor(TimeGraphColorScheme.MID_LINE));\r
- gc.drawLine(x, midy, x + width, midy);\r
- }\r
- }\r
- }\r
-\r
- protected void drawState(TimeGraphColorScheme colors, ITimeEvent event,\r
- Rectangle rect, GC gc, boolean selected, boolean timeSelected) {\r
-\r
- int colorIdx = fTimeGraphProvider.getStateTableIndex(event);\r
- if (colorIdx < 0) {\r
- return;\r
- }\r
- boolean visible = rect.width == 0 ? false : true;\r
-\r
- if (visible) {\r
- Color stateColor = null;\r
- if (colorIdx < fEventColorMap.length) {\r
- stateColor = fEventColorMap[colorIdx];\r
- } else {\r
- stateColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);\r
- }\r
-\r
- timeSelected = timeSelected && selected;\r
- if (timeSelected) {\r
- // modify the color?\r
- }\r
- // fill all rect area\r
- gc.setBackground(stateColor);\r
- gc.fillRectangle(rect);\r
- // get the border color?\r
- gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));\r
-\r
- // draw bounds\r
- if (!timeSelected) {\r
- // Draw the top and bottom borders i.e. no side borders\r
- // top\r
- gc.drawLine(rect.x, rect.y, rect.x + rect.width - 1, rect.y);\r
- // bottom\r
- gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1);\r
- }\r
- } else {\r
- gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));\r
- gc.drawPoint(rect.x, rect.y - 2);\r
- /*\r
- // selected rectangle area is not visible but can be represented\r
- // with a broken vertical line of specified width.\r
- int width = 1;\r
- rect.width = width;\r
- gc.setForeground(stateColor);\r
- int s = gc.getLineStyle();\r
- int w = gc.getLineWidth();\r
- gc.setLineStyle(SWT.LINE_DOT);\r
- gc.setLineWidth(width);\r
- // Trace.debug("Rectangle not visible, drawing vertical line with: "\r
- // + rect.x + "," + rect.y + "," + rect.x + "," + rect.y\r
- // + rect.height);\r
- gc.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height - 1);\r
- gc.setLineStyle(s);\r
- gc.setLineWidth(w);\r
- if (!timeSelected) {\r
- gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));\r
- gc.drawPoint(rect.x, rect.y);\r
- gc.drawPoint(rect.x, rect.y + rect.height - 1);\r
- }\r
- */\r
- }\r
- fTimeGraphProvider.postDrawEvent(event, rect, gc);\r
- }\r
-\r
- protected void fillSpace(Rectangle rect, GC gc, boolean selected) {\r
- gc.setBackground(_colors.getBkColor(selected, _isInFocus, false));\r
- gc.fillRectangle(rect);\r
- // draw middle line\r
- gc.setForeground(_colors.getColor(TimeGraphColorScheme.MID_LINE));\r
- int midy = rect.y + rect.height / 2;\r
- gc.drawLine(rect.x, midy, rect.x + rect.width, midy);\r
- }\r
-\r
- @Override\r
- public void keyTraversed(TraverseEvent e) {\r
- if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS)) {\r
- e.doit = true;\r
- }\r
- }\r
-\r
- @Override\r
- public void keyPressed(KeyEvent e) {\r
- int idx = -1;\r
- if (_data._expandedItems.length == 0) {\r
- return;\r
- }\r
- if (SWT.HOME == e.keyCode) {\r
- idx = 0;\r
- } else if (SWT.END == e.keyCode) {\r
- idx = _data._expandedItems.length - 1;\r
- } else if (SWT.ARROW_DOWN == e.keyCode) {\r
- idx = getSelectedIndex();\r
- if (idx < 0) {\r
- idx = 0;\r
- } else if (idx < _data._expandedItems.length - 1) {\r
- idx++;\r
- }\r
- } else if (SWT.ARROW_UP == e.keyCode) {\r
- idx = getSelectedIndex();\r
- if (idx < 0) {\r
- idx = 0;\r
- } else if (idx > 0) {\r
- idx--;\r
- }\r
- } else if (SWT.ARROW_LEFT == e.keyCode) {\r
- selectPrevEvent();\r
- } else if (SWT.ARROW_RIGHT == e.keyCode) {\r
- selectNextEvent();\r
- } else if (SWT.PAGE_DOWN == e.keyCode) {\r
- int page = countPerPage();\r
- idx = getSelectedIndex();\r
- if (idx < 0) {\r
- idx = 0;\r
- }\r
- idx += page;\r
- if (idx >= _data._expandedItems.length) {\r
- idx = _data._expandedItems.length - 1;\r
- }\r
- } else if (SWT.PAGE_UP == e.keyCode) {\r
- int page = countPerPage();\r
- idx = getSelectedIndex();\r
- if (idx < 0) {\r
- idx = 0;\r
- }\r
- idx -= page;\r
- if (idx < 0) {\r
- idx = 0;\r
- }\r
- } else if (SWT.CR == e.keyCode) {\r
- idx = getSelectedIndex();\r
- if (idx >= 0) {\r
- if (_data._expandedItems[idx]._hasChildren) {\r
- toggle(idx);\r
- } else {\r
- fireDefaultSelection();\r
- }\r
- }\r
- idx = -1;\r
- }\r
- if (idx >= 0) {\r
- selectItem(idx, false);\r
- fireSelectionChanged();\r
- }\r
- }\r
-\r
- @Override\r
- public void keyReleased(KeyEvent e) {\r
- }\r
-\r
- @Override\r
- public void focusGained(FocusEvent e) {\r
- _isInFocus = true;\r
- if (mouseScrollFilterListener == null) {\r
- mouseScrollFilterListener = new Listener() {\r
- // This filter is used to prevent horizontal scrolling of the view\r
- // when the mouse wheel is used to zoom\r
- @Override\r
- public void handleEvent(Event event) {\r
- event.doit = false;\r
- }\r
- };\r
- getDisplay().addFilter(SWT.MouseWheel, mouseScrollFilterListener);\r
- }\r
- redraw();\r
- }\r
-\r
- @Override\r
- public void focusLost(FocusEvent e) {\r
- _isInFocus = false;\r
- if (mouseScrollFilterListener != null) {\r
- getDisplay().removeFilter(SWT.MouseWheel, mouseScrollFilterListener);\r
- mouseScrollFilterListener = null;\r
- }\r
- if (DRAG_NONE != _dragState) {\r
- setCapture(false);\r
- _dragState = DRAG_NONE;\r
- }\r
- redraw();\r
- }\r
-\r
- /**\r
- * @return If the current view is focused\r
- */\r
- public boolean isInFocus() {\r
- return _isInFocus;\r
- }\r
-\r
- /**\r
- * Provide the possibility to control the wait cursor externally e.g. data\r
- * requests in progress\r
- *\r
- * @param waitInd Should we wait indefinitely?\r
- */\r
- public void waitCursor(boolean waitInd) {\r
- // Update cursor as indicated\r
- if (waitInd) {\r
- setCursor(_WaitCursor);\r
- _isWaitCursor = true;\r
- } else {\r
- setCursor(null);\r
- _isWaitCursor = false;\r
- }\r
-\r
- // Get ready for next mouse move\r
- _isDragCursor3 = false;\r
- }\r
-\r
- /**\r
- * <p>\r
- * If the x, y position is over the vertical split line (name to time\r
- * ranges), then change the cursor to a drag cursor to indicate the user the\r
- * possibility of resizing\r
- * </p>\r
- *\r
- * @param x\r
- * @param y\r
- */\r
- void updateCursor(int x, int y) {\r
- // if Wait cursor not active, check for the need to change to a drag\r
- // cursor\r
- if (_isWaitCursor == false) {\r
- boolean isSplitLine = isOverSplitLine(x);\r
- // No dragcursor is name space is fixed to zero\r
- if (isSplitLine && !_isDragCursor3 && _timeProvider.getNameSpace() > 0) {\r
- setCursor(_dragCursor3);\r
- _isDragCursor3 = true;\r
- } else if (!isSplitLine && _isDragCursor3) {\r
- setCursor(null);\r
- _isDragCursor3 = false;\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public void mouseMove(MouseEvent e) {\r
- if (null == _timeProvider) {\r
- return;\r
- }\r
- Point size = getCtrlSize();\r
- if (DRAG_TRACE_ITEM == _dragState) {\r
- int nameWidth = _timeProvider.getNameSpace();\r
- int x = e.x - nameWidth;\r
- if (x > 0 && size.x > nameWidth && _dragX != x) {\r
- _dragX = x;\r
- double pixelsPerNanoSec = (size.x - nameWidth <= RIGHT_MARGIN) ? 0 : (double) (size.x - nameWidth - RIGHT_MARGIN) / (_time1bak - _time0bak);\r
- long timeDelta = (long) ((pixelsPerNanoSec == 0) ? 0 : ((_dragX - _dragX0) / pixelsPerNanoSec));\r
- long time1 = _time1bak - timeDelta;\r
- long maxTime = _timeProvider.getMaxTime();\r
- if (time1 > maxTime) {\r
- time1 = maxTime;\r
- }\r
- long time0 = time1 - (_time1bak - _time0bak);\r
- if (time0 < _timeProvider.getMinTime()) {\r
- time0 = _timeProvider.getMinTime();\r
- time1 = time0 + (_time1bak - _time0bak);\r
- }\r
- _timeProvider.setStartFinishTime(time0, time1);\r
- }\r
- } else if (DRAG_SPLIT_LINE == _dragState) {\r
- _dragX = e.x;\r
- _timeProvider.setNameSpace(e.x);\r
- } else if (DRAG_NONE == _dragState) {\r
- boolean mouseOverSplitLine = isOverSplitLine(e.x);\r
- if (_mouseOverSplitLine != mouseOverSplitLine) {\r
- redraw();\r
- }\r
- _mouseOverSplitLine = mouseOverSplitLine;\r
- }\r
- updateCursor(e.x, e.y);\r
- }\r
-\r
- @Override\r
- public void mouseDoubleClick(MouseEvent e) {\r
- if (null == _timeProvider) {\r
- return;\r
- }\r
- if (1 == e.button) {\r
- if (isOverSplitLine(e.x) && _timeProvider.getNameSpace() != 0) {\r
- _timeProvider.setNameSpace(_idealNameSpace);\r
- boolean mouseOverSplitLine = isOverSplitLine(e.x);\r
- if (_mouseOverSplitLine != mouseOverSplitLine) {\r
- redraw();\r
- }\r
- _mouseOverSplitLine = mouseOverSplitLine;\r
- return;\r
- }\r
- int idx = getItemIndexAtY(e.y);\r
- if (idx >= 0) {\r
- selectItem(idx, false);\r
- fireDefaultSelection();\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public void mouseDown(MouseEvent e) {\r
- if (null == _timeProvider) {\r
- return;\r
- }\r
- int idx;\r
- if (1 == e.button) {\r
- int nameSpace = _timeProvider.getNameSpace();\r
- if (nameSpace != 0) {\r
- if (isOverSplitLine(e.x)) {\r
- _dragState = DRAG_SPLIT_LINE;\r
- _dragX = _dragX0 = e.x;\r
- _time0bak = _timeProvider.getTime0();\r
- _time1bak = _timeProvider.getTime1();\r
- redraw();\r
- return;\r
- }\r
- }\r
-\r
- idx = getItemIndexAtY(e.y);\r
- if (idx >= 0) {\r
- Item item = _data._expandedItems[idx];\r
- if (item._hasChildren && e.x < nameSpace && e.x < MARGIN + (item.level + 1) * EXPAND_SIZE) {\r
- toggle(idx);\r
- } else {\r
- long hitTime = getTimeAtX(e.x);\r
- if (hitTime >= 0) {\r
- // _timeProvider.setSelectedTimeInt(hitTime, false);\r
- setCapture(true);\r
- _dragState = DRAG_TRACE_ITEM;\r
- _dragX = _dragX0 = e.x - nameSpace;\r
- _time0bak = _timeProvider.getTime0();\r
- _time1bak = _timeProvider.getTime1();\r
- }\r
- }\r
- selectItem(idx, false);\r
- fireSelectionChanged();\r
- } else {\r
- selectItem(idx, false); // clear selection\r
- redraw();\r
- fireSelectionChanged();\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public void mouseUp(MouseEvent e) {\r
- if (DRAG_NONE != _dragState) {\r
- setCapture(false);\r
- if (DRAG_TRACE_ITEM == _dragState) {\r
- // Notify time provider to check the need for listener\r
- // notification\r
- _timeProvider.notifyStartFinishTime();\r
- if (_dragX == _dragX0) { // click without drag\r
- long time = getTimeAtX(e.x);\r
- _timeProvider.setSelectedTimeNotify(time, false);\r
- }\r
- } else if (DRAG_SPLIT_LINE == _dragState) {\r
- redraw();\r
- }\r
- _dragState = DRAG_NONE;\r
- }\r
- }\r
-\r
- @Override\r
- public void mouseEnter(MouseEvent e) {\r
- }\r
-\r
- @Override\r
- public void mouseExit(MouseEvent e) {\r
- if (_mouseOverSplitLine) {\r
- _mouseOverSplitLine = false;\r
- redraw();\r
- }\r
- }\r
-\r
- @Override\r
- public void mouseHover(MouseEvent e) {\r
- }\r
-\r
- @Override\r
- public void mouseScrolled(MouseEvent e) {\r
- if ((mouseScrollFilterListener == null) || _dragState != DRAG_NONE) {\r
- return;\r
- }\r
- boolean zoomScroll = false;\r
- Point p = getParent().toControl(getDisplay().getCursorLocation());\r
- Point parentSize = getParent().getSize();\r
- if (p.x >= 0 && p.x < parentSize.x && p.y >= 0 && p.y < parentSize.y) {\r
- // over the parent control\r
- if (e.x > getCtrlSize().x) {\r
- // over the horizontal scroll bar\r
- zoomScroll = false;\r
- } else if (e.y >= 0 && e.y < getCtrlSize().y && e.x < _timeProvider.getNameSpace()) {\r
- // over the name space\r
- zoomScroll = false;\r
- } else {\r
- zoomScroll = true;\r
- }\r
- }\r
- if (zoomScroll && _timeProvider.getTime0() != _timeProvider.getTime1()) {\r
- if (e.count > 0) {\r
- zoom(true);\r
- } else if (e.count < 0) {\r
- zoom(false);\r
- }\r
- } else {\r
- setTopIndex(getTopIndex() - e.count);\r
- }\r
- }\r
-\r
- @Override\r
- public void controlMoved(ControlEvent e) {\r
- }\r
-\r
- @Override\r
- public void controlResized(ControlEvent e) {\r
- adjustScrolls();\r
- }\r
-\r
- @Override\r
- public void widgetDefaultSelected(SelectionEvent e) {\r
- }\r
-\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- if (e.widget == getVerticalBar()) {\r
- setTopIndex(getVerticalBar().getSelection());\r
- } else if (e.widget == getHorizontalBar() && null != _timeProvider) {\r
- int start = getHorizontalBar().getSelection();\r
- long time0 = _timeProvider.getTime0();\r
- long time1 = _timeProvider.getTime1();\r
- long timeMin = _timeProvider.getMinTime();\r
- long timeMax = _timeProvider.getMaxTime();\r
- long delta = timeMax - timeMin;\r
-\r
- long range = time1 - time0;\r
- // _timeRangeFixed = true;\r
- time0 = timeMin + Math.round(delta * ((double) start / H_SCROLLBAR_MAX));\r
- time1 = time0 + range;\r
-\r
- // TODO: Follow-up with Bug 310310\r
- // In Linux SWT.DRAG is the only value received\r
- // https://bugs.eclipse.org/bugs/show_bug.cgi?id=310310\r
- if (e.detail == SWT.DRAG) {\r
- _timeProvider.setStartFinishTime(time0, time1);\r
- } else {\r
- _timeProvider.setStartFinishTimeNotify(time0, time1);\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * @return The current visibility of the vertical scroll bar\r
- */\r
- public boolean isVisibleVerticalScroll() {\r
- return _visibleVerticalScroll;\r
- }\r
-\r
- @Override\r
- public int getBorderWidth() {\r
- return _borderWidth;\r
- }\r
-\r
- /**\r
- * Set the border width\r
- *\r
- * @param borderWidth\r
- * The width\r
- */\r
- public void setBorderWidth(int borderWidth) {\r
- this._borderWidth = borderWidth;\r
- }\r
-\r
- /**\r
- * @return The current height of the header row\r
- */\r
- public int getHeaderHeight() {\r
- return _headerHeight;\r
- }\r
-\r
- /**\r
- * Set the height of the header row\r
- *\r
- * @param headerHeight\r
- * The height\r
- */\r
- public void setHeaderHeight(int headerHeight) {\r
- this._headerHeight = headerHeight;\r
- }\r
-\r
- /**\r
- * @return The height of regular item rows\r
- */\r
- public int getItemHeight() {\r
- return _itemHeight;\r
- }\r
-\r
- /**\r
- * Set the height of regular itew rows\r
- *\r
- * @param rowHeight\r
- * The height\r
- */\r
- public void setItemHeight(int rowHeight) {\r
- this._itemHeight = rowHeight;\r
- }\r
-\r
- /**\r
- * Set the minimum item width\r
- *\r
- * @param width The minimum width\r
- */\r
- public void setMinimumItemWidth(int width) {\r
- this._minimumItemWidth = width;\r
- }\r
-\r
- /**\r
- * @return The minimum item width\r
- */\r
- public int getMinimumItemWidth() {\r
- return _minimumItemWidth;\r
- }\r
-\r
- /**\r
- * @return The entries that are currently filtered out\r
- */\r
- public Vector<ITimeGraphEntry> getFilteredOut() {\r
- return _data.getFilteredOut();\r
- }\r
-\r
- // @Override\r
- @Override\r
- public void addSelectionChangedListener(ISelectionChangedListener listener) {\r
- if (listener != null) {\r
- if (!_selectionChangedListeners.contains(listener)) {\r
- _selectionChangedListeners.add(listener);\r
- }\r
- }\r
- }\r
-\r
- // @Override\r
- @Override\r
- public void removeSelectionChangedListener(ISelectionChangedListener listener) {\r
- if (listener != null) {\r
- _selectionChangedListeners.remove(listener);\r
- }\r
- }\r
-\r
- // @Override\r
- @Override\r
- public void setSelection(ISelection selection) {\r
- if (selection instanceof TimeGraphSelection) {\r
- TimeGraphSelection sel = (TimeGraphSelection) selection;\r
- Object ob = sel.getFirstElement();\r
- if (ob instanceof ITimeGraphEntry) {\r
- ITimeGraphEntry trace = (ITimeGraphEntry) ob;\r
- selectItem(trace, false);\r
- }\r
- }\r
-\r
- }\r
-\r
- private class ItemData {\r
- public Item[] _expandedItems = new Item[0];\r
- public Item[] _items = new Item[0];\r
- private ITimeGraphEntry _traces[] = new ITimeGraphEntry[0];\r
- private boolean traceFilter[] = new boolean[0];\r
- private final Vector<ITimeGraphEntry> filteredOut = new Vector<ITimeGraphEntry>();\r
- public ITimeGraphPresentationProvider provider;\r
-\r
- public ItemData() {\r
- }\r
-\r
- Item findItem(ITimeGraphEntry entry) {\r
- if (entry == null) {\r
- return null;\r
- }\r
-\r
- for (int i = 0; i < _items.length; i++) {\r
- Item item = _items[i];\r
- if (item._trace == entry) {\r
- return item;\r
- }\r
- }\r
-\r
- return null;\r
- }\r
-\r
- int findItemIndex(ITimeGraphEntry trace) {\r
- if (trace == null) {\r
- return -1;\r
- }\r
-\r
- for (int i = 0; i < _expandedItems.length; i++) {\r
- Item item = _expandedItems[i];\r
- if (item._trace == trace) {\r
- return i;\r
- }\r
- }\r
-\r
- return -1;\r
- }\r
-\r
- public void refreshData() {\r
- List<Item> itemList = new ArrayList<Item>();\r
- filteredOut.clear();\r
- for (int i = 0; i < _traces.length; i++) {\r
- ITimeGraphEntry entry = _traces[i];\r
- refreshData(itemList, null, 0, entry);\r
- }\r
- _items = itemList.toArray(new Item[0]);\r
- updateExpandedItems();\r
- }\r
-\r
- private void refreshData(List<Item> itemList, Item parent, int level, ITimeGraphEntry entry) {\r
- Item item = new Item(entry, entry.getName(), level);\r
- if (parent != null) {\r
- parent.children.add(item);\r
- }\r
- item.itemHeight = provider.getItemHeight(entry);\r
- itemList.add(item);\r
- if (entry.hasChildren()) {\r
- item._expanded = true;\r
- item._hasChildren = true;\r
- for (ITimeGraphEntry child : entry.getChildren()) {\r
- refreshData(itemList, item, level + 1, child);\r
- }\r
- }\r
- }\r
-\r
- public void updateExpandedItems() {\r
- List<Item> expandedItemList = new ArrayList<Item>();\r
- for (int i = 0; i < _traces.length; i++) {\r
- ITimeGraphEntry entry = _traces[i];\r
- Item item = findItem(entry);\r
- refreshExpanded(expandedItemList, item);\r
- }\r
- _expandedItems = expandedItemList.toArray(new Item[0]);\r
- }\r
-\r
- private void refreshExpanded(List<Item> expandedItemList, Item item) {\r
- expandedItemList.add(item);\r
- if (item._hasChildren && item._expanded) {\r
- for (Item child : item.children) {\r
- refreshExpanded(expandedItemList, child);\r
- }\r
- }\r
- }\r
-\r
- public void refreshData(ITimeGraphEntry traces[]) {\r
- if (traces == null || traces.length == 0) {\r
- traceFilter = null;\r
- } else if (traceFilter == null || traces.length != traceFilter.length) {\r
- traceFilter = new boolean[traces.length];\r
- java.util.Arrays.fill(traceFilter, true);\r
- }\r
-\r
- _traces = traces;\r
- refreshData();\r
- }\r
-\r
- public ITimeGraphEntry[] getTraces() {\r
- return _traces;\r
- }\r
-\r
- public boolean[] getTraceFilter() {\r
- return traceFilter;\r
- }\r
-\r
- public Vector<ITimeGraphEntry> getFilteredOut() {\r
- return filteredOut;\r
- }\r
- }\r
-\r
- private class Item {\r
- public boolean _expanded;\r
- public boolean _selected;\r
- public boolean _hasChildren;\r
- public int itemHeight;\r
- public int level;\r
- public List<Item> children;\r
- public String _name;\r
- public ITimeGraphEntry _trace;\r
-\r
- public Item(ITimeGraphEntry trace, String name, int level) {\r
- this._trace = trace;\r
- this._name = name;\r
- this.level = level;\r
- this.children = new ArrayList<Item>();\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- return _name;\r
- }\r
- }\r
-\r
-}\r
-\r
+/*****************************************************************************
+ * Copyright (c) 2007, 2008 Intel Corporation, 2009, 2010, 2011, 2012 Ericsson.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Intel Corporation - Initial API and implementation
+ * Ruslan A. Scherbakov, Intel - Initial API and implementation
+ * Alvaro Sanchez-Leon - Updated for TMF
+ * Patrick Tasse - Refactoring
+ *
+ *****************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTreeListener;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.StateItem;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTreeExpansionEvent;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.MouseWheelListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ScrollBar;
+
+/**
+ * Time graph control implementation
+ *
+ * @version 1.0
+ * @author Alvaro Sanchez-Leon
+ * @author Patrick Tasse
+ */
+public class TimeGraphControl extends TimeGraphBaseControl implements FocusListener, KeyListener, MouseMoveListener, MouseListener, MouseWheelListener, ControlListener, SelectionListener, MouseTrackListener, TraverseListener, ISelectionProvider {
+
+ private static final int DRAG_NONE = 0;
+ private static final int DRAG_TRACE_ITEM = 1;
+ private static final int DRAG_SPLIT_LINE = 2;
+ public static final boolean DEFAULT_DRAW_THREAD_JOIN = true;
+ public static final boolean DEFAULT_DRAW_THREAD_WAIT = true;
+ public static final boolean DEFAULT_DRAW_THREAD_RELEASE = true;
+ public static final int H_SCROLLBAR_MAX = Integer.MAX_VALUE - 1;
+ private static final int CUSTOM_ITEM_HEIGHT = -1; // get item height from provider
+
+ private static final double zoomCoeff = 1.5;
+
+ private ITimeDataProvider _timeProvider;
+ private boolean _isInFocus = false;
+ private boolean _isDragCursor3 = false;
+ private boolean _isWaitCursor = true;
+ private boolean _mouseOverSplitLine = false;
+ private int _itemHeight = CUSTOM_ITEM_HEIGHT;
+ private int _minimumItemWidth = 0;
+ private int _topIndex = 0;
+ private int _dragState = DRAG_NONE;
+ private int _dragX0 = 0;
+ private int _dragX = 0;
+ private int _idealNameSpace = 0;
+ // private double _timeStep = 10000000;
+ private long _time0bak;
+ private long _time1bak;
+ private ITimeGraphPresentationProvider fTimeGraphProvider = null;
+ private ItemData _data = null;
+ private List<SelectionListener> _selectionListeners;
+ private final List<ISelectionChangedListener> _selectionChangedListeners = new ArrayList<ISelectionChangedListener>();
+ private final List<ITimeGraphTreeListener> _treeListeners = new ArrayList<ITimeGraphTreeListener>();
+ private final Cursor _dragCursor3;
+ private final Cursor _WaitCursor;
+
+ // Vertical formatting formatting for the state control view
+ private final boolean _visibleVerticalScroll = true;
+ private int _borderWidth = 0;
+ private int _headerHeight = 0;
+
+ private Listener mouseScrollFilterListener;
+
+ protected LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
+ protected Color[] fEventColorMap = null;
+
+ private MouseScrollNotifier fMouseScrollNotifier;
+ private final Object fMouseScrollNotifierLock = new Object();
+ private class MouseScrollNotifier extends Thread {
+ private final static long DELAY = 400L;
+ private final static long POLLING_INTERVAL = 10L;
+ private long fLastScrollTime = Long.MAX_VALUE;
+
+ @Override
+ public void run() {
+ while ((System.currentTimeMillis() - fLastScrollTime) < DELAY) {
+ try {
+ Thread.sleep(POLLING_INTERVAL);
+ } catch (Exception e) {
+ return;
+ }
+ }
+ if (!isInterrupted()) {
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (isDisposed()) {
+ return;
+ }
+ _timeProvider.notifyStartFinishTime();
+ }
+ });
+ }
+ synchronized (fMouseScrollNotifierLock) {
+ fMouseScrollNotifier = null;
+ }
+ }
+
+ public void mouseScrolled() {
+ fLastScrollTime = System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * Standard constructor
+ *
+ * @param parent
+ * The parent composite object
+ * @param colors
+ * The color scheme to use
+ */
+ public TimeGraphControl(Composite parent, TimeGraphColorScheme colors) {
+
+ super(parent, colors, SWT.NO_BACKGROUND | SWT.H_SCROLL | SWT.DOUBLE_BUFFERED);
+
+ _data = new ItemData();
+
+ addFocusListener(this);
+ addMouseListener(this);
+ addMouseMoveListener(this);
+ addMouseTrackListener(this);
+ addMouseWheelListener(this);
+ addTraverseListener(this);
+ addKeyListener(this);
+ addControlListener(this);
+ ScrollBar scrollHor = getHorizontalBar();
+
+ if (scrollHor != null) {
+ scrollHor.addSelectionListener(this);
+ }
+
+ _dragCursor3 = new Cursor(super.getDisplay(), SWT.CURSOR_SIZEWE);
+ _WaitCursor = new Cursor(super.getDisplay(), SWT.CURSOR_WAIT);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ _dragCursor3.dispose();
+ _WaitCursor.dispose();
+ fResourceManager.dispose();
+ }
+
+ /**
+ * Sets the timegraph provider used by this timegraph viewer.
+ *
+ * @param timeGraphProvider the timegraph provider
+ */
+ public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
+ fTimeGraphProvider = timeGraphProvider;
+ _data.provider = timeGraphProvider;
+
+ if (fEventColorMap != null) {
+ for (Color color : fEventColorMap) {
+ fResourceManager.destroyColor(color.getRGB());
+ }
+ }
+ StateItem[] stateItems = fTimeGraphProvider.getStateTable();
+ if (stateItems != null) {
+ fEventColorMap = new Color[stateItems.length];
+ for (int i = 0; i < stateItems.length; i++) {
+ fEventColorMap[i] = fResourceManager.createColor(stateItems[i].getStateColor());
+ }
+ } else {
+ fEventColorMap = new Color[] { };
+ }
+ }
+
+ /**
+ * Assign the given time provider
+ *
+ * @param timeProvider
+ * The time provider
+ */
+ public void setTimeProvider(ITimeDataProvider timeProvider) {
+ _timeProvider = timeProvider;
+ adjustScrolls();
+ redraw();
+ }
+
+ /**
+ * Add a selection listener
+ *
+ * @param listener
+ * The listener to add
+ */
+ public void addSelectionListener(SelectionListener listener) {
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (null == _selectionListeners) {
+ _selectionListeners = new ArrayList<SelectionListener>();
+ }
+ _selectionListeners.add(listener);
+ }
+
+ /**
+ * Remove a selection listener
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeSelectionListener(SelectionListener listener) {
+ if (null != _selectionListeners) {
+ _selectionListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Selection changed callback
+ */
+ public void fireSelectionChanged() {
+ if (null != _selectionListeners) {
+ Iterator<SelectionListener> it = _selectionListeners.iterator();
+ while (it.hasNext()) {
+ SelectionListener listener = it.next();
+ listener.widgetSelected(null);
+ }
+ }
+ }
+
+ /**
+ * Default selection callback
+ */
+ public void fireDefaultSelection() {
+ if (null != _selectionListeners) {
+ Iterator<SelectionListener> it = _selectionListeners.iterator();
+ while (it.hasNext()) {
+ SelectionListener listener = it.next();
+ listener.widgetDefaultSelected(null);
+ }
+ }
+ }
+
+ /**
+ * Get the traces in the model
+ *
+ * @return The array of traces
+ */
+ public ITimeGraphEntry[] getTraces() {
+ return _data.getTraces();
+ }
+
+ /**
+ * Get the on/off trace filters
+ *
+ * @return The array of filters
+ */
+ public boolean[] getTraceFilter() {
+ return _data.getTraceFilter();
+ }
+
+ /**
+ * Refresh the data for the thing
+ */
+ public void refreshData() {
+ _data.refreshData();
+ adjustScrolls();
+ redraw();
+ }
+
+ /**
+ * Refresh data for the given traces
+ *
+ * @param traces
+ * The traces to refresh
+ */
+ public void refreshData(ITimeGraphEntry[] traces) {
+ _data.refreshData(traces);
+ adjustScrolls();
+ redraw();
+ }
+
+ /**
+ * Adjust the scoll bars
+ */
+ public void adjustScrolls() {
+ if (null == _timeProvider) {
+ getHorizontalBar().setValues(0, 1, 1, 1, 1, 1);
+ return;
+ }
+
+ // HORIZONTAL BAR
+ // Visible window
+ long time0 = _timeProvider.getTime0();
+ long time1 = _timeProvider.getTime1();
+ // Time boundaries
+ long timeMin = _timeProvider.getMinTime();
+ long timeMax = _timeProvider.getMaxTime();
+
+ long delta = timeMax - timeMin;
+
+ int timePos = 0;
+ int thumb = H_SCROLLBAR_MAX;
+
+ if (delta != 0) {
+ // Thumb size (page size)
+ thumb = Math.max(1, (int) (H_SCROLLBAR_MAX * ((double) (time1 - time0) / delta)));
+ // At the beginning of visible window
+ timePos = (int) (H_SCROLLBAR_MAX * ((double) (time0 - timeMin) / delta));
+ }
+
+ // position, minimum, maximum, thumb size, increment (half page)t, page
+ // increment size (full page)
+ getHorizontalBar().setValues(timePos, 0, H_SCROLLBAR_MAX, thumb, Math.max(1, thumb / 2), Math.max(2, thumb));
+ }
+
+ boolean ensureVisibleItem(int idx, boolean redraw) {
+ boolean changed = false;
+ if (idx < 0) {
+ for (idx = 0; idx < _data._expandedItems.length; idx++) {
+ if (_data._expandedItems[idx]._selected) {
+ break;
+ }
+ }
+ }
+ if (idx >= _data._expandedItems.length) {
+ return changed;
+ }
+ if (idx < _topIndex) {
+ setTopIndex(idx);
+ //FIXME:getVerticalBar().setSelection(_topItem);
+ if (redraw) {
+ redraw();
+ }
+ changed = true;
+ } else {
+ int page = countPerPage();
+ if (idx >= _topIndex + page) {
+ setTopIndex(idx - page + 1);
+ //FIXME:getVerticalBar().setSelection(_topItem);
+ if (redraw) {
+ redraw();
+ }
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ /**
+ * Assign the given index as the top one
+ *
+ * @param idx
+ * The index
+ */
+ public void setTopIndex(int idx) {
+ idx = Math.min(idx, _data._expandedItems.length - countPerPage());
+ idx = Math.max(0, idx);
+ _topIndex = idx;
+ redraw();
+ }
+
+ /**
+ * Set the expanded state of a given entry
+ *
+ * @param entry
+ * The entry
+ * @param expanded
+ * True if expanded, false if collapsed
+ */
+ public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
+ Item item = _data.findItem(entry);
+ if (item != null && item._expanded != expanded) {
+ item._expanded = expanded;
+ _data.updateExpandedItems();
+ redraw();
+ }
+ }
+
+ /**
+ * Collapses all nodes of the viewer's tree, starting with the root.
+ *
+ * @since 2.0
+ */
+ public void collapseAll() {
+ for (Item item : _data._items) {
+ item._expanded = false;
+ }
+ _data.updateExpandedItems();
+ redraw();
+ }
+
+ /**
+ * Expands all nodes of the viewer's tree, starting with the root.
+ *
+ * @since 2.0
+ */
+ public void expandAll() {
+ for (Item item : _data._items) {
+ item._expanded = true;
+ }
+ _data.updateExpandedItems();
+ redraw();
+ }
+
+ /**
+ * Add a tree listener
+ *
+ * @param listener
+ * The listener to add
+ */
+ public void addTreeListener(ITimeGraphTreeListener listener) {
+ if (!_treeListeners.contains(listener)) {
+ _treeListeners.add(listener);
+ }
+ }
+
+ /**
+ * Remove a tree listener
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeTreeListener(ITimeGraphTreeListener listener) {
+ if (_treeListeners.contains(listener)) {
+ _treeListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Tree event callback
+ *
+ * @param entry
+ * The affected entry
+ * @param expanded
+ * The expanded state (true for expanded, false for collapsed)
+ */
+ public void fireTreeEvent(ITimeGraphEntry entry, boolean expanded) {
+ TimeGraphTreeExpansionEvent event = new TimeGraphTreeExpansionEvent(this, entry);
+ for (ITimeGraphTreeListener listener : _treeListeners) {
+ if (expanded) {
+ listener.treeExpanded(event);
+ } else {
+ listener.treeCollapsed(event);
+ }
+ }
+ }
+
+ @Override
+ public ISelection getSelection() {
+ TimeGraphSelection sel = new TimeGraphSelection();
+ ITimeGraphEntry trace = getSelectedTrace();
+ if (null != trace && null != _timeProvider) {
+ long selectedTime = _timeProvider.getSelectedTime();
+ ITimeEvent event = Utils.findEvent(trace, selectedTime, 0);
+ if (event != null) {
+ sel.add(event);
+ } else {
+ sel.add(trace);
+ }
+ }
+ return sel;
+ }
+
+ /**
+ * Get the selection object
+ *
+ * @return The selection
+ */
+ public ISelection getSelectionTrace() {
+ TimeGraphSelection sel = new TimeGraphSelection();
+ ITimeGraphEntry trace = getSelectedTrace();
+ if (null != trace) {
+ sel.add(trace);
+ }
+ return sel;
+ }
+
+ /**
+ * Enable/disable one of the traces in the model
+ *
+ * @param n
+ * 1 to enable it, -1 to disable. The method returns immediately
+ * if another value is used.
+ */
+ public void selectTrace(int n) {
+ if ((n != 1) && (n != -1)) {
+ return;
+ }
+
+ boolean changed = false;
+ int lastSelection = -1;
+ for (int i = 0; i < _data._expandedItems.length; i++) {
+ Item item = _data._expandedItems[i];
+ if (item._selected) {
+ lastSelection = i;
+ if ((1 == n) && (i < _data._expandedItems.length - 1)) {
+ item._selected = false;
+ item = _data._expandedItems[i + 1];
+ item._selected = true;
+ changed = true;
+ } else if ((-1 == n) && (i > 0)) {
+ item._selected = false;
+ item = _data._expandedItems[i - 1];
+ item._selected = true;
+ changed = true;
+ }
+ break;
+ }
+ }
+
+ if (lastSelection < 0 && _data._expandedItems.length > 0) {
+ Item item = _data._expandedItems[0];
+ item._selected = true;
+ changed = true;
+ }
+
+ if (changed) {
+ ensureVisibleItem(-1, false);
+ redraw();
+ fireSelectionChanged();
+ }
+ }
+
+ /**
+ * Select an event
+ *
+ * @param n
+ * 1 for next event, -1 for previous event
+ */
+ public void selectEvent(int n) {
+ if (null == _timeProvider) {
+ return;
+ }
+ ITimeGraphEntry trace = getSelectedTrace();
+ if (trace == null) {
+ return;
+ }
+ long selectedTime = _timeProvider.getSelectedTime();
+ long endTime = _timeProvider.getEndTime();
+ ITimeEvent nextEvent;
+ if (-1 == n && selectedTime > endTime) {
+ nextEvent = Utils.findEvent(trace, selectedTime, 0);
+ } else {
+ nextEvent = Utils.findEvent(trace, selectedTime, n);
+ }
+ if (null == nextEvent && -1 == n) {
+ nextEvent = Utils.getFirstEvent(trace);
+ }
+ if (null != nextEvent) {
+ long nextTime = nextEvent.getTime();
+ // If last event detected e.g. going back or not moving to a next
+ // event
+ if (nextTime <= selectedTime && n == 1) {
+ // Select to the end of this last event
+ nextTime = nextEvent.getTime() + nextEvent.getDuration();
+ // but not beyond the end of the trace
+ if (nextTime > endTime) {
+ nextTime = endTime;
+ }
+ } else if (n == -1) {
+ // for previous event go to its end time unless we were already there
+ if (nextEvent.getTime() + nextEvent.getDuration() < selectedTime) {
+ nextTime = nextEvent.getTime() + nextEvent.getDuration();
+ }
+ }
+ _timeProvider.setSelectedTimeNotify(nextTime, true);
+ fireSelectionChanged();
+ } else if (1 == n) {
+ _timeProvider.setSelectedTimeNotify(endTime, true);
+ fireSelectionChanged();
+ }
+ }
+
+ /**
+ * Select the next event
+ */
+ public void selectNextEvent() {
+ selectEvent(1);
+ // Notify if visible time window has been adjusted
+ _timeProvider.setStartFinishTimeNotify(_timeProvider.getTime0(), _timeProvider.getTime1());
+ }
+
+ /**
+ * Select the previous event
+ */
+ public void selectPrevEvent() {
+ selectEvent(-1);
+ // Notify if visible time window has been adjusted
+ _timeProvider.setStartFinishTimeNotify(_timeProvider.getTime0(), _timeProvider.getTime1());
+ }
+
+ /**
+ * Select the next trace
+ */
+ public void selectNextTrace() {
+ selectTrace(1);
+ }
+
+ /**
+ * Select the previous trace
+ */
+ public void selectPrevTrace() {
+ selectTrace(-1);
+ }
+
+ /**
+ * Zoom based on mouse cursor location with mouse scrolling
+ *
+ * @param zoomIn true to zoom in, false to zoom out
+ */
+ public void zoom(boolean zoomIn) {
+ int globalX = getDisplay().getCursorLocation().x;
+ Point p = toControl(globalX, 0);
+ int nameSpace = _timeProvider.getNameSpace();
+ int timeSpace = _timeProvider.getTimeSpace();
+ int xPos = Math.max(nameSpace, Math.min(nameSpace + timeSpace, p.x));
+ long time0 = _timeProvider.getTime0();
+ long time1 = _timeProvider.getTime1();
+ long interval = time1 - time0;
+ if (interval == 0) {
+ interval = 1;
+ } // to allow getting out of single point interval
+ long newInterval;
+ if (zoomIn) {
+ newInterval = Math.max(Math.round(interval * 0.8), _timeProvider.getMinTimeInterval());
+ } else {
+ newInterval = (long) Math.ceil(interval * 1.25);
+ }
+ long center = time0 + Math.round(((double) (xPos - nameSpace) / timeSpace * interval));
+ long newTime0 = center - Math.round((double) newInterval * (center - time0) / interval);
+ long newTime1 = newTime0 + newInterval;
+ _timeProvider.setStartFinishTime(newTime0, newTime1);
+ synchronized (fMouseScrollNotifierLock) {
+ if (fMouseScrollNotifier == null) {
+ fMouseScrollNotifier = new MouseScrollNotifier();
+ fMouseScrollNotifier.start();
+ }
+ fMouseScrollNotifier.mouseScrolled();
+ }
+ }
+
+ /**
+ * zoom in using single click
+ */
+ public void zoomIn() {
+ long _time0 = _timeProvider.getTime0();
+ long _time1 = _timeProvider.getTime1();
+ long _range = _time1 - _time0;
+ long selTime = _timeProvider.getSelectedTime();
+ if (selTime <= _time0 || selTime >= _time1) {
+ selTime = (_time0 + _time1) / 2;
+ }
+ long time0 = selTime - (long) ((selTime - _time0) / zoomCoeff);
+ long time1 = selTime + (long) ((_time1 - selTime) / zoomCoeff);
+
+ long inaccuracy = (_timeProvider.getMaxTime() - _timeProvider.getMinTime()) - (time1 - time0);
+
+ // Trace.debug("selTime:" + selTime + " time0:" + time0 + " time1:"
+ // + time1 + " inaccuracy:" + inaccuracy);
+
+ if (inaccuracy > 0 && inaccuracy < 100) {
+ _timeProvider.setStartFinishTimeNotify(_timeProvider.getMinTime(), _timeProvider.getMaxTime());
+ return;
+ }
+
+ long m = _timeProvider.getMinTimeInterval();
+ if ((time1 - time0) < m) {
+ time0 = selTime - (selTime - _time0) * m / _range;
+ time1 = time0 + m;
+ }
+
+ _timeProvider.setStartFinishTimeNotify(time0, time1);
+ }
+
+ /**
+ * zoom out using single click
+ */
+ public void zoomOut() {
+ long _time0 = _timeProvider.getTime0();
+ long _time1 = _timeProvider.getTime1();
+ long selTime = _timeProvider.getSelectedTime();
+ if (selTime <= _time0 || selTime >= _time1) {
+ selTime = (_time0 + _time1) / 2;
+ }
+ long time0 = (long) (selTime - (selTime - _time0) * zoomCoeff);
+ long time1 = (long) (selTime + (_time1 - selTime) * zoomCoeff);
+
+ long inaccuracy = (_timeProvider.getMaxTime() - _timeProvider.getMinTime()) - (time1 - time0);
+ if (inaccuracy > 0 && inaccuracy < 100) {
+ _timeProvider.setStartFinishTimeNotify(_timeProvider.getMinTime(), _timeProvider.getMaxTime());
+ return;
+ }
+
+ _timeProvider.setStartFinishTimeNotify(time0, time1);
+ }
+
+ /**
+ * Return the currently selected trace
+ *
+ * @return The entry matching the trace
+ */
+ public ITimeGraphEntry getSelectedTrace() {
+ ITimeGraphEntry trace = null;
+ int idx = getSelectedIndex();
+ if (idx >= 0) {
+ trace = _data._expandedItems[idx]._trace;
+ }
+ return trace;
+ }
+
+ /**
+ * Retrieve the index of the currently selected item
+ *
+ * @return The index
+ */
+ public int getSelectedIndex() {
+ int idx = -1;
+ for (int i = 0; i < _data._expandedItems.length; i++) {
+ Item item = _data._expandedItems[i];
+ if (item._selected) {
+ idx = i;
+ break;
+ }
+ }
+ return idx;
+ }
+
+ boolean toggle(int idx) {
+ boolean toggled = false;
+ if (idx >= 0 && idx < _data._expandedItems.length) {
+ Item item = _data._expandedItems[idx];
+ if (item._hasChildren) {
+ item._expanded = !item._expanded;
+ _data.updateExpandedItems();
+ adjustScrolls();
+ redraw();
+ toggled = true;
+ fireTreeEvent(item._trace, item._expanded);
+ }
+ }
+ return toggled;
+ }
+
+ int getItemIndexAtY(int y) {
+ if (y < 0) {
+ return -1;
+ }
+ if (_itemHeight == CUSTOM_ITEM_HEIGHT) {
+ int ySum = 0;
+ for (int idx = _topIndex; idx < _data._expandedItems.length; idx++) {
+ ySum += _data._expandedItems[idx].itemHeight;
+ if (y < ySum) {
+ return idx;
+ }
+ }
+ return -1;
+ }
+ int idx = y / _itemHeight;
+ idx += _topIndex;
+ if (idx < _data._expandedItems.length) {
+ return idx;
+ }
+ return -1;
+ }
+
+ boolean isOverSplitLine(int x) {
+ if (x < 0 || null == _timeProvider) {
+ return false;
+ }
+ int w = 4;
+ int nameWidth = _timeProvider.getNameSpace();
+ if (x > nameWidth - w && x < nameWidth + w) {
+ return true;
+ }
+ return false;
+ }
+
+ ITimeGraphEntry getEntry(Point pt) {
+ int idx = getItemIndexAtY(pt.y);
+ return idx >= 0 ? _data._expandedItems[idx]._trace : null;
+ }
+
+ long getTimeAtX(int x) {
+ if (null == _timeProvider) {
+ return -1;
+ }
+ long hitTime = -1;
+ Point size = getCtrlSize();
+ long time0 = _timeProvider.getTime0();
+ long time1 = _timeProvider.getTime1();
+ int nameWidth = _timeProvider.getNameSpace();
+ x -= nameWidth;
+ int timeWidth = size.x - nameWidth - RIGHT_MARGIN;
+ if (x >= 0 && size.x >= nameWidth) {
+ if (time1 - time0 > timeWidth) {
+ // nanosecond smaller than one pixel: use the first integer nanosecond of this pixel's time range
+ hitTime = time0 + (long) Math.ceil((time1 - time0) * ((double) x / timeWidth));
+ } else {
+ // nanosecond greater than one pixel: use the nanosecond that covers this pixel start position
+ hitTime = time0 + (long) Math.floor((time1 - time0) * ((double) x / timeWidth));
+ }
+ }
+ return hitTime;
+ }
+
+ void selectItem(int idx, boolean addSelection) {
+ boolean changed = false;
+ if (addSelection) {
+ if (idx >= 0 && idx < _data._expandedItems.length) {
+ Item item = _data._expandedItems[idx];
+ changed = (item._selected == false);
+ item._selected = true;
+ }
+ } else {
+ for (int i = 0; i < _data._expandedItems.length; i++) {
+ Item item = _data._expandedItems[i];
+ if ((i == idx && !item._selected) || (idx == -1 && item._selected)) {
+ changed = true;
+ }
+ item._selected = i == idx;
+ }
+ }
+ changed |= ensureVisibleItem(idx, true);
+ if (changed) {
+ redraw();
+ }
+ }
+
+ /**
+ * Callback for item selection
+ *
+ * @param trace
+ * The entry matching the trace
+ * @param addSelection
+ * If the selection is added or removed
+ */
+ public void selectItem(ITimeGraphEntry trace, boolean addSelection) {
+ int idx = _data.findItemIndex(trace);
+ selectItem(idx, addSelection);
+ }
+
+ /**
+ * Retrieve the number of entries shown per page.
+ *
+ * @return The count
+ */
+ public int countPerPage() {
+ int height = getCtrlSize().y;
+ int count = 0;
+ if (_itemHeight == CUSTOM_ITEM_HEIGHT) {
+ int ySum = 0;
+ for (int idx = _topIndex; idx < _data._expandedItems.length; idx++) {
+ ySum += _data._expandedItems[idx].itemHeight;
+ if (ySum >= height) {
+ return count;
+ }
+ count++;
+ }
+ for (int idx = _topIndex - 1; idx >= 0; idx--) {
+ ySum += _data._expandedItems[idx].itemHeight;
+ if (ySum >= height) {
+ return count;
+ }
+ count++;
+ }
+ return count;
+ }
+ if (height > 0) {
+ count = height / _itemHeight;
+ }
+ return count;
+ }
+
+ /**
+ * Get the index of the top element
+ *
+ * @return The index
+ */
+ public int getTopIndex() {
+ return _topIndex;
+ }
+
+ /**
+ * Get the number of expanded items
+ *
+ * @return The count of expanded items
+ */
+ public int getExpandedElementCount() {
+ return _data._expandedItems.length;
+ }
+
+ /**
+ * Get an array of all expanded elements
+ *
+ * @return The expanded elements
+ */
+ public ITimeGraphEntry[] getExpandedElements() {
+ ArrayList<ITimeGraphEntry> elements = new ArrayList<ITimeGraphEntry>();
+ for (Item item : _data._expandedItems) {
+ elements.add(item._trace);
+ }
+ return elements.toArray(new ITimeGraphEntry[0]);
+ }
+
+ Point getCtrlSize() {
+ Point size = getSize();
+ if (getHorizontalBar().isVisible()) {
+ size.y -= getHorizontalBar().getSize().y;
+ }
+ return size;
+ }
+
+ Rectangle getNameRect(Rectangle bound, int idx, int nameWidth) {
+ int x = bound.x;
+ int y = bound.y + (idx - _topIndex) * _itemHeight;
+ int width = nameWidth;
+ int height = _itemHeight;
+ if (_itemHeight == CUSTOM_ITEM_HEIGHT) {
+ int ySum = 0;
+ for (int i = _topIndex; i < idx; i++) {
+ ySum += _data._expandedItems[i].itemHeight;
+ }
+ y = bound.y + ySum;
+ height = _data._expandedItems[idx].itemHeight;
+ }
+ return new Rectangle(x, y, width, height);
+ }
+
+ Rectangle getStatesRect(Rectangle bound, int idx, int nameWidth) {
+ int x = bound.x + nameWidth;
+ int y = bound.y + (idx - _topIndex) * _itemHeight;
+ int width = bound.width - x;
+ int height = _itemHeight;
+ if (_itemHeight == CUSTOM_ITEM_HEIGHT) {
+ int ySum = 0;
+ for (int i = _topIndex; i < idx; i++) {
+ ySum += _data._expandedItems[i].itemHeight;
+ }
+ y = bound.y + ySum;
+ height = _data._expandedItems[idx].itemHeight;
+ }
+ return new Rectangle(x, y, width, height);
+ }
+
+ @Override
+ void paint(Rectangle bounds, PaintEvent e) {
+ GC gc = e.gc;
+ gc.setBackground(_colors.getColor(TimeGraphColorScheme.BACKGROUND));
+ drawBackground(gc, bounds.x, bounds.y, bounds.width, bounds.height);
+
+ if (bounds.width < 2 || bounds.height < 2 || null == _timeProvider) {
+ return;
+ }
+
+ _idealNameSpace = 0;
+ int nameSpace = _timeProvider.getNameSpace();
+
+ // draw empty name space background
+ gc.setBackground(_colors.getBkColor(false, false, true));
+ drawBackground(gc, bounds.x, bounds.y, nameSpace, bounds.height);
+
+ drawItems(bounds, _timeProvider, _data._expandedItems, _topIndex, nameSpace, gc);
+
+ // draw selected time
+ long time0 = _timeProvider.getTime0();
+ long time1 = _timeProvider.getTime1();
+ long selectedTime = _timeProvider.getSelectedTime();
+ double pixelsPerNanoSec = (bounds.width - nameSpace <= RIGHT_MARGIN) ? 0 : (double) (bounds.width - nameSpace - RIGHT_MARGIN) / (time1 - time0);
+ int x = bounds.x + nameSpace + (int) ((selectedTime - time0) * pixelsPerNanoSec);
+ if (x >= nameSpace && x < bounds.x + bounds.width) {
+ gc.setForeground(_colors.getColor(TimeGraphColorScheme.SELECTED_TIME));
+ gc.drawLine(x, bounds.y, x, bounds.y + bounds.height);
+ }
+
+ // draw drag line, no line if name space is 0.
+ if (DRAG_SPLIT_LINE == _dragState) {
+ gc.setForeground(_colors.getColor(TimeGraphColorScheme.BLACK));
+ gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);
+ } else if (DRAG_NONE == _dragState && _mouseOverSplitLine && _timeProvider.getNameSpace() > 0) {
+ gc.setForeground(_colors.getColor(TimeGraphColorScheme.RED));
+ gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);
+ }
+ }
+
+ /**
+ * Draw many items at once
+ *
+ * @param bounds
+ * The rectangle of the area
+ * @param timeProvider
+ * The time provider
+ * @param items
+ * The array items to draw
+ * @param topIndex
+ * The index of the first element to draw
+ * @param nameSpace
+ * The width reserved for the names
+ * @param gc
+ * Reference to the SWT GC object
+ */
+ public void drawItems(Rectangle bounds, ITimeDataProvider timeProvider,
+ Item[] items, int topIndex, int nameSpace, GC gc) {
+ for (int i = topIndex; i < items.length; i++) {
+ Item item = items[i];
+ drawItem(item, bounds, timeProvider, i, nameSpace, gc);
+ }
+ fTimeGraphProvider.postDrawControl(bounds, gc);
+ }
+
+ /**
+ * Draws the item
+ *
+ * @param item the item to draw
+ * @param bounds the container rectangle
+ * @param i the item index
+ * @param nameSpace the name space
+ * @param gc
+ */
+ protected void drawItem(Item item, Rectangle bounds, ITimeDataProvider timeProvider, int i, int nameSpace, GC gc) {
+ ITimeGraphEntry entry = item._trace;
+ long time0 = timeProvider.getTime0();
+ long time1 = timeProvider.getTime1();
+ long selectedTime = timeProvider.getSelectedTime();
+
+ Rectangle nameRect = getNameRect(bounds, i, nameSpace);
+ if (nameRect.y >= bounds.y + bounds.height) {
+ return;
+ }
+
+ if (! item._trace.hasTimeEvents()) {
+ Rectangle statesRect = getStatesRect(bounds, i, nameSpace);
+ nameRect.width += statesRect.width;
+ drawName(item, nameRect, gc);
+ } else {
+ drawName(item, nameRect, gc);
+ }
+ Rectangle rect = getStatesRect(bounds, i, nameSpace);
+ if (rect.isEmpty()) {
+ fTimeGraphProvider.postDrawEntry(entry, rect, gc);
+ return;
+ }
+ if (time1 <= time0) {
+ gc.setBackground(_colors.getBkColor(false, false, false));
+ gc.fillRectangle(rect);
+ fTimeGraphProvider.postDrawEntry(entry, rect, gc);
+ return;
+ }
+
+ // Initialize _rect1 to same values as enclosing rectangle rect
+ Rectangle stateRect = Utils.clone(rect);
+ boolean selected = item._selected;
+ // K pixels per second
+ double pixelsPerNanoSec = (rect.width <= RIGHT_MARGIN) ? 0 : (double) (rect.width - RIGHT_MARGIN) / (time1 - time0);
+
+ if (item._trace.hasTimeEvents()) {
+ fillSpace(rect, gc, selected);
+ // Drawing rectangle is smaller than reserved space
+ stateRect.y += 3;
+ stateRect.height -= 6;
+
+ long maxDuration = (timeProvider.getTimeSpace() == 0) ? Long.MAX_VALUE : 1 * (time1 - time0) / timeProvider.getTimeSpace();
+ Iterator<ITimeEvent> iterator = entry.getTimeEventsIterator(time0, time1, maxDuration);
+
+ int lastX = -1;
+ while (iterator.hasNext()) {
+ ITimeEvent event = iterator.next();
+ int x = rect.x + (int) ((event.getTime() - time0) * pixelsPerNanoSec);
+ int xEnd = rect.x + (int) ((event.getTime() + event.getDuration() - time0) * pixelsPerNanoSec);
+ if (x >= rect.x + rect.width || xEnd < rect.x) {
+ // event is out of bounds
+ continue;
+ }
+ xEnd = Math.min(rect.x + rect.width, xEnd);
+ stateRect.x = Math.max(rect.x, x);
+ stateRect.width = Math.max(0, xEnd - stateRect.x + 1);
+ if (stateRect.x == lastX) {
+ stateRect.width -= 1;
+ if (stateRect.width > 0) {
+ gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
+ gc.drawPoint(stateRect.x, stateRect.y - 2);
+ stateRect.x += 1;
+ }
+ } else {
+ lastX = x;
+ }
+ boolean timeSelected = selectedTime >= event.getTime() && selectedTime < event.getTime() + event.getDuration();
+ drawState(_colors, event, stateRect, gc, selected, timeSelected);
+ }
+ }
+ fTimeGraphProvider.postDrawEntry(entry, rect, gc);
+ }
+
+ protected void drawName(Item item, Rectangle bounds, GC gc) {
+ boolean hasTimeEvents = item._trace.hasTimeEvents();
+ if (! hasTimeEvents) {
+ gc.setBackground(_colors.getBkColorGroup(item._selected, _isInFocus));
+ gc.fillRectangle(bounds);
+ if (item._selected && _isInFocus) {
+ gc.setForeground(_colors.getBkColor(item._selected, _isInFocus, false));
+ gc.drawRectangle(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);
+ }
+ } else {
+ gc.setBackground(_colors.getBkColor(item._selected, _isInFocus, true));
+ gc.setForeground(_colors.getFgColor(item._selected, _isInFocus));
+ gc.fillRectangle(bounds);
+ }
+
+ // No name to be drawn
+ if (_timeProvider.getNameSpace() == 0) {
+ return;
+ }
+
+ int leftMargin = MARGIN + item.level * EXPAND_SIZE;
+ if (item._hasChildren) {
+ gc.setForeground(_colors.getFgColorGroup(false, false));
+ gc.setBackground(_colors.getBkColor(false, false, false));
+ Rectangle rect = Utils.clone(bounds);
+ rect.x += leftMargin;
+ rect.y += (bounds.height - EXPAND_SIZE) / 2;
+ rect.width = EXPAND_SIZE;
+ rect.height = EXPAND_SIZE;
+ gc.fillRectangle(rect);
+ gc.drawRectangle(rect.x, rect.y, rect.width - 1, rect.height - 1);
+ int midy = rect.y + rect.height / 2;
+ gc.drawLine(rect.x + 2, midy, rect.x + rect.width - 3, midy);
+ if (!item._expanded) {
+ int midx = rect.x + rect.width / 2;
+ gc.drawLine(midx, rect.y + 2, midx, rect.y + rect.height - 3);
+ }
+ }
+ leftMargin += EXPAND_SIZE + MARGIN;
+
+ Image img = fTimeGraphProvider.getItemImage(item._trace);
+ if (img != null) {
+ // draw icon
+ int imgHeight = img.getImageData().height;
+ int imgWidth = img.getImageData().width;
+ int x = leftMargin;
+ int y = bounds.y + (bounds.height - imgHeight) / 2;
+ gc.drawImage(img, x, y);
+ leftMargin += imgWidth + MARGIN;
+ }
+ String name = item._name;
+ Point size = gc.stringExtent(name);
+ if (_idealNameSpace < leftMargin + size.x + MARGIN) {
+ _idealNameSpace = leftMargin + size.x + MARGIN;
+ }
+ if (hasTimeEvents) {
+ // cut long string with "..."
+ int width = bounds.width - leftMargin;
+ int cuts = 0;
+ while (size.x > width && name.length() > 1) {
+ cuts++;
+ name = name.substring(0, name.length() - 1);
+ size = gc.stringExtent(name + "..."); //$NON-NLS-1$
+ }
+ if (cuts > 0) {
+ name += "..."; //$NON-NLS-1$
+ }
+ }
+ Rectangle rect = Utils.clone(bounds);
+ rect.x += leftMargin;
+ rect.width -= leftMargin;
+ // draw text
+ if (rect.width > 0) {
+ rect.y += (bounds.height - gc.stringExtent(name).y) / 2;
+ gc.setForeground(_colors.getFgColor(item._selected, _isInFocus));
+ int textWidth = Utils.drawText(gc, name, rect, true);
+ leftMargin += textWidth + MARGIN;
+ rect.y -= 2;
+
+ if (hasTimeEvents) {
+ // draw middle line
+ int x = bounds.x + leftMargin;
+ int width = bounds.width - x;
+ int midy = bounds.y + bounds.height / 2;
+ gc.setForeground(_colors.getColor(TimeGraphColorScheme.MID_LINE));
+ gc.drawLine(x, midy, x + width, midy);
+ }
+ }
+ }
+
+ protected void drawState(TimeGraphColorScheme colors, ITimeEvent event,
+ Rectangle rect, GC gc, boolean selected, boolean timeSelected) {
+
+ int colorIdx = fTimeGraphProvider.getStateTableIndex(event);
+ if (colorIdx < 0) {
+ return;
+ }
+ boolean visible = rect.width == 0 ? false : true;
+
+ if (visible) {
+ Color stateColor = null;
+ if (colorIdx < fEventColorMap.length) {
+ stateColor = fEventColorMap[colorIdx];
+ } else {
+ stateColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ }
+
+ timeSelected = timeSelected && selected;
+ if (timeSelected) {
+ // modify the color?
+ }
+ // fill all rect area
+ gc.setBackground(stateColor);
+ gc.fillRectangle(rect);
+ // get the border color?
+ gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
+
+ // draw bounds
+ if (!timeSelected) {
+ // Draw the top and bottom borders i.e. no side borders
+ // top
+ gc.drawLine(rect.x, rect.y, rect.x + rect.width - 1, rect.y);
+ // bottom
+ gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1);
+ }
+ } else {
+ gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
+ gc.drawPoint(rect.x, rect.y - 2);
+ /*
+ // selected rectangle area is not visible but can be represented
+ // with a broken vertical line of specified width.
+ int width = 1;
+ rect.width = width;
+ gc.setForeground(stateColor);
+ int s = gc.getLineStyle();
+ int w = gc.getLineWidth();
+ gc.setLineStyle(SWT.LINE_DOT);
+ gc.setLineWidth(width);
+ // Trace.debug("Rectangle not visible, drawing vertical line with: "
+ // + rect.x + "," + rect.y + "," + rect.x + "," + rect.y
+ // + rect.height);
+ gc.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height - 1);
+ gc.setLineStyle(s);
+ gc.setLineWidth(w);
+ if (!timeSelected) {
+ gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
+ gc.drawPoint(rect.x, rect.y);
+ gc.drawPoint(rect.x, rect.y + rect.height - 1);
+ }
+ */
+ }
+ fTimeGraphProvider.postDrawEvent(event, rect, gc);
+ }
+
+ protected void fillSpace(Rectangle rect, GC gc, boolean selected) {
+ gc.setBackground(_colors.getBkColor(selected, _isInFocus, false));
+ gc.fillRectangle(rect);
+ // draw middle line
+ gc.setForeground(_colors.getColor(TimeGraphColorScheme.MID_LINE));
+ int midy = rect.y + rect.height / 2;
+ gc.drawLine(rect.x, midy, rect.x + rect.width, midy);
+ }
+
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS)) {
+ e.doit = true;
+ }
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ int idx = -1;
+ if (_data._expandedItems.length == 0) {
+ return;
+ }
+ if (SWT.HOME == e.keyCode) {
+ idx = 0;
+ } else if (SWT.END == e.keyCode) {
+ idx = _data._expandedItems.length - 1;
+ } else if (SWT.ARROW_DOWN == e.keyCode) {
+ idx = getSelectedIndex();
+ if (idx < 0) {
+ idx = 0;
+ } else if (idx < _data._expandedItems.length - 1) {
+ idx++;
+ }
+ } else if (SWT.ARROW_UP == e.keyCode) {
+ idx = getSelectedIndex();
+ if (idx < 0) {
+ idx = 0;
+ } else if (idx > 0) {
+ idx--;
+ }
+ } else if (SWT.ARROW_LEFT == e.keyCode) {
+ selectPrevEvent();
+ } else if (SWT.ARROW_RIGHT == e.keyCode) {
+ selectNextEvent();
+ } else if (SWT.PAGE_DOWN == e.keyCode) {
+ int page = countPerPage();
+ idx = getSelectedIndex();
+ if (idx < 0) {
+ idx = 0;
+ }
+ idx += page;
+ if (idx >= _data._expandedItems.length) {
+ idx = _data._expandedItems.length - 1;
+ }
+ } else if (SWT.PAGE_UP == e.keyCode) {
+ int page = countPerPage();
+ idx = getSelectedIndex();
+ if (idx < 0) {
+ idx = 0;
+ }
+ idx -= page;
+ if (idx < 0) {
+ idx = 0;
+ }
+ } else if (SWT.CR == e.keyCode) {
+ idx = getSelectedIndex();
+ if (idx >= 0) {
+ if (_data._expandedItems[idx]._hasChildren) {
+ toggle(idx);
+ } else {
+ fireDefaultSelection();
+ }
+ }
+ idx = -1;
+ }
+ if (idx >= 0) {
+ selectItem(idx, false);
+ fireSelectionChanged();
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ _isInFocus = true;
+ if (mouseScrollFilterListener == null) {
+ mouseScrollFilterListener = new Listener() {
+ // This filter is used to prevent horizontal scrolling of the view
+ // when the mouse wheel is used to zoom
+ @Override
+ public void handleEvent(Event event) {
+ event.doit = false;
+ }
+ };
+ getDisplay().addFilter(SWT.MouseWheel, mouseScrollFilterListener);
+ }
+ redraw();
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ _isInFocus = false;
+ if (mouseScrollFilterListener != null) {
+ getDisplay().removeFilter(SWT.MouseWheel, mouseScrollFilterListener);
+ mouseScrollFilterListener = null;
+ }
+ if (DRAG_NONE != _dragState) {
+ setCapture(false);
+ _dragState = DRAG_NONE;
+ }
+ redraw();
+ }
+
+ /**
+ * @return If the current view is focused
+ */
+ public boolean isInFocus() {
+ return _isInFocus;
+ }
+
+ /**
+ * Provide the possibility to control the wait cursor externally e.g. data
+ * requests in progress
+ *
+ * @param waitInd Should we wait indefinitely?
+ */
+ public void waitCursor(boolean waitInd) {
+ // Update cursor as indicated
+ if (waitInd) {
+ setCursor(_WaitCursor);
+ _isWaitCursor = true;
+ } else {
+ setCursor(null);
+ _isWaitCursor = false;
+ }
+
+ // Get ready for next mouse move
+ _isDragCursor3 = false;
+ }
+
+ /**
+ * <p>
+ * If the x, y position is over the vertical split line (name to time
+ * ranges), then change the cursor to a drag cursor to indicate the user the
+ * possibility of resizing
+ * </p>
+ *
+ * @param x
+ * @param y
+ */
+ void updateCursor(int x, int y) {
+ // if Wait cursor not active, check for the need to change to a drag
+ // cursor
+ if (_isWaitCursor == false) {
+ boolean isSplitLine = isOverSplitLine(x);
+ // No dragcursor is name space is fixed to zero
+ if (isSplitLine && !_isDragCursor3 && _timeProvider.getNameSpace() > 0) {
+ setCursor(_dragCursor3);
+ _isDragCursor3 = true;
+ } else if (!isSplitLine && _isDragCursor3) {
+ setCursor(null);
+ _isDragCursor3 = false;
+ }
+ }
+ }
+
+ @Override
+ public void mouseMove(MouseEvent e) {
+ if (null == _timeProvider) {
+ return;
+ }
+ Point size = getCtrlSize();
+ if (DRAG_TRACE_ITEM == _dragState) {
+ int nameWidth = _timeProvider.getNameSpace();
+ int x = e.x - nameWidth;
+ if (x > 0 && size.x > nameWidth && _dragX != x) {
+ _dragX = x;
+ double pixelsPerNanoSec = (size.x - nameWidth <= RIGHT_MARGIN) ? 0 : (double) (size.x - nameWidth - RIGHT_MARGIN) / (_time1bak - _time0bak);
+ long timeDelta = (long) ((pixelsPerNanoSec == 0) ? 0 : ((_dragX - _dragX0) / pixelsPerNanoSec));
+ long time1 = _time1bak - timeDelta;
+ long maxTime = _timeProvider.getMaxTime();
+ if (time1 > maxTime) {
+ time1 = maxTime;
+ }
+ long time0 = time1 - (_time1bak - _time0bak);
+ if (time0 < _timeProvider.getMinTime()) {
+ time0 = _timeProvider.getMinTime();
+ time1 = time0 + (_time1bak - _time0bak);
+ }
+ _timeProvider.setStartFinishTime(time0, time1);
+ }
+ } else if (DRAG_SPLIT_LINE == _dragState) {
+ _dragX = e.x;
+ _timeProvider.setNameSpace(e.x);
+ } else if (DRAG_NONE == _dragState) {
+ boolean mouseOverSplitLine = isOverSplitLine(e.x);
+ if (_mouseOverSplitLine != mouseOverSplitLine) {
+ redraw();
+ }
+ _mouseOverSplitLine = mouseOverSplitLine;
+ }
+ updateCursor(e.x, e.y);
+ }
+
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ if (null == _timeProvider) {
+ return;
+ }
+ if (1 == e.button) {
+ if (isOverSplitLine(e.x) && _timeProvider.getNameSpace() != 0) {
+ _timeProvider.setNameSpace(_idealNameSpace);
+ boolean mouseOverSplitLine = isOverSplitLine(e.x);
+ if (_mouseOverSplitLine != mouseOverSplitLine) {
+ redraw();
+ }
+ _mouseOverSplitLine = mouseOverSplitLine;
+ return;
+ }
+ int idx = getItemIndexAtY(e.y);
+ if (idx >= 0) {
+ selectItem(idx, false);
+ fireDefaultSelection();
+ }
+ }
+ }
+
+ @Override
+ public void mouseDown(MouseEvent e) {
+ if (null == _timeProvider) {
+ return;
+ }
+ int idx;
+ if (1 == e.button) {
+ int nameSpace = _timeProvider.getNameSpace();
+ if (nameSpace != 0) {
+ if (isOverSplitLine(e.x)) {
+ _dragState = DRAG_SPLIT_LINE;
+ _dragX = _dragX0 = e.x;
+ _time0bak = _timeProvider.getTime0();
+ _time1bak = _timeProvider.getTime1();
+ redraw();
+ return;
+ }
+ }
+
+ idx = getItemIndexAtY(e.y);
+ if (idx >= 0) {
+ Item item = _data._expandedItems[idx];
+ if (item._hasChildren && e.x < nameSpace && e.x < MARGIN + (item.level + 1) * EXPAND_SIZE) {
+ toggle(idx);
+ } else {
+ long hitTime = getTimeAtX(e.x);
+ if (hitTime >= 0) {
+ // _timeProvider.setSelectedTimeInt(hitTime, false);
+ setCapture(true);
+ _dragState = DRAG_TRACE_ITEM;
+ _dragX = _dragX0 = e.x - nameSpace;
+ _time0bak = _timeProvider.getTime0();
+ _time1bak = _timeProvider.getTime1();
+ }
+ }
+ selectItem(idx, false);
+ fireSelectionChanged();
+ } else {
+ selectItem(idx, false); // clear selection
+ redraw();
+ fireSelectionChanged();
+ }
+ }
+ }
+
+ @Override
+ public void mouseUp(MouseEvent e) {
+ if (DRAG_NONE != _dragState) {
+ setCapture(false);
+ if (DRAG_TRACE_ITEM == _dragState) {
+ // Notify time provider to check the need for listener
+ // notification
+ _timeProvider.notifyStartFinishTime();
+ if (_dragX == _dragX0) { // click without drag
+ long time = getTimeAtX(e.x);
+ _timeProvider.setSelectedTimeNotify(time, false);
+ }
+ } else if (DRAG_SPLIT_LINE == _dragState) {
+ redraw();
+ }
+ _dragState = DRAG_NONE;
+ }
+ }
+
+ @Override
+ public void mouseEnter(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseExit(MouseEvent e) {
+ if (_mouseOverSplitLine) {
+ _mouseOverSplitLine = false;
+ redraw();
+ }
+ }
+
+ @Override
+ public void mouseHover(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseScrolled(MouseEvent e) {
+ if ((mouseScrollFilterListener == null) || _dragState != DRAG_NONE) {
+ return;
+ }
+ boolean zoomScroll = false;
+ Point p = getParent().toControl(getDisplay().getCursorLocation());
+ Point parentSize = getParent().getSize();
+ if (p.x >= 0 && p.x < parentSize.x && p.y >= 0 && p.y < parentSize.y) {
+ // over the parent control
+ if (e.x > getCtrlSize().x) {
+ // over the horizontal scroll bar
+ zoomScroll = false;
+ } else if (e.y >= 0 && e.y < getCtrlSize().y && e.x < _timeProvider.getNameSpace()) {
+ // over the name space
+ zoomScroll = false;
+ } else {
+ zoomScroll = true;
+ }
+ }
+ if (zoomScroll && _timeProvider.getTime0() != _timeProvider.getTime1()) {
+ if (e.count > 0) {
+ zoom(true);
+ } else if (e.count < 0) {
+ zoom(false);
+ }
+ } else {
+ setTopIndex(getTopIndex() - e.count);
+ }
+ }
+
+ @Override
+ public void controlMoved(ControlEvent e) {
+ }
+
+ @Override
+ public void controlResized(ControlEvent e) {
+ adjustScrolls();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (e.widget == getVerticalBar()) {
+ setTopIndex(getVerticalBar().getSelection());
+ } else if (e.widget == getHorizontalBar() && null != _timeProvider) {
+ int start = getHorizontalBar().getSelection();
+ long time0 = _timeProvider.getTime0();
+ long time1 = _timeProvider.getTime1();
+ long timeMin = _timeProvider.getMinTime();
+ long timeMax = _timeProvider.getMaxTime();
+ long delta = timeMax - timeMin;
+
+ long range = time1 - time0;
+ // _timeRangeFixed = true;
+ time0 = timeMin + Math.round(delta * ((double) start / H_SCROLLBAR_MAX));
+ time1 = time0 + range;
+
+ // TODO: Follow-up with Bug 310310
+ // In Linux SWT.DRAG is the only value received
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=310310
+ if (e.detail == SWT.DRAG) {
+ _timeProvider.setStartFinishTime(time0, time1);
+ } else {
+ _timeProvider.setStartFinishTimeNotify(time0, time1);
+ }
+ }
+ }
+
+ /**
+ * @return The current visibility of the vertical scroll bar
+ */
+ public boolean isVisibleVerticalScroll() {
+ return _visibleVerticalScroll;
+ }
+
+ @Override
+ public int getBorderWidth() {
+ return _borderWidth;
+ }
+
+ /**
+ * Set the border width
+ *
+ * @param borderWidth
+ * The width
+ */
+ public void setBorderWidth(int borderWidth) {
+ this._borderWidth = borderWidth;
+ }
+
+ /**
+ * @return The current height of the header row
+ */
+ public int getHeaderHeight() {
+ return _headerHeight;
+ }
+
+ /**
+ * Set the height of the header row
+ *
+ * @param headerHeight
+ * The height
+ */
+ public void setHeaderHeight(int headerHeight) {
+ this._headerHeight = headerHeight;
+ }
+
+ /**
+ * @return The height of regular item rows
+ */
+ public int getItemHeight() {
+ return _itemHeight;
+ }
+
+ /**
+ * Set the height of regular itew rows
+ *
+ * @param rowHeight
+ * The height
+ */
+ public void setItemHeight(int rowHeight) {
+ this._itemHeight = rowHeight;
+ }
+
+ /**
+ * Set the minimum item width
+ *
+ * @param width The minimum width
+ */
+ public void setMinimumItemWidth(int width) {
+ this._minimumItemWidth = width;
+ }
+
+ /**
+ * @return The minimum item width
+ */
+ public int getMinimumItemWidth() {
+ return _minimumItemWidth;
+ }
+
+ /**
+ * @return The entries that are currently filtered out
+ */
+ public Vector<ITimeGraphEntry> getFilteredOut() {
+ return _data.getFilteredOut();
+ }
+
+ // @Override
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ if (listener != null) {
+ if (!_selectionChangedListeners.contains(listener)) {
+ _selectionChangedListeners.add(listener);
+ }
+ }
+ }
+
+ // @Override
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ if (listener != null) {
+ _selectionChangedListeners.remove(listener);
+ }
+ }
+
+ // @Override
+ @Override
+ public void setSelection(ISelection selection) {
+ if (selection instanceof TimeGraphSelection) {
+ TimeGraphSelection sel = (TimeGraphSelection) selection;
+ Object ob = sel.getFirstElement();
+ if (ob instanceof ITimeGraphEntry) {
+ ITimeGraphEntry trace = (ITimeGraphEntry) ob;
+ selectItem(trace, false);
+ }
+ }
+
+ }
+
+ private class ItemData {
+ public Item[] _expandedItems = new Item[0];
+ public Item[] _items = new Item[0];
+ private ITimeGraphEntry _traces[] = new ITimeGraphEntry[0];
+ private boolean traceFilter[] = new boolean[0];
+ private final Vector<ITimeGraphEntry> filteredOut = new Vector<ITimeGraphEntry>();
+ public ITimeGraphPresentationProvider provider;
+
+ public ItemData() {
+ }
+
+ Item findItem(ITimeGraphEntry entry) {
+ if (entry == null) {
+ return null;
+ }
+
+ for (int i = 0; i < _items.length; i++) {
+ Item item = _items[i];
+ if (item._trace == entry) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ int findItemIndex(ITimeGraphEntry trace) {
+ if (trace == null) {
+ return -1;
+ }
+
+ for (int i = 0; i < _expandedItems.length; i++) {
+ Item item = _expandedItems[i];
+ if (item._trace == trace) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ public void refreshData() {
+ List<Item> itemList = new ArrayList<Item>();
+ filteredOut.clear();
+ for (int i = 0; i < _traces.length; i++) {
+ ITimeGraphEntry entry = _traces[i];
+ refreshData(itemList, null, 0, entry);
+ }
+ _items = itemList.toArray(new Item[0]);
+ updateExpandedItems();
+ }
+
+ private void refreshData(List<Item> itemList, Item parent, int level, ITimeGraphEntry entry) {
+ Item item = new Item(entry, entry.getName(), level);
+ if (parent != null) {
+ parent.children.add(item);
+ }
+ item.itemHeight = provider.getItemHeight(entry);
+ itemList.add(item);
+ if (entry.hasChildren()) {
+ item._expanded = true;
+ item._hasChildren = true;
+ for (ITimeGraphEntry child : entry.getChildren()) {
+ refreshData(itemList, item, level + 1, child);
+ }
+ }
+ }
+
+ public void updateExpandedItems() {
+ List<Item> expandedItemList = new ArrayList<Item>();
+ for (int i = 0; i < _traces.length; i++) {
+ ITimeGraphEntry entry = _traces[i];
+ Item item = findItem(entry);
+ refreshExpanded(expandedItemList, item);
+ }
+ _expandedItems = expandedItemList.toArray(new Item[0]);
+ }
+
+ private void refreshExpanded(List<Item> expandedItemList, Item item) {
+ expandedItemList.add(item);
+ if (item._hasChildren && item._expanded) {
+ for (Item child : item.children) {
+ refreshExpanded(expandedItemList, child);
+ }
+ }
+ }
+
+ public void refreshData(ITimeGraphEntry traces[]) {
+ if (traces == null || traces.length == 0) {
+ traceFilter = null;
+ } else if (traceFilter == null || traces.length != traceFilter.length) {
+ traceFilter = new boolean[traces.length];
+ java.util.Arrays.fill(traceFilter, true);
+ }
+
+ _traces = traces;
+ refreshData();
+ }
+
+ public ITimeGraphEntry[] getTraces() {
+ return _traces;
+ }
+
+ public boolean[] getTraceFilter() {
+ return traceFilter;
+ }
+
+ public Vector<ITimeGraphEntry> getFilteredOut() {
+ return filteredOut;
+ }
+ }
+
+ private class Item {
+ public boolean _expanded;
+ public boolean _selected;
+ public boolean _hasChildren;
+ public int itemHeight;
+ public int level;
+ public List<Item> children;
+ public String _name;
+ public ITimeGraphEntry _trace;
+
+ public Item(ITimeGraphEntry trace, String name, int level) {
+ this._trace = trace;
+ this._name = name;
+ this.level = level;
+ this.children = new ArrayList<Item>();
+ }
+
+ @Override
+ public String toString() {
+ return _name;
+ }
+ }
+
+}
+