/******************************************************************************* * Copyright (c) 2012-2015 INRIA. * 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: * Generoso Pagano - initial API and implementation ******************************************************************************/ package fr.inria.soctrace.framesoc.ui.gantt.view; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MenuAdapter; import org.eclipse.swt.events.MenuEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; 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.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.ui.IActionBars; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphContentProvider; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider2; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphRangeListener; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphSelectionListener; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTimeListener; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.TimeGraphCombo; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.TimeGraphSelectionEvent; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTimeEvent; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.TimeGraphViewer; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.dialogs.TimeGraphFilterDialog; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.model.ILinkEvent; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.model.TimeGraphEntry; import fr.inria.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat; import fr.inria.soctrace.framesoc.ui.model.TimeInterval; import fr.inria.soctrace.framesoc.ui.model.TraceIntervalDescriptor; import fr.inria.soctrace.framesoc.ui.perspective.FramesocPart; import fr.inria.soctrace.framesoc.ui.providers.EventTypeTreeLabelProvider; import fr.inria.soctrace.framesoc.ui.providers.TreeContentProvider; import fr.inria.soctrace.framesoc.ui.utils.TimeBar; import fr.inria.soctrace.lib.model.utils.ModelConstants.TimeUnit; /** * An abstract view all time graph views can inherit * * This view contains a time graph combo which is divided between a tree viewer on the left and a * time graph viewer on the right. * */ public abstract class AbstractGanttView extends FramesocPart { private static final Logger logger = LoggerFactory.getLogger(AbstractGanttView.class); /** * Redraw state enum */ private enum State { IDLE, BUSY, PENDING } /** Suffix text for link percentage label */ private final static String LINK_PERCENTAGE = "Percentage of displayed links: "; // ------------------------------------------------------------------------ // Fields // ------------------------------------------------------------------------ /** The timegraph wrapper */ private ITimeGraphWrapper fTimeGraphWrapper; /** The timegraph entry list */ protected List<TimeGraphEntry> fEntryList; /** The start time */ private long fStartTime; /** The end time */ private long fEndTime; /** * Flag indicating if the user changed the selection (via the timebar or the viewer) */ private boolean fUserChangedTimeRange = false; /** Flag indicating if the user changed the time range (zooming or panning) */ private boolean fUserChangedSelection = false; /** Flag stating if we were dragging */ private boolean fDragging = false; /** The min time */ private long fMinTime; /** The max time */ private long fMaxTime; /** The display width */ private final int fDisplayWidth; /** The zoom thread */ private ZoomThread fZoomThread; /** The next resource action */ private Action fNextResourceAction; /** The previous resource action */ private Action fPreviousResourceAction; /** A comparator class */ private Comparator<ITimeGraphEntry> fEntryComparator = null; /** * The redraw state used to prevent unnecessary queuing of display runnables */ private State fRedrawState = State.IDLE; /** The redraw synchronization object */ private final Object fSyncObj = new Object(); /** The presentation provider for this view */ private final TimeGraphPresentationProvider fPresentation; /** The tree column label array, or null if combo is not used */ private String[] fColumns; /** The tree label provider, or null if combo is not used */ private TimeGraphTreeLabelProvider fLabelProvider = null; /** The relative weight of the sash, ignored if combo is not used */ private int[] fWeight = { 1, 4 }; /** The filter column label array, or null if filter is not used */ private String[] fFilterColumns; /** The filter label provider, or null if filter is not used */ private TimeGraphTreeLabelProvider fFilterLabelProvider; /** The pack done flag */ private boolean fPackDone = false; /** The time management bar */ private TimeBar fTimeBar; /** Label displaying arrow percentage */ private Label arrowPercentageLabel; /** Type filter dialog */ private TimeGraphFilterDialog fTypeFilterDialog; // ------------------------------------------------------------------------ // Classes // ------------------------------------------------------------------------ private interface ITimeGraphWrapper { void setTimeGraphProvider(TimeGraphPresentationProvider fPresentation); TimeGraphViewer getTimeGraphViewer(); void addSelectionListener(ITimeGraphSelectionListener iTimeGraphSelectionListener); ISelectionProvider getSelectionProvider(); void setFocus(); boolean isDisposed(); void refresh(); void setInput(Object input); Object getInput(); void redraw(); void update(); } private class TimeGraphComboWrapper implements ITimeGraphWrapper { private TimeGraphCombo combo; private TimeGraphComboWrapper(Composite parent, int style) { combo = new TimeGraphCombo(parent, style, fWeight); } @Override public void setTimeGraphProvider(TimeGraphPresentationProvider timeGraphProvider) { combo.setTimeGraphProvider(timeGraphProvider); } @Override public TimeGraphViewer getTimeGraphViewer() { return combo.getTimeGraphViewer(); } @Override public void addSelectionListener(ITimeGraphSelectionListener listener) { combo.addSelectionListener(listener); } @Override public ISelectionProvider getSelectionProvider() { return combo.getTreeViewer(); } @Override public void setFocus() { combo.setFocus(); } @Override public boolean isDisposed() { return combo.isDisposed(); } @Override public void setInput(Object input) { combo.setInput(input); } @Override public Object getInput() { return combo.getInput(); } @Override public void refresh() { combo.refresh(); } @Override public void redraw() { combo.redraw(); } @Override public void update() { combo.update(); } TimeGraphCombo getTimeGraphCombo() { return combo; } TreeViewer getTreeViewer() { return combo.getTreeViewer(); } } private class TimeGraphTreeContentProvider implements ITreeContentProvider { @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public ITimeGraphEntry[] getElements(Object inputElement) { if (inputElement != null) { try { return ((List<?>) inputElement).toArray(new ITimeGraphEntry[0]); } catch (ClassCastException e) { } } return new ITimeGraphEntry[0]; } @Override public Object[] getChildren(Object parentElement) { ITimeGraphEntry entry = (ITimeGraphEntry) parentElement; List<? extends ITimeGraphEntry> children = entry.getChildren(); return children.toArray(new ITimeGraphEntry[children.size()]); } @Override public Object getParent(Object element) { ITimeGraphEntry entry = (ITimeGraphEntry) element; return entry.getParent(); } @Override public boolean hasChildren(Object element) { ITimeGraphEntry entry = (ITimeGraphEntry) element; return entry.hasChildren(); } } private class TimeGraphContentProvider implements ITimeGraphContentProvider { @Override public ITimeGraphEntry[] getElements(Object inputElement) { if (inputElement != null) { try { return ((List<?>) inputElement).toArray(new ITimeGraphEntry[0]); } catch (ClassCastException e) { } } return new ITimeGraphEntry[0]; } } /** * Base class to provide the labels for the tree viewer. Views extending this class typically * need to override the getColumnText method if they have more than one column to display */ protected static class TimeGraphTreeLabelProvider implements ITableLabelProvider, ILabelProvider { @Override public void addListener(ILabelProviderListener listener) { } @Override public void dispose() { } @Override public boolean isLabelProperty(Object element, String property) { return false; } @Override public void removeListener(ILabelProviderListener listener) { } @Override public Image getColumnImage(Object element, int columnIndex) { return null; } @Override public String getColumnText(Object element, int columnIndex) { TimeGraphEntry entry = (TimeGraphEntry) element; if (entry != null && columnIndex == 0) { return entry.getName(); } return new String(); } @Override public Image getImage(Object element) { return null; } @Override public String getText(Object element) { TimeGraphEntry entry = (TimeGraphEntry) element; return entry.getName(); } } private class ZoomThread extends Thread { private final long fZoomStartTime; private final long fZoomEndTime; private final long fResolution; private final IProgressMonitor fMonitor; public ZoomThread(List<TimeGraphEntry> entryList, long startTime, long endTime) { super("Zoom Thread"); //$NON-NLS-1$ fZoomStartTime = startTime; fZoomEndTime = endTime; fResolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth); fMonitor = new NullProgressMonitor(); } @Override public void run() { logger.debug("Zoom thread run"); /* Refresh the arrows when zooming */ List<ILinkEvent> events = getLinkList(fZoomStartTime, fZoomEndTime, fResolution, fMonitor); if (events != null) { fTimeGraphWrapper.getTimeGraphViewer().setLinks(events); redraw(); } } public void cancel() { fMonitor.setCanceled(true); } } // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ /** * Constructs a time graph view that contains a time graph combo. * * The subclass constructor must call {@link #setTreeColumns(String[])} and * {@link #setTreeLabelProvider(TimeGraphTreeLabelProvider)}. * * @param id * The id of the view * @param pres * The presentation provider */ public AbstractGanttView(String id, TimeGraphPresentationProvider pres) { fPresentation = pres; fDisplayWidth = Display.getDefault().getBounds().width; } // ------------------------------------------------------------------------ // Getters and setters // ------------------------------------------------------------------------ /** * Getter for the time graph combo * * @return The time graph combo, or null if combo is not used */ protected TimeGraphCombo getTimeGraphCombo() { if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) { return ((TimeGraphComboWrapper) fTimeGraphWrapper).getTimeGraphCombo(); } return null; } /** * Getter for the time graph viewer * * @return The time graph viewer */ protected TimeGraphViewer getTimeGraphViewer() { return fTimeGraphWrapper.getTimeGraphViewer(); } /** * Getter for the presentation provider * * @return The time graph presentation provider * @since 3.0 */ protected ITimeGraphPresentationProvider2 getPresentationProvider() { return fPresentation; } /** * Sets the tree column labels. This should be called from the constructor. * * @param columns * The array of tree column labels */ protected void setTreeColumns(final String[] columns) { fColumns = columns; } /** * Sets the tree label provider. This should be called from the constructor. * * @param tlp * The tree label provider */ protected void setTreeLabelProvider(final TimeGraphTreeLabelProvider tlp) { fLabelProvider = tlp; } /** * Sets the relative weight of each part of the time graph combo. This should be called from the * constructor. * * @param weights * The array (length 2) of relative weights of each part of the combo */ protected void setWeight(final int[] weights) { fWeight = weights; } /** * Sets the filter column labels. This should be called from the constructor. * * @param filterColumns * The array of filter column labels */ protected void setFilterColumns(final String[] filterColumns) { fFilterColumns = filterColumns; } /** * Sets the filter label provider. This should be called from the constructor. * * @param labelProvider * The filter label provider * * @since 3.0 */ protected void setFilterLabelProvider(final TimeGraphTreeLabelProvider labelProvider) { fFilterLabelProvider = labelProvider; } /** * Gets the display width * * @return the display width */ protected int getDisplayWidth() { return fDisplayWidth; } /** * Gets the comparator for the entries * * @return The entry comparator */ protected Comparator<ITimeGraphEntry> getEntryComparator() { return fEntryComparator; } /** * Sets the comparator class for the entries * * @param comparator * A comparator object */ protected void setEntryComparator(final Comparator<ITimeGraphEntry> comparator) { fEntryComparator = comparator; } /** * Gets the start time * * @return The start time */ protected long getStartTime() { return fStartTime; } /** * Sets the start time * * @param time * The start time */ protected void setMinTime(long time) { fMinTime = time; } /** * Sets the start time * * @param time * The start time */ protected void setMaxTime(long time) { fMaxTime = time; } /** * Sets the start time * * @param time * The start time */ protected void setStartTime(long time) { fStartTime = time; } /** * Gets the end time * * @return The end time */ protected long getEndTime() { return fEndTime; } /** * Sets the end time * * @param time * The end time */ protected void setEndTime(long time) { fEndTime = time; } /** * Gets the entry list for a trace * * @param trace * the trace * * @return the entry list map * @since 3.0 */ protected List<TimeGraphEntry> getEntryList() { return fEntryList; } /** * Adds a list of entries to the entry list * * @param list * the list of time graph entries to add */ protected void addToEntryList(List<TimeGraphEntry> list) { if (fEntryList == null) { fEntryList = new CopyOnWriteArrayList<>(list); } else { fEntryList.addAll(list); } } /** * Removes a list of entries from a trace's entry list * * @param trace * the trace * @param list * the list of time graph entries to remove * @since 3.0 */ protected void removeFromEntryList(List<TimeGraphEntry> list) { if (fEntryList != null) { fEntryList.removeAll(list); } } /** * Text for the "next" button * * @return The "next" button text */ protected String getNextText() { return "Next"; } /** * Tooltip for the "next" button * * @return Tooltip for the "next" button */ protected String getNextTooltip() { return "Next"; } /** * Text for the "Previous" button * * @return The "Previous" button text */ protected String getPrevText() { return "Previous"; } /** * Tooltip for the "previous" button * * @return Tooltip for the "previous" button */ protected String getPrevTooltip() { return "Previous"; } public boolean isfUserChangedTimeRange() { return fUserChangedTimeRange; } public void setfUserChangedTimeRange(boolean fUserChangedTimeRange) { this.fUserChangedTimeRange = fUserChangedTimeRange; } // ------------------------------------------------------------------------ // ViewPart // ------------------------------------------------------------------------ @Override public void createFramesocPartControl(Composite parent) { GridLayout layout = new GridLayout(1, false); parent.setLayout(layout); layout.horizontalSpacing = 0; layout.verticalSpacing = 2; layout.marginHeight = 0; layout.marginWidth = 0; arrowPercentageLabel = new Label(parent, SWT.NONE); setArrowPercentage(0.0); // ------------------------------- // TYPE FILTER DIALOG // ------------------------------- fTypeFilterDialog = new TimeGraphFilterDialog(parent.getShell()); fTypeFilterDialog.setColumnNames(new String[] { "Event Type" }); fTypeFilterDialog.setContentProvider(new TreeContentProvider()); fTypeFilterDialog.setLabelProvider(new EventTypeTreeLabelProvider()); // ------------------------------- // COMBO VIEWER // ------------------------------- Composite comboComposite = new Composite(parent, SWT.BORDER); comboComposite.setLayout(new FillLayout()); comboComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); TimeGraphComboWrapper wrapper = new TimeGraphComboWrapper(comboComposite, SWT.NONE); fTimeGraphWrapper = wrapper; final TimeGraphCombo combo = wrapper.getTimeGraphCombo(); // Event Producer Tree combo.setTreeContentProvider(new TimeGraphTreeContentProvider()); combo.setTreeLabelProvider(fLabelProvider); combo.setTreeColumns(fColumns); // Event Producer Context Menu final Tree tree = combo.getTreeViewer().getTree(); final Menu menu = new Menu(tree); tree.setMenu(menu); menu.addMenuListener(new MenuAdapter() { @Override public void menuShown(MenuEvent e) { MenuItem[] items = menu.getItems(); for (int i = 0; i < items.length; i++) { items[i].dispose(); } IStructuredSelection selection = (IStructuredSelection) combo.getTreeViewer() .getSelection(); final ITimeGraphEntry node = (ITimeGraphEntry) selection.getFirstElement(); // expand/collapse if (node.hasChildren()) { MenuItem exp = new MenuItem(menu, SWT.NONE); final boolean expanded = combo.getTreeViewer().getExpandedState(node); exp.setText(expanded ? "Collapse" : "Expand All"); exp.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (expanded) combo.setExpandedState(node, false); else expandFromNode(node); } private void expandFromNode(ITimeGraphEntry node) { combo.setExpandedState(node, true); for (ITimeGraphEntry entry : node.getChildren()) { expandFromNode(entry); } } }); // restore Set<ITimeGraphEntry> filteredSet = getFiltered(); List<ITimeGraphEntry> filteredChildren = new ArrayList<>(); getFilteredChildren(filteredChildren, filteredSet, node); if (filteredChildren.size() > 0) { for (ITimeGraphEntry entry : filteredChildren) { filteredSet.remove(entry); } final List<Object> newFiltered = new ArrayList<>(); for (ITimeGraphEntry entry : filteredSet) { newFiltered.add(entry); } MenuItem restore = new MenuItem(menu, SWT.NONE); restore.setText("Restore hidden children"); restore.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { combo.setFilteredEntries(newFiltered); combo.refresh(); } }); } } // hide MenuItem hide = new MenuItem(menu, SWT.NONE); hide.setText("Hide"); hide.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { IStructuredSelection selection = (IStructuredSelection) combo .getTreeViewer().getSelection(); ITimeGraphEntry node = (ITimeGraphEntry) selection.getFirstElement(); combo.addFiltered(node); combo.refresh(); } }); } private void getFilteredChildren(List<ITimeGraphEntry> filteredChildren, Set<ITimeGraphEntry> filteredSet, ITimeGraphEntry entry) { for (ITimeGraphEntry e : entry.getChildren()) { if (filteredSet.contains(e)) { filteredChildren.add(e); } getFilteredChildren(filteredChildren, filteredSet, e); } } private Set<ITimeGraphEntry> getFiltered() { List<Object> filtered = combo.getFilteredEntries(); Set<ITimeGraphEntry> filteredSet = new HashSet<>(); for (Object e : filtered) { filteredSet.add(((ITimeGraphEntry) e)); } return filteredSet; } }); // Event Producer Filter combo.setFilterContentProvider(new TimeGraphTreeContentProvider()); combo.setFilterLabelProvider(fFilterLabelProvider); combo.setFilterColumns(fFilterColumns); // Gantt Chart combo.setTimeGraphContentProvider(new TimeGraphContentProvider()); getTimeGraphViewer().setTimeGraphProvider(fPresentation); getTimeGraphViewer().getTimeGraphControl().addDragSelectionListener( new ITimeGraphTimeListener() { public void timeSelected(TimeGraphTimeEvent event) { if (fTimeBar != null) { fTimeBar.setSelection(event.getBeginTime(), event.getEndTime()); fUserChangedSelection = true; fDragging = true; } } }); fTimeGraphWrapper.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() { @Override public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) { // visible start and end time changed by the user // (range updated after zoom or pan) fUserChangedTimeRange = true; final long startTime = event.getStartTime(); final long endTime = event.getEndTime(); if (fZoomThread != null) { fZoomThread.cancel(); } startZoomThread(startTime, endTime); } }); fTimeGraphWrapper.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() { @Override public void timeSelected(TimeGraphTimeEvent event) { logger.debug("timeSelected"); if (!fDragging && fTimeBar != null) { // resynch timebar fTimeBar.setSelection(fStartTime, fEndTime); // clean user selection change fUserChangedSelection = false; } fDragging = false; } }); fTimeGraphWrapper.addSelectionListener(new ITimeGraphSelectionListener() { @Override public void selectionChanged(TimeGraphSelectionEvent event) { logger.debug("selectionChanged"); } }); fTimeGraphWrapper.getTimeGraphViewer().setTimeFormat(TimeFormat.NUMBER); IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager(); fTimeGraphWrapper.getTimeGraphViewer().getTimeGraphControl() .setStatusLineManager(statusLineManager); // ------------------------------- // TIME MANAGEMENT BAR // ------------------------------- Composite timeComposite = new Composite(parent, SWT.BORDER); timeComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); GridLayout gl_timeComposite = new GridLayout(1, false); gl_timeComposite.horizontalSpacing = 0; timeComposite.setLayout(gl_timeComposite); layout.horizontalSpacing = 0; layout.verticalSpacing = 2; layout.marginHeight = 0; layout.marginWidth = 0; // time manager fTimeBar = new TimeBar(timeComposite, SWT.NONE, true, true); fTimeBar.setEnabled(false); fTimeBar.setStatusLineManager(statusLineManager); fTimeBar.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (combo != null && fTimeBar != null) { combo.getTimeGraphViewer().setSelectionRange(fTimeBar.getStartTimestamp(), fTimeBar.getEndTimestamp()); fUserChangedSelection = true; } } }); // button to synch the timebar with the gantt fTimeBar.getSynchButton().addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (combo != null && fTimeBar != null) { // clean selection combo.getTimeGraphViewer().setSelectionRange(0, 0); // re-synch timebar fTimeBar.setSelection(fStartTime, fEndTime); // clean user selection change fUserChangedSelection = false; } } }); // draw button fTimeBar.getLoadButton().addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { // reset selection fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(0, 0); // load new interval TraceIntervalDescriptor des = new TraceIntervalDescriptor(); des.setTrace(currentShownTrace); des.setTimeInterval(fTimeBar.getSelection()); showTrace(currentShownTrace, des); } }); createContextMenu(); // ------------------------------- // TOOL BAR // ------------------------------- // View Action Handling makeActions(); contributeToActionBars(); enableActions(false); } @Override public void setFocus() { super.setFocus(); fTimeGraphWrapper.setFocus(); } // ------------------------------------------------------------------------ // Internal // ------------------------------------------------------------------------ /** * Draw the percentage of shown arrows * * @param percentage * percentage of shown arrows */ protected void setArrowPercentage(double percentage) { DecimalFormat decim = new DecimalFormat("##.#"); DecimalFormatSymbols custom = new DecimalFormatSymbols(); custom.setDecimalSeparator('.'); decim.setDecimalFormatSymbols(custom); Double percent = Double.parseDouble(decim.format(percentage)); StringBuilder sb = new StringBuilder(); sb.append(LINK_PERCENTAGE); sb.append(percent); sb.append("%"); arrowPercentageLabel.setText(sb.toString()); arrowPercentageLabel.pack(); } /** * Gets the list of links (displayed as arrows) for a trace in a given time range. Default * implementation returns an empty list. * * @param startTime * Start of the time range * @param endTime * End of the time range * @param resolution * The resolution * @param monitor * The progress monitor object * @return The list of link events * @since 2.1 */ protected List<ILinkEvent> getLinkList(long startTime, long endTime, long resolution, IProgressMonitor monitor) { return new ArrayList<>(); } /** * Refresh the display */ protected void refresh() { Display.getDefault().syncExec(new Runnable() { @Override public void run() { if (fTimeGraphWrapper.isDisposed()) { return; } // update colors fTimeGraphWrapper.getTimeGraphViewer().getTimeGraphControl() .colorSettingsChanged(fPresentation.getStateTable()); boolean hasEntries = false; if (fEntryList == null) { fEntryList = new CopyOnWriteArrayList<>(); } else if (fEntryComparator != null) { ArrayList<TimeGraphEntry> list = new ArrayList<>(fEntryList); sort(list); fEntryList.clear(); fEntryList.addAll(list); } hasEntries = fEntryList.size() != 0; if (fEntryList != fTimeGraphWrapper.getInput()) { fTimeGraphWrapper.setInput(fEntryList); } else { fTimeGraphWrapper.refresh(); } // set time unit if (currentShownTrace != null) { TimeUnit unit = TimeUnit.getTimeUnit(currentShownTrace.getTimeUnit()); fTimeGraphWrapper.getTimeGraphViewer().setTimeUnit(unit); fTimeBar.setTimeUnit(unit); fPresentation.setTimeUnit(unit); } // set timebar bounds (min, max) fTimeBar.setMaxTimestamp(fMaxTime); fTimeBar.setMinTimestamp(fMinTime); // set the viewer time bounds (including all the loaded events) fTimeGraphWrapper.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime); // set the viewer start and end times (the visible part) if (!fUserChangedTimeRange) { fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(fStartTime, fEndTime); } if (!fUserChangedSelection) { // reset selection in the viewer and set the bounds in the // timebar fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(0, 0); fTimeBar.setSelection(fStartTime, fEndTime); } fTimeBar.setDisplayInterval(fStartTime, fEndTime); if (fTimeGraphWrapper instanceof TimeGraphComboWrapper && !fPackDone) { for (TreeColumn column : ((TimeGraphComboWrapper) fTimeGraphWrapper) .getTreeViewer().getTree().getColumns()) { column.pack(); } if (hasEntries) { fPackDone = true; } } fTimeBar.setEnabled(true); if (!fUserChangedTimeRange) { startZoomThread(fStartTime, fEndTime); } } }); } /** * Redraw the canvas */ protected void redraw() { synchronized (fSyncObj) { if (fRedrawState == State.IDLE) { fRedrawState = State.BUSY; } else { fRedrawState = State.PENDING; return; } } Display.getDefault().asyncExec(new Runnable() { @Override public void run() { logger.debug("refreshing"); if (fTimeGraphWrapper.isDisposed()) { return; } fTimeGraphWrapper.redraw(); fTimeGraphWrapper.update(); synchronized (fSyncObj) { if (fRedrawState == State.PENDING) { fRedrawState = State.IDLE; redraw(); } else { fRedrawState = State.IDLE; } } } }); } /** * Start the zoom thread. * * @param startTime * current visible start time * @param endTime * current visible end time */ private void startZoomThread(long startTime, long endTime) { if (fZoomThread != null) { fZoomThread.cancel(); } fZoomThread = new ZoomThread(fEntryList, startTime, endTime); fZoomThread.start(); } /** * Refresh only the passed interval after a request to show a part of an already loaded window. * * @param interval * time interval to show */ protected void refresh(TimeInterval interval) { fUserChangedSelection = false; fUserChangedTimeRange = false; setStartTime(interval.startTimestamp); setEndTime(interval.endTimestamp); refresh(); } /** * Add actions to local tool bar manager * * @param manager * the tool bar manager */ protected abstract void fillLocalToolBar(IToolBarManager manager); protected IAction getPreviousResourceAction() { return fPreviousResourceAction; } protected IAction getNextResourceAction() { return fNextResourceAction; } /** * Recursively sort the entries * * @param list * list of entries */ private void sort(ArrayList<TimeGraphEntry> list) { Collections.sort(list, fEntryComparator); for (TimeGraphEntry entry : list) { if (!entry.hasChildren()) continue; ArrayList<TimeGraphEntry> sl = new ArrayList<>(entry.getChildren()); sort(sl); entry.getChildren().clear(); entry.getChildren().addAll(sl); } } private void makeActions() { fPreviousResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getPreviousItemAction(); fPreviousResourceAction.setText(getPrevText()); fPreviousResourceAction.setToolTipText(getPrevTooltip()); fNextResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getNextItemAction(); fNextResourceAction.setText(getNextText()); fNextResourceAction.setToolTipText(getNextTooltip()); } private void contributeToActionBars() { IActionBars bars = getViewSite().getActionBars(); fillLocalToolBar(bars.getToolBarManager()); } protected void resetBeforeLoad() { fUserChangedSelection = false; fUserChangedTimeRange = false; } protected TimeGraphFilterDialog getTypeFilterDialog() { return fTypeFilterDialog; } public abstract void createContextMenu(); }