/*******************************************************************************
- * Copyright (c) 2012, 2013 Ericsson, École Polytechnique de Montréal
+ * Copyright (c) 2012, 2014 Ericsson, École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jdt.annotation.Nullable;
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.action.Separator;
+import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfNanoTimestamp;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
+import org.eclipse.linuxtools.tmf.ui.TmfUiRefreshHandler;
import org.eclipse.linuxtools.tmf.ui.views.TmfView;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphContentProvider;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider2;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphSelectionListener;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphCombo;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphSelectionEvent;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphViewer;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ILinkEvent;
/** The trace to entry list hash map */
private final Map<ITmfTrace, List<TimeGraphEntry>> fEntryListMap = new HashMap<>();
- /* The trace to build thread hash map */
+ /** The trace to build thread hash map */
private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<>();
/** The start time */
/** A comparator class */
private Comparator<ITimeGraphEntry> fEntryComparator = null;
- /** The redraw state used to prevent unnecessary queuing of display runnables */
+ /** The redraw state used to prevent unnecessary queuing of display runnables */
private State fRedrawState = State.IDLE;
/** The redraw synchronization object */
/** The filter column label array, or null if filter is not used */
private String[] fFilterColumns;
+ /** The pack done flag */
+ private boolean fPackDone = false;
+
/** The filter label provider, or null if filter is not used */
private TreeLabelProvider fFilterLabelProvider;
void refresh();
- void setInput(ITimeGraphEntry[] entries);
+ void setInput(Object input);
+
+ Object getInput();
void redraw();
}
@Override
- public void setInput(ITimeGraphEntry[] input) {
+ public void setInput(Object input) {
viewer.setInput(input);
}
+ @Override
+ public Object getInput() {
+ return viewer.getInput();
+ }
+
@Override
public void refresh() {
viewer.refresh();
}
@Override
- public void setInput(ITimeGraphEntry[] input) {
+ public void setInput(Object input) {
combo.setInput(input);
}
+ @Override
+ public Object getInput() {
+ return combo.getInput();
+ }
+
@Override
public void refresh() {
combo.refresh();
}
@Override
- public Object[] getElements(Object inputElement) {
- return (ITimeGraphEntry[]) inputElement;
+ public ITimeGraphEntry[] getElements(Object inputElement) {
+ if (inputElement != null) {
+ try {
+ return ((List<?>) inputElement).toArray(new ITimeGraphEntry[0]);
+ } catch (ClassCastException e) {
+ }
+ }
+ return new ITimeGraphEntry[0];
}
@Override
}
+ 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 TreeLabelProvider implements ITableLabelProvider {
+ protected static class TreeLabelProvider implements ITableLabelProvider, ILabelProvider {
@Override
public void addListener(ILabelProviderListener listener) {
return new String();
}
+ /**
+ * @since 3.2
+ */
+ @Override
+ public Image getImage(Object element) {
+ return null;
+ }
+
+ /**
+ * @since 3.2
+ */
+ @Override
+ public String getText(Object element) {
+ TimeGraphEntry entry = (TimeGraphEntry) element;
+ return entry.getName();
+ }
+
}
private class BuildThread extends Thread {
private final ITmfTrace fBuildTrace;
+ private final ITmfTrace fParentTrace;
private final IProgressMonitor fMonitor;
- public BuildThread(final ITmfTrace trace, final String name) {
+ public BuildThread(final ITmfTrace trace, final ITmfTrace parentTrace, final String name) {
super(name + " build"); //$NON-NLS-1$
fBuildTrace = trace;
+ fParentTrace = parentTrace;
fMonitor = new NullProgressMonitor();
}
@Override
public void run() {
- buildEventList(fBuildTrace, fMonitor);
+ buildEventList(fBuildTrace, fParentTrace, fMonitor);
synchronized (fBuildThreadMap) {
- fBuildThreadMap.remove(this);
+ fBuildThreadMap.remove(fBuildTrace);
}
}
}
}
redraw();
- for (TimeGraphEntry child : entry.getChildren()) {
+ for (ITimeGraphEntry child : entry.getChildren()) {
if (fMonitor.isCanceled()) {
return;
}
- zoom(child, monitor);
+ if (child instanceof TimeGraphEntry) {
+ zoom((TimeGraphEntry) child, monitor);
+ }
}
}
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.
}
/**
- * Gets the entry list map
+ * Gets the entry list for a trace
+ *
+ * @param trace
+ * the trace
*
* @return the entry list map
+ * @since 3.0
*/
- protected Map<ITmfTrace, List<TimeGraphEntry>> getEntryListMap() {
- return Collections.unmodifiableMap(fEntryListMap);
+ protected List<TimeGraphEntry> getEntryList(ITmfTrace trace) {
+ synchronized (fEntryListMap) {
+ return fEntryListMap.get(trace);
+ }
}
/**
- * Adds an entry to the entry list
+ * Adds a trace entry list to the entry list map
*
* @param trace
* the trace to add
* @param list
- * The list of time graph entries
+ * the list of time graph entries
*/
protected void putEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
- synchronized(fEntryListMap) {
- fEntryListMap.put(trace, list);
+ synchronized (fEntryListMap) {
+ fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
+ }
+ }
+
+ /**
+ * Adds a list of entries to a trace's entry list
+ *
+ * @param trace
+ * the trace
+ * @param list
+ * the list of time graph entries to add
+ * @since 3.0
+ */
+ protected void addToEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
+ synchronized (fEntryListMap) {
+ List<TimeGraphEntry> entryList = fEntryListMap.get(trace);
+ if (entryList == null) {
+ fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
+ } else {
+ entryList.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(ITmfTrace trace, List<TimeGraphEntry> list) {
+ synchronized (fEntryListMap) {
+ List<TimeGraphEntry> entryList = fEntryListMap.get(trace);
+ if (entryList != null) {
+ entryList.removeAll(list);
+ }
}
}
public void createPartControl(Composite parent) {
if (fColumns == null || fLabelProvider == null) {
fTimeGraphWrapper = new TimeGraphViewerWrapper(parent, SWT.NONE);
+ TimeGraphViewer viewer = fTimeGraphWrapper.getTimeGraphViewer();
+ viewer.setTimeGraphContentProvider(new TimeGraphContentProvider());
} else {
TimeGraphComboWrapper wrapper = new TimeGraphComboWrapper(parent, SWT.NONE);
fTimeGraphWrapper = wrapper;
combo.setFilterContentProvider(new TreeContentProvider());
combo.setFilterLabelProvider(fFilterLabelProvider);
combo.setFilterColumns(fFilterColumns);
+ combo.setTimeGraphContentProvider(new TimeGraphContentProvider());
}
fTimeGraphWrapper.setTimeGraphProvider(fPresentation);
}
});
- fTimeGraphWrapper.addSelectionListener(new ITimeGraphSelectionListener() {
- @Override
- public void selectionChanged(TimeGraphSelectionEvent event) {
- // ITimeGraphEntry selection = event.getSelection();
- }
- });
-
fTimeGraphWrapper.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
@TmfSignalHandler
public void traceClosed(final TmfTraceClosedSignal signal) {
synchronized (fBuildThreadMap) {
- BuildThread buildThread = fBuildThreadMap.remove(signal.getTrace());
- if (buildThread != null) {
- buildThread.cancel();
+ for (ITmfTrace trace : getTracesToBuild(signal.getTrace())) {
+ BuildThread buildThread = fBuildThreadMap.remove(trace);
+ if (buildThread != null) {
+ buildThread.cancel();
+ }
}
}
synchronized (fEntryListMap) {
synchronized (fEntryListMap) {
fEntryList = fEntryListMap.get(fTrace);
if (fEntryList == null) {
- synchronized (fBuildThreadMap) {
- BuildThread buildThread = new BuildThread(fTrace, getName());
- fBuildThreadMap.put(fTrace, buildThread);
- buildThread.start();
- }
+ rebuild();
} else {
fStartTime = fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
fEndTime = fTrace.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
}
}
+ /**
+ * Forces a rebuild of the entries list, even if entries already exist for this trace
+ * @since 3.0
+ */
+ protected void rebuild() {
+ setStartTime(Long.MAX_VALUE);
+ setEndTime(Long.MIN_VALUE);
+ synchronized (fBuildThreadMap) {
+ for (ITmfTrace trace : getTracesToBuild(fTrace)) {
+ BuildThread buildThread = new BuildThread(trace, fTrace, getName());
+ fBuildThreadMap.put(trace, buildThread);
+ buildThread.start();
+ }
+ }
+ }
+
/**
* Method called when synching to a given timestamp. Inheriting classes can
* perform actions here to update the view at the given timestamp.
}
+ /**
+ * Return the list of traces whose data or analysis results will be used to
+ * populate the view. By default, if the trace is an experiment, the traces
+ * under it will be returned, otherwise, the trace itself is returned.
+ *
+ * A build thread will be started for each trace returned by this method,
+ * some of which may receive events in live streaming mode.
+ *
+ * @param trace
+ * The trace associated with this view
+ * @return List of traces with data to display
+ * @since 3.0
+ */
+ protected Iterable<ITmfTrace> getTracesToBuild(ITmfTrace trace) {
+ return Arrays.asList(TmfTraceManager.getTraceSet(trace));
+ }
+
/**
* Build the entries list to show in this time graph
*
*
* @param trace
* The trace being built
+ * @param parentTrace
+ * The parent of the trace set, or the trace itself
* @param monitor
* The progress monitor object
+ * @since 3.0
*/
- protected abstract void buildEventList(final ITmfTrace trace, IProgressMonitor monitor);
+ protected abstract void buildEventList(ITmfTrace trace, ITmfTrace parentTrace, IProgressMonitor monitor);
/**
* Gets the list of event for an entry in a given timerange
* The progress monitor object
* @return The list of events for the entry
*/
- protected abstract List<ITimeEvent> getEventList(TimeGraphEntry entry,
+ protected abstract @Nullable List<ITimeEvent> getEventList(TimeGraphEntry entry,
long startTime, long endTime, long resolution,
IProgressMonitor monitor);
* Refresh the display
*/
protected void refresh() {
- Display.getDefault().asyncExec(new Runnable() {
+ TmfUiRefreshHandler.getInstance().queueUpdate(this, new Runnable() {
@Override
public void run() {
if (fTimeGraphWrapper.isDisposed()) {
return;
}
- ITimeGraphEntry[] entries = null;
+ boolean hasEntries = false;
synchronized (fEntryListMap) {
fEntryList = fEntryListMap.get(fTrace);
if (fEntryList == null) {
- fEntryList = new ArrayList<>();
+ fEntryList = new CopyOnWriteArrayList<>();
+ } else if (fEntryComparator != null) {
+ List<TimeGraphEntry> list = new ArrayList<>(fEntryList);
+ Collections.sort(list, fEntryComparator);
+ fEntryList.clear();
+ fEntryList.addAll(list);
}
- entries = fEntryList.toArray(new ITimeGraphEntry[0]);
+ hasEntries = fEntryList.size() != 0;
}
- if (fEntryComparator != null) {
- Arrays.sort(entries, fEntryComparator);
+ if (fEntryList != fTimeGraphWrapper.getInput()) {
+ fTimeGraphWrapper.setInput(fEntryList);
+ } else {
+ fTimeGraphWrapper.refresh();
}
- fTimeGraphWrapper.setInput(entries);
fTimeGraphWrapper.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
long selectionBeginTime = fTrace == null ? 0 : fTraceManager.getSelectionBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime);
fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
- if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
+ if (fTimeGraphWrapper instanceof TimeGraphComboWrapper && !fPackDone) {
for (TreeColumn column : ((TimeGraphComboWrapper) fTimeGraphWrapper).getTreeViewer().getTree().getColumns()) {
column.pack();
}
+ if (hasEntries) {
+ fPackDone = true;
+ }
}
startZoomThread(startTime, endTime);