// ------------------------------------------------------------------------
// Fields
// ------------------------------------------------------------------------
- private final static String LEVEL_COLUMN = org.eclipse.linuxtools.tmf.ui.viewers.statistics.Messages.TmfStatisticsView_LevelColumn;
- private final static String EVENTS_COUNT_COLUMN = org.eclipse.linuxtools.tmf.ui.viewers.statistics.Messages.TmfStatisticsView_NbEventsColumn;
+ private final static String LEVEL_COLUMN = Messages.TmfStatisticsView_LevelColumn;
+ private final static String EVENTS_COUNT_COLUMN = Messages.TmfStatisticsView_NbEventsColumn;
private TmfBaseColumnDataProvider provider;
org.eclipse.linuxtools.tmf.ui.project.model,
org.eclipse.linuxtools.tmf.ui.project.wizards,
org.eclipse.linuxtools.tmf.ui.signal,
+ org.eclipse.linuxtools.tmf.ui.viewers,
org.eclipse.linuxtools.tmf.ui.viewers.events,
org.eclipse.linuxtools.tmf.ui.viewers.statistics,
org.eclipse.linuxtools.tmf.ui.viewers.statistics.model,
org.eclipse.linuxtools.tmf.ui.views.uml2sd.preferences,
org.eclipse.linuxtools.tmf.ui.views.uml2sd.util,
org.eclipse.linuxtools.tmf.ui.widgets.rawviewer,
+ org.eclipse.linuxtools.tmf.ui.widgets.tabsview,
org.eclipse.linuxtools.tmf.ui.widgets.timegraph,
org.eclipse.linuxtools.tmf.ui.widgets.timegraph.dialogs,
org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model,
import java.util.LinkedList;
import java.util.List;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
+import org.eclipse.linuxtools.internal.tmf.ui.Activator;
+import org.eclipse.linuxtools.tmf.core.TmfCommonConstants;
/**
* Utility class for accessing TMF trace type extensions from the platform's extensions registry.
return ""; //$NON-NLS-1$
}
+ /**
+ * Retrieves and instantiates an element's object based on his plug-in
+ * definition for a specific trace type.
+ *
+ * The element's object is instantiated using its 0-argument constructor.
+ *
+ * @param resource
+ * The resource where to find the information about the trace
+ * properties
+ * @param element
+ * The name of the element to find under the trace type
+ * definition
+ * @return a new Object based on his definition in plugin.xml, or null if no
+ * definition was found
+ * @since 2.0
+ */
+ public static Object getTraceTypeElement(IResource resource, String element) {
+ try {
+ if (resource != null) {
+ String traceType = resource.getPersistentProperty(TmfCommonConstants.TRACETYPE);
+ /*
+ * Search in the configuration if there is any viewer specified
+ * for this kind of trace type.
+ */
+ for (IConfigurationElement ce : TmfTraceType.getTypeElements()) {
+ if (ce.getAttribute(TmfTraceType.ID_ATTR).equals(traceType)) {
+ IConfigurationElement[] viewerCE = ce.getChildren(element);
+ if (viewerCE.length != 1) {
+ break;
+ }
+ return viewerCE[0].createExecutableExtension(TmfTraceType.CLASS_ATTR);
+ }
+ }
+ }
+ } catch (CoreException e) {
+ Activator.getDefault().logError("Error creating the element from the resource", e); //$NON-NLS-1$
+ }
+ return null;
+ }
+
/**
* Retrieves all configuration elements from the platform extension registry
* for the trace type extension.
--- /dev/null
+/*******************************************************************************
+ * 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:
+ * Mathieu Denis <mathieu.denis@polymtl.ca> - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.viewers;
+
+import org.eclipse.linuxtools.tmf.core.component.ITmfComponent;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Interface to viewers.
+ *
+ * Viewers are to be put into views which need to know how to refresh the
+ * viewer's contents.
+ *
+ * @author Mathieu Denis
+ * @version 2.0
+ * @since 2.0
+ */
+public interface ITmfViewer extends ITmfComponent {
+
+ /**
+ * Returns the primary control associated with this viewer.
+ *
+ * @return the SWT control which displays this viewer's contents
+ */
+ public Control getControl();
+
+ /**
+ * Tells the viewer to refresh its contents.
+ */
+ public void refresh();
+}
--- /dev/null
+/*******************************************************************************
+ * 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:
+ * Mathieu Denis <mathieu.denis@polymtl.ca> - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.viewers;
+
+import org.eclipse.linuxtools.tmf.core.component.TmfComponent;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Abstract class that extends {@link TmfComponent} to be specific to viewers.
+ *
+ * It allows the access to the control and the parent of a viewer.
+ *
+ * @author Mathieu Denis
+ * @version 2.0
+ * @since 2.0
+ */
+public abstract class TmfViewer extends TmfComponent implements ITmfViewer {
+
+ /**
+ * The parent composite that holds the viewer
+ */
+ protected Composite fParent;
+
+ /**
+ * Default constructor. The viewer have to be initialize through the
+ * {@link TmfViewer#init(Composite, String)} function later on.
+ */
+ public TmfViewer() {
+ super();
+ }
+
+ /**
+ * Constructor that initializes the parent of the viewer
+ *
+ * @param parent
+ * The parent composite that holds this viewer
+ *
+ * @see TmfComponent#TmfComponent(String)
+ */
+ public TmfViewer(Composite parent) {
+ this(parent, ""); //$NON-NLS-1$
+ }
+
+ /**
+ * Constructor that initializes the parent of the viewer and that sets the
+ * name of the viewer
+ *
+ * @param parent
+ * The parent composite that holds this viewer
+ * @param name
+ * The name of the viewer
+ */
+ public TmfViewer(Composite parent, String name) {
+ init(parent, name);
+ }
+
+ /**
+ * Performs initialization of the viewer. It initializes the component. Need
+ * to be called when the default constructor is used.
+ *
+ * @param parent
+ * The parent composite of the viewer
+ * @param name
+ * The name to give to this viewer
+ * @see TmfComponent#init(String)
+ */
+ public void init(Composite parent, String name) {
+ super.init(name);
+ fParent = parent;
+ }
+
+ /**
+ * @return the parent of this viewer
+ */
+ public Composite getParent() {
+ return fParent;
+ }
+}
public interface ITmfExtraEventInfo {
/**
- * Returns the trace name.
+ * Returns the name of the trace.
*
* @return the name of the trace.
*/
/*******************************************************************************
- * Copyright (c) 2011, 2012 Ericsson
+ * 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
/**
* Messages file for statistics view strings.
*
- * @version 2.0
* @author Mathieu Denis
* @since 2.0
+ * @version 2.0
*/
public class Messages extends NLS {
private static final String BUNDLE_NAME = "org.eclipse.linuxtools.tmf.ui.viewers.statistics.messages"; //$NON-NLS-1$
- /**
- * Level column name
- */
- public static String TmfStatisticsView_LevelColumn;
-
- /**
- * Level column tool tip.
- */
- public static String TmfStatisticsView_LevelColumnTip;
-
- /**
- * Number of events column name.
- */
- public static String TmfStatisticsView_NbEventsColumn;
-
- /**
- * Number of events column tool tip.
- */
- public static String TmfStatisticsView_NbEventsTip;
-
- /**
- * Partial number of events column.
- * @since 2.0
- */
- public static String TmfStatisticsView_NbEventsTimeRangeColumn;
-
- /**
- * Partial number of events column tool tip.
- * @since 2.0
- */
- public static String TmfStatisticsView_NbEventsTimeRangeTip;
-
/**
* String for unknown trace name.
*/
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 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:
+ * Mathieu Denis <mathieu.denis@polymtl.ca> - Initial implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.viewers.statistics;
+
+import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
+import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
+import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;
+import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.AbsTmfStatisticsTree;
+
+/**
+ * Class for the TMF event requests specific to the statistics view.
+ *
+ * @version 2.0
+ * @since 2.0
+ */
+public class TmfStatisticsRequest extends TmfEventRequest {
+
+ /**
+ * Reference to the statistics viewer that sent the request.
+ */
+ private final TmfStatisticsViewer fSender;
+
+ /**
+ * Reference to the statistics tree.
+ */
+ private final AbsTmfStatisticsTree fStatisticsData;
+
+ /**
+ * Tells if the request is for the whole trace or for a smaller time range.
+ */
+ private final boolean fGlobal;
+
+ /**
+ * Index of the last event retrieved.
+ */
+ private long fLastEventIndex;
+
+ /**
+ * Constructor
+ *
+ * @param sender
+ * Sender of this request
+ * @param range
+ * The target time range
+ * @param index
+ * The starting index
+ * @param global
+ * Is this for a global statistics request (true), or a partial
+ * one (false)?
+ */
+ public TmfStatisticsRequest(TmfStatisticsViewer sender, TmfTimeRange range, long index, boolean global) {
+ super(ITmfEvent.class, range, index, TmfDataRequest.ALL_DATA, sender.getPageSize(), ExecutionType.BACKGROUND);
+ fGlobal = global;
+ fSender = sender;
+ fStatisticsData = fSender.getStatisticData();
+ fLastEventIndex = index;
+ }
+
+
+ @Override
+ public void handleData(ITmfEvent data) {
+ ++fLastEventIndex;
+
+ if (data != null) {
+ final String traceName = data.getTrace().getName();
+ if (fSender.isListeningTo(traceName)) {
+ super.handleData(data);
+
+ ITmfExtraEventInfo extraInfo = new ITmfExtraEventInfo() {
+ @Override
+ public String getTraceName() {
+ if (traceName == null) {
+ return Messages.TmfStatisticsView_UnknownTraceName;
+ }
+ return traceName;
+ }
+ };
+
+ if (fGlobal) {
+ fStatisticsData.registerEvent(data, extraInfo);
+ } else {
+ fStatisticsData.registerEventInTimeRange(data, extraInfo);
+ }
+
+ if (getNbRead() % fSender.getRefreshRate() == 0) {
+ fSender.refresh();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void handleSuccess() {
+ super.handleSuccess();
+ handleFinish(true);
+ }
+
+ @Override
+ public void handleFailure() {
+ super.handleFailure();
+ handleFinish(false);
+ }
+
+ @Override
+ public void handleCancel() {
+ super.handleCancel();
+ handleFinish(false);
+ }
+
+ /**
+ * @return the index of the last event read in the experiment so far
+ */
+ protected long getLastEventIndex() {
+ return fLastEventIndex;
+ }
+
+ /**
+ * Handles the end of the request whether it is successful or not.
+ *
+ * @param isSuccessful
+ * Tells if the request has finished successfully or not and
+ * calls the right method from the sender in each case.
+ */
+ protected void handleFinish(boolean isSuccessful) {
+ if (isSuccessful) {
+ fSender.modelComplete(fGlobal);
+ } else {
+ fSender.modelIncomplete(fGlobal);
+ }
+ }
+}
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.linuxtools.tmf.core.component.TmfComponent;
+import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest;
+import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentUpdatedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;
+import org.eclipse.linuxtools.tmf.ui.viewers.TmfViewer;
import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.AbsTmfStatisticsTree;
import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.ITmfColumnDataProvider;
import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfBaseColumnData;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
-import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
* @version 2.0
* @since 2.0
*/
-public class TmfStatisticsViewer extends TmfComponent {
+public class TmfStatisticsViewer extends TmfViewer {
/**
- * Refresh frequency
+ * The initial window span (in nanoseconds)
*/
- protected static final Long STATS_INPUT_CHANGED_REFRESH = 5000L;
+ public static final long INITIAL_WINDOW_SPAN = (1L * 100 * 1000 * 1000); // .1sec
+
+ /**
+ * Timestamp scale (nanosecond)
+ */
+ public static final byte TIME_SCALE = -9;
+
+ /**
+ * Default PAGE_SIZE for background requests.
+ */
+ protected static final int PAGE_SIZE = 50000;
+
+ /**
+ * Refresh frequency.
+ */
+ protected final Long STATS_INPUT_CHANGED_REFRESH = 5000L;
+
+ /**
+ * Stores the request to the experiment
+ */
+ protected TmfStatisticsRequest fRequest = null;
+
+ /**
+ * Stores the ranged request to the experiment
+ */
+ protected TmfStatisticsRequest fRequestRange = null;
/**
* The actual tree viewer to display
protected TreeViewer fTreeViewer;
/**
- * View instance counter (for multiple statistic views)
+ * The statistics tree linked to this viewer
+ */
+ protected AbsTmfStatisticsTree fStatisticsData;
+
+ /**
+ * Update synchronization parameter (used for streaming): Update busy
+ * indicator.
+ */
+ protected boolean fStatisticsUpdateBusy = false;
+
+ /**
+ * Update synchronization parameter (used for streaming): Update pending
+ * indicator.
+ */
+ protected boolean fStatisticsUpdatePending = false;
+
+ /**
+ * Update synchronization parameter (used for streaming): Pending Update
+ * time range.
+ */
+ protected TmfTimeRange fStatisticsUpdateRange = null;
+
+ /**
+ * Update synchronization object.
+ */
+ protected final Object fStatisticsUpdateSyncObj = new Object();
+
+ /**
+ * Indicates to process all events
+ */
+ private boolean fProcessAll;
+
+ /**
+ * View instance counter (for multiple statistics views)
*/
private static int fCountInstance = 0;
*/
private int fInstanceNb;
+ /**
+ * The trace that is displayed by this viewer
+ */
+ private ITmfTrace fTrace;
+
/**
* Object to store the cursor while waiting for the experiment to load
*/
private Cursor fWaitCursor = null;
/**
- * Default constructor
+ * Counts the number of times waitCursor() has been called. It avoids
+ * removing the waiting cursor, since there may be multiple requests running
+ * at the same time.
+ */
+ private int fWaitCursorCount = 0;
+
+ /**
+ * Tells to send a time range request when the experiment gets updated.
+ */
+ private boolean fSendRangeRequest = true;
+
+ /**
+ * Empty constructor. To be used in conjunction with
+ * {@link TmfStatisticsViewer#init(Composite, String, ITmfTrace)}
+ */
+ public TmfStatisticsViewer() {
+ super();
+ }
+
+ /**
+ * Create a basic statistics viewer. To be used in conjunction with
+ * {@link TmfStatisticsViewer#init(Composite, String, ITmfTrace)}
+ *
+ * @param parent
+ * The parent composite that will hold the viewer
+ * @param viewerName
+ * The name that will be assigned to this viewer
+ * @param trace
+ * The trace that is displayed by this viewer
+ * @see TmfComponent
+ */
+ public TmfStatisticsViewer(Composite parent, String viewerName, ITmfTrace trace) {
+ init(parent, viewerName, trace);
+ }
+
+ /**
+ * Initialize the statistics viewer.
*
* @param parent
- * The parent of this viewer
+ * The parent component of the viewer.
+ * @param viewerName
+ * The name to give to the viewer.
+ * @param trace
+ * The trace that will be displayed by the viewer.
*/
- public TmfStatisticsViewer(Composite parent) {
+ public void init(Composite parent, String viewerName, ITmfTrace trace) {
+ super.init(parent, viewerName);
// Increment a counter to make sure the tree ID is unique.
fCountInstance++;
fInstanceNb = fCountInstance;
+ fTrace = trace;
+
+ // The viewer will process all events if he is assigned to the experiment
+ fProcessAll = (trace instanceof TmfExperiment);
+
+ initContent(parent);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.linuxtools.tmf.core.component.TmfComponent#dispose()
+ */
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (fWaitCursor != null) {
+ fWaitCursor.dispose();
+ }
+ /*
+ * Make sure there is no request running before removing the statistics
+ * tree
+ */
+ cancelOngoingRequest(fRequestRange);
+ cancelOngoingRequest(fRequest);
+ }
+
+ /**
+ * Handles the signal about new experiment range.
+ *
+ * @param signal
+ * The experiment range updated signal
+ */
+ @TmfSignalHandler
+ public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal) {
+ TmfExperiment experiment = signal.getExperiment();
+ // validate
+ if (!experiment.equals(TmfExperiment.getCurrentExperiment())) {
+ return;
+ }
+
+ // Sends the time range request only once in this method.
+ if (fSendRangeRequest) {
+ fSendRangeRequest = false;
+ // Calculate the selected time range to request
+ long startTime = signal.getRange().getStartTime().normalize(0, TIME_SCALE).getValue();
+ TmfTimestamp startTS = new TmfTimestamp(startTime, TIME_SCALE);
+ TmfTimestamp endTS = new TmfTimestamp(startTime + INITIAL_WINDOW_SPAN, TIME_SCALE);
+ TmfTimeRange timeRange = new TmfTimeRange(startTS, endTS);
+
+ requestTimeRangeData(experiment, timeRange);
+ }
+ requestData(experiment, signal.getRange());
+ }
+
+ /**
+ * Handles the experiment updated signal. This will detect new events in
+ * case the indexing is not coalesced with a statistics request.
+ *
+ * @param signal
+ * The experiment updated signal
+ */
+ @TmfSignalHandler
+ public void experimentUpdated(TmfExperimentUpdatedSignal signal) {
+ TmfExperiment experiment = signal.getExperiment();
+ if (!experiment.equals(TmfExperiment.getCurrentExperiment())) {
+ return;
+ }
+
+ long nbEvents = 0;
+ if (fRequest != null) {
+ nbEvents = fRequest.getLastEventIndex();
+ }
+ /*
+ * In the normal case, the statistics request is coalesced with indexing
+ * and the number of events are the same, there is nothing to do. But if
+ * it's not the case, trigger a new request to count the new events.
+ */
+ if (nbEvents < experiment.getNbEvents()) {
+ requestData(experiment, experiment.getTimeRange());
+ }
+ }
+
+ /**
+ * * Handles the time range updated signal. It updates the time range
+ * statistics.
+ *
+ * @param signal
+ * Contains the information about the new selected time range.
+ */
+ @TmfSignalHandler
+ public void timeRangeUpdated(TmfRangeSynchSignal signal) {
+ /*
+ * It is possible that the time range changes while a request is
+ * processing.
+ */
+ cancelOngoingRequest(fRequestRange);
+
+ requestTimeRangeData(TmfExperiment.getCurrentExperiment(), signal.getCurrentRange());
+ }
+
+ /*
+ * Returns the primary control associated with this viewer.
+ *
+ * @return the SWT control which displays this viewer's content
+ */
+ @Override
+ public Control getControl() {
+ return fTreeViewer.getControl();
+ }
+
+ /**
+ * Get the input of the viewer.
+ *
+ * @return an object representing the input of the statistics viewer.
+ */
+ public Object getInput() {
+ return fTreeViewer.getInput();
+ }
+
+ /**
+ * Return the size of the request when performing background request.
+ *
+ * @return the block size for background request.
+ */
+ public int getPageSize() {
+ return PAGE_SIZE;
+ }
+
+ /**
+ * Return the number of events to receive before a refresh of the viewer is
+ * performed.
+ *
+ * @return the input refresh rate
+ */
+ public long getRefreshRate() {
+ return STATS_INPUT_CHANGED_REFRESH;
+ }
+
+ /**
+ * This method can be overridden to implement another way of representing
+ * the statistics data and to retrieve the information for display.
+ *
+ * @return a TmfStatisticsData object.
+ */
+ public AbsTmfStatisticsTree getStatisticData() {
+ if (fStatisticsData == null) {
+ fStatisticsData = new TmfBaseStatisticsTree();
+ }
+ return fStatisticsData;
+ }
+
+ /**
+ * Returns a unique ID based on name to be associated with the statistics
+ * tree for this viewer. For a same name, it will always return the same ID.
+ *
+ * @return a unique statistics tree ID.
+ */
+ public String getTreeID() {
+ return getName() + fInstanceNb;
+ }
+
+ @Override
+ public void refresh() {
+ final Control viewerControl = getControl();
+ // Ignore update if disposed
+ if (viewerControl.isDisposed()) {
+ return;
+ }
+
+ viewerControl.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!viewerControl.isDisposed()) {
+ fTreeViewer.refresh();
+ }
+ }
+ });
+ }
+
+ /**
+ * Focus on the statistics tree of the viewer
+ */
+ public void setFocus() {
+ fTreeViewer.getTree().setFocus();
+ }
+
+ /**
+ * Sets or clears the input for this viewer.
+ *
+ * @param input
+ * The input of this viewer, or <code>null</code> if none
+ */
+ public void setInput(TmfStatisticsTreeNode input) {
+ resetUpdateSynchronization();
+ fTreeViewer.setInput(input);
+ }
+
+ /**
+ * Cancels the request if it is not already completed
+ *
+ * @param request
+ * The request to be canceled
+ */
+ protected void cancelOngoingRequest(ITmfDataRequest request) {
+ if (request != null && !request.isCompleted()) {
+ request.cancel();
+ }
+ }
+
+ /**
+ * This method can be overridden to change the representation of the data in
+ * the columns.
+ *
+ * @return an object implementing ITmfBaseColumnDataProvider.
+ */
+ protected ITmfColumnDataProvider getColumnDataProvider() {
+ return new TmfBaseColumnDataProvider();
+ }
+ /**
+ * Initialize the content that will be drawn in this viewer
+ *
+ * @param parent
+ * The parent of the control to create
+ */
+ protected void initContent(Composite parent) {
final List<TmfBaseColumnData> columnDataList = getColumnDataProvider().getColumnData();
- parent.setLayout(new FillLayout());
fTreeViewer = new TreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
fTreeViewer.setContentProvider(new TmfTreeContentProvider());
}
/**
- * Refreshes this viewer completely with information freshly obtained from
- * this viewer's model.
- */
- public void refresh() {
- fTreeViewer.refresh();
- }
-
- /*
- * (non-Javadoc)
+ * Tells if the viewer is listening to a trace from the selected experiment.
*
- * @see org.eclipse.linuxtools.tmf.core.component.TmfComponent#dispose()
+ * @param traceName
+ * The trace that the viewer may be listening
+ * @return true if the viewer is listening to the trace, false otherwise
*/
- @Override
- public void dispose() {
- if (fWaitCursor != null) {
- fWaitCursor.dispose();
+ protected boolean isListeningTo(String traceName) {
+ if (fProcessAll || traceName.equals(fTrace.getName())) {
+ return true;
}
- fTreeViewer.getControl().dispose();
- super.dispose();
- // clean the model
- TmfStatisticsTreeRootFactory.removeAll();
- }
-
- /**
- * Focus on the statistics tree of the viewer
- */
- public void setFocus() {
- fTreeViewer.getTree().setFocus();
+ return false;
}
/**
- * Sets or clears the input for this viewer.
+ * Called when an experiment request has been completed successfully.
*
- * @param input
- * The input of this viewer, or <code>null</code> if none
+ * @param global
+ * Tells if the request is a global or time range (partial)
+ * request.
*/
- public void setInput(TmfStatisticsTreeNode input) {
- fTreeViewer.setInput(input);
+ protected void modelComplete(boolean global) {
+ refresh();
+ waitCursor(false);
+ if (global) {
+ sendPendingUpdate();
+ }
}
/**
- * Returns the quantity of data to retrieve before a refresh of the view is
- * performed
+ * Called when an experiment request has failed or has been cancelled.
*
- * @return the quantity of data to retrieve before a refresh of the view is
- * performed.
+ * @param isGlobalRequest
+ * Tells if the request is a global or time range (partial)
+ * request.
*/
- public long getInputChangedRefresh() {
- return STATS_INPUT_CHANGED_REFRESH;
+ protected void modelIncomplete(boolean isGlobalRequest) {
+ if (isGlobalRequest) { // Clean the global statistics
+ /*
+ * The data is invalid and shall be removed to refresh upon next
+ * selection
+ */
+ Object input = getInput();
+ if (input instanceof TmfStatisticsTreeNode) {
+ TmfStatisticsTreeRootFactory.removeStatTreeRoot(getTreeID());
+ }
+ resetUpdateSynchronization();
+ sendPendingUpdate();
+ } else { // Clean the partial statistics
+ resetTimeRangeValue();
+ }
+ refresh();
+ waitCursor(false);
}
/**
- * This method can be overridden to implement another way to represent the
- * statistics data and to retrieve the information for display.
+ * Sends the request to the experiment for the whole trace
*
- * @return a TmfStatisticsData object.
+ * @param experiment
+ * The experiment used to send the request
+ * @param range
+ * The range to request to the experiment
*/
- public AbsTmfStatisticsTree getStatisticData() {
- return new TmfBaseStatisticsTree();
+ protected void requestData(TmfExperiment experiment, TmfTimeRange range) {
+ // Check if an update is already ongoing
+ if (checkUpdateBusy(range)) {
+ return;
+ }
+
+ long index = 0;
+ /*
+ * Sets the index to the last event retrieved from the experiment during
+ * the last request.
+ */
+ if (fRequest != null) {
+ index = fRequest.getLastEventIndex();
+ }
+
+ fRequest = new TmfStatisticsRequest(this, range, index, true);
+ waitCursor(true);
+ experiment.sendRequest(fRequest);
}
/**
- * Get the input of the viewer
+ * Sends the time range request from the experiment
*
- * @return an object representing the input of the statistics viewer
+ * @param experiment
+ * The experiment used to send the request
+ * @param range
+ * The range to request to the experiment
*/
- public Object getInput() {
- return fTreeViewer.getInput();
+ protected void requestTimeRangeData(TmfExperiment experiment, TmfTimeRange range) {
+ resetTimeRangeValue();
+ fRequestRange = new TmfStatisticsRequest(this, range, 0, false);
+ waitCursor(true);
+ experiment.sendRequest(fRequestRange);
}
/**
- * Returns the primary control associated with this viewer.
- *
- * @return the SWT control which displays this viewer's content
+ * Resets the number of events within the time range
*/
- public Control getControl() {
- return fTreeViewer.getControl();
+ protected void resetTimeRangeValue() {
+ TmfStatisticsTreeNode treeModelRoot = TmfStatisticsTreeRootFactory.getStatTreeRoot(getTreeID());
+ if (treeModelRoot != null && treeModelRoot.hasChildren()) {
+ treeModelRoot.resetTimeRangeValue();
+ }
}
/**
* When the experiment is loading the cursor will be different so the user
- * know the processing is not finished yet.
+ * knows that the processing is not finished yet.
+ *
+ * Calls to this method are stacked.
*
- * @param waitInd
+ * @param waitRequested
* Indicates if we need to show the waiting cursor, or the
- * default one
+ * default one.
*/
- public void waitCursor(final boolean waitInd) {
+ protected void waitCursor(final boolean waitRequested) {
if ((fTreeViewer == null) || (fTreeViewer.getTree().isDisposed())) {
return;
}
+ boolean needsUpdate = false;
Display display = fTreeViewer.getControl().getDisplay();
- if (fWaitCursor == null) {
- fWaitCursor = new Cursor(display, SWT.CURSOR_WAIT);
+ if (waitRequested) {
+ fWaitCursorCount++;
+ if (fWaitCursor == null) { // The cursor hasn't been initialized yet
+ fWaitCursor = new Cursor(display, SWT.CURSOR_WAIT);
+ }
+ if (fWaitCursorCount == 1) { // The cursor is not in waiting mode
+ needsUpdate = true;
+ }
+ } else {
+ if (fWaitCursorCount > 0) { // The cursor is in waiting mode
+ fWaitCursorCount--;
+ if (fWaitCursorCount == 0) { // No more reason to wait
+ // Put back the default cursor
+ needsUpdate = true;
+ }
+ }
}
- // Perform the updates on the UI thread
- display.asyncExec(new Runnable() {
- @Override
- public void run() {
- if ((fTreeViewer != null)
- && (!fTreeViewer.getTree().isDisposed())) {
- Cursor cursor = null; /* indicates default */
- if (waitInd) {
- cursor = fWaitCursor;
+ if (needsUpdate) {
+ // Performs the updates on the UI thread
+ display.asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if ((fTreeViewer != null)
+ && (!fTreeViewer.getTree().isDisposed())) {
+ Cursor cursor = null; // indicates default
+ if (waitRequested) {
+ cursor = fWaitCursor;
+ }
+ fTreeViewer.getControl().setCursor(cursor);
}
- fTreeViewer.getControl().setCursor(cursor);
}
- }
- });
+ });
+ }
}
+ // ------------------------------------------------------------------------
+ // Methods reserved for the streaming functionality
+ // ------------------------------------------------------------------------
+
/**
- * Constructs the ID based on the experiment name and the instance number
- *
- * @param name
- * The name of the trace to show in the view
- * @return a view ID
+ * Resets update synchronization information
*/
- public String getTreeID(String name) {
- return name + fInstanceNb;
+ protected void resetUpdateSynchronization() {
+ synchronized (fStatisticsUpdateSyncObj) {
+ fStatisticsUpdateBusy = false;
+ fStatisticsUpdatePending = false;
+ fStatisticsUpdateRange = null;
+ }
}
/**
- * This method can be overridden to change the representation of the data in
- * the columns.
+ * Checks if statistics update is ongoing. If it is ongoing, the new time
+ * range is stored as pending
*
- * @return an object implementing ITmfBaseColumnDataProvider.
+ * @param timeRange
+ * - new time range
+ * @return true if statistic update is ongoing else false
*/
- protected ITmfColumnDataProvider getColumnDataProvider() {
- return new TmfBaseColumnDataProvider();
+ protected boolean checkUpdateBusy(TmfTimeRange timeRange) {
+ synchronized (fStatisticsUpdateSyncObj) {
+ if (fStatisticsUpdateBusy) {
+ fStatisticsUpdatePending = true;
+ if (fStatisticsUpdateRange == null
+ || timeRange.getEndTime().compareTo(fStatisticsUpdateRange.getEndTime()) > 0) {
+ fStatisticsUpdateRange = timeRange;
+ }
+ return true;
+ }
+ fStatisticsUpdateBusy = true;
+ return false;
+ }
+ }
+
+ /**
+ * Sends pending request (if any)
+ */
+ protected void sendPendingUpdate() {
+ synchronized (fStatisticsUpdateSyncObj) {
+ fStatisticsUpdateBusy = false;
+ if (fStatisticsUpdatePending) {
+ fStatisticsUpdatePending = false;
+ requestData(TmfExperiment.getCurrentExperiment(), fStatisticsUpdateRange);
+ fStatisticsUpdateRange = null;
+ }
+ }
}
}
-TmfStatisticsView_LevelColumn=Level
-TmfStatisticsView_LevelColumnTip=Level at which statistics apply.
-TmfStatisticsView_NbEventsColumn=Global event count
-TmfStatisticsView_NbEventsTip=Total amount of events that are tied to given resource.
-TmfStatisticsView_NbEventsTimeRangeColumn=Partial event count
-TmfStatisticsView_NbEventsTimeRangeTip=Number of events in the selected time range
-TmfStatisticsView_UnknownTraceName=Unknown_Trace
+TmfStatisticsView_UnknownTraceName=Unknown_Trace
\ No newline at end of file
*/
public static String TmfStatisticsData_EventTypes;
+ /**
+ * Level column name
+ */
+ public static String TmfStatisticsView_LevelColumn;
+
+ /**
+ * Level column tool tip.
+ */
+ public static String TmfStatisticsView_LevelColumnTip;
+
+ /**
+ * Number of events column name.
+ */
+ public static String TmfStatisticsView_NbEventsColumn;
+
+ /**
+ * Number of events column tool tip.
+ */
+ public static String TmfStatisticsView_NbEventsTip;
+
+ /**
+ * Partial number of events column.
+ * @since 2.0
+ */
+ public static String TmfStatisticsView_NbEventsTimeRangeColumn;
+
+ /**
+ * Partial number of events column tool tip.
+ * @since 2.0
+ */
+ public static String TmfStatisticsView_NbEventsTimeRangeTip;
+
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
-import org.eclipse.linuxtools.tmf.ui.viewers.statistics.Messages;
import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfBaseColumnData.ITmfColumnPercentageProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
TmfStatisticsData_CPUs=CPUs
-TmfStatisticsData_EventTypes=Event Types
\ No newline at end of file
+TmfStatisticsData_EventTypes=Event Types
+TmfStatisticsView_LevelColumn=Level
+TmfStatisticsView_LevelColumnTip=Level at which statistics apply.
+TmfStatisticsView_NbEventsColumn=Global event count
+TmfStatisticsView_NbEventsTip=Total amount of events contained in the trace/experiment.
+TmfStatisticsView_NbEventsTimeRangeColumn=Partial event count
+TmfStatisticsView_NbEventsTimeRangeTip=Number of events in the selected time range
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 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:
+ * Mathieu Denis <mathieu.denis@polymtl.ca> - Initial API and Implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.views.statistics;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages file for statistics view strings.
+ *
+ * @version 2.0
+ * @author Mathieu Denis
+ * @since 2.0
+ */
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.linuxtools.tmf.ui.views.statistics.messages"; //$NON-NLS-1$
+
+ /**
+ * String for unknown trace name.
+ */
+ public static String TmfStatisticsView_UnknownTraceName;
+
+ /**
+ * String for the global tab name
+ * @since 2.0
+ */
+ public static String TmfStatisticsView_GlobalTabName;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 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:
- * Mathieu Denis <mathieu.denis@polymtl.ca> - Initial implementation
- *******************************************************************************/
-
-package org.eclipse.linuxtools.tmf.ui.views.statistics;
-
-import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
-import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
-import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
-import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;
-import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;
-import org.eclipse.linuxtools.tmf.ui.viewers.statistics.ITmfExtraEventInfo;
-import org.eclipse.linuxtools.tmf.ui.viewers.statistics.Messages;
-import org.eclipse.linuxtools.tmf.ui.viewers.statistics.TmfStatisticsViewer;
-import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.AbsTmfStatisticsTree;
-import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfStatisticsTreeRootFactory;
-
-/**
- * Class for the TMF event requests specific to the statistics view.
- * @version 2.0
- */
-class TmfStatisticsRequest extends TmfEventRequest {
-
- /**
- * Reference to the statistics viewer that sent the request
- */
- private final TmfStatisticsView fSender;
-
- /**
- * The viewer that displays the statistics data
- */
- private TmfStatisticsViewer fViewer;
-
- /**
- * The experiment for which to send the request
- */
- private final TmfExperiment fExperiment;
-
- /**
- * Tells if the request is for the whole trace or for a smaller time range
- */
- private final boolean fGlobal;
-
- /**
- * The statistics tree that will be updated from the requested data
- */
- private final AbsTmfStatisticsTree fStatisticsData;
-
- /**
- * Constructor
- *
- * @param sender
- * Sender of this request
- * @param experiment
- * Experiment targeted by this request
- * @param range
- * The target time range
- * @param index
- * The starting index
- * @param prio
- * The priority of the request
- * @param global
- * Is this for a global statistics request (true), or a partial
- * one (false)?
- */
- TmfStatisticsRequest(TmfStatisticsView sender, TmfStatisticsViewer viewer, TmfExperiment experiment, TmfTimeRange range, long index, ExecutionType prio, boolean global) {
- super(ITmfEvent.class, range, index, TmfDataRequest.ALL_DATA, sender.getIndexPageSize(), prio);
- String treeID = viewer.getTreeID(experiment.getName());
-
- fSender = sender;
- fViewer = viewer;
- fExperiment = experiment;
- fGlobal = global;
- fStatisticsData = TmfStatisticsTreeRootFactory.getStatTree(treeID);
- }
-
- @Override
- public void handleData(ITmfEvent data) {
- super.handleData(data);
- if (data != null) {
- final String traceName = data.getTrace().getName();
- ITmfExtraEventInfo extraInfo = new ITmfExtraEventInfo() {
- @Override
- public String getTraceName() {
- if (traceName == null) {
- return Messages.TmfStatisticsView_UnknownTraceName;
- }
- return traceName;
- }
- };
- if (fGlobal) {
- fStatisticsData.registerEvent(data, extraInfo);
- } else {
- fStatisticsData.registerEventInTimeRange(data, extraInfo);
- }
- fStatisticsData.increase(data, extraInfo, 1);
- // Refresh view
- if ((getNbRead() % fViewer.getInputChangedRefresh()) == 0) {
- fSender.modelInputChanged(false);
- }
- }
- }
-
- @Override
- public void handleSuccess() {
- super.handleSuccess();
- fSender.modelInputChanged(true);
- if (fGlobal) {
- fViewer.waitCursor(false);
- }
- }
-
- @Override
- public void handleFailure() {
- super.handleFailure();
- fSender.modelIncomplete(fExperiment.getName());
- }
-
- @Override
- public void handleCancel() {
- super.handleCancel();
- /*
- * The global request can be cancelled when another experiment is
- * selected, but a time range request can also be cancelled when there is
- * a time range update, which means the model must not be deleted.
- */
- if (fGlobal) {
- fSender.modelIncomplete(fExperiment.getName());
- }
- }
-}
package org.eclipse.linuxtools.tmf.ui.views.statistics;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-
import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.core.runtime.Platform;
import org.eclipse.linuxtools.internal.tmf.ui.Activator;
-import org.eclipse.linuxtools.tmf.core.TmfCommonConstants;
-import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
-import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
-import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType;
-import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
-import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentDisposedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfEndSynchSignal;
import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal;
import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal;
-import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentUpdatedSignal;
-import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.linuxtools.tmf.core.signal.TmfStartSynchSignal;
import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;
import org.eclipse.linuxtools.tmf.ui.project.model.TmfTraceType;
+import org.eclipse.linuxtools.tmf.ui.viewers.ITmfViewer;
import org.eclipse.linuxtools.tmf.ui.viewers.statistics.TmfStatisticsViewer;
import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfStatisticsTreeNode;
import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfStatisticsTreeRootFactory;
import org.eclipse.linuxtools.tmf.ui.views.TmfView;
+import org.eclipse.linuxtools.tmf.ui.widgets.tabsview.TmfViewerFolder;
+import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.osgi.framework.Bundle;
+import org.eclipse.swt.widgets.Shell;
/**
* The generic Statistics View displays statistics for any kind of traces.
public class TmfStatisticsView extends TmfView {
/**
- * The ID correspond to the package in which this class is embedded
+ * The ID corresponds to the package in which this class is embedded.
*/
public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.statistics"; //$NON-NLS-1$
public static final String TMF_STATISTICS_VIEW = "StatisticsView"; //$NON-NLS-1$
/**
- * Stores the request to the experiment
- */
- protected ITmfEventRequest fRequest = null;
-
- /**
- * The viewer that builds the columns to show the statistics
- */
- private TmfStatisticsViewer fStatsViewer;
-
- /**
- * The initial window span (in nanoseconds)
- *
- * @since 2.0
- */
- public static final long INITIAL_WINDOW_SPAN = (1L * 100 * 1000 * 1000); // .1sec
-
- /**
- * Timestamp scale (nanosecond)
+ * The viewer that builds the columns to show the statistics.
*
* @since 2.0
*/
- public static final byte TIME_SCALE = -9;
+ protected final TmfViewerFolder fStatsViewers;
/**
- * Stores a reference to the parent composite of this view
- */
- private Composite fParent;
-
- /**
- * Stores a reference to the experiment
- */
- private TmfExperiment fExperiment;
-
- /**
- * Flag to force request the data from trace
+ * Flag to force request the data from trace.
*/
protected boolean fRequestData = false;
/**
- * Default PAGE_SIZE for background requests
- */
- protected static final int PAGE_SIZE = 50000;
-
- /**
- * Stores the ranged request to the experiment
- * @since 2.0
+ * Stores a reference to the selected experiment.
*/
- protected ITmfEventRequest fRequestRange = null;
-
- /**
- * Update synchronization parameter (used for streaming): Update busy
- * indicator
- */
- protected boolean fStatisticsUpdateBusy = false;
-
- /**
- * Update synchronization parameter (used for streaming): Update pending
- * indicator
- */
- protected boolean fStatisticsUpdatePending = false;
-
- /**
- * Update synchronization parameter (used for streaming): Pending Update
- * time range
- */
- protected TmfTimeRange fStatisticsUpdateRange = null;
-
- /**
- * Update synchronization object.
- */
- protected final Object fStatisticsUpdateSyncObj = new Object();
+ private TmfExperiment fExperiment;
/**
* Constructor of a statistics view.
*/
public TmfStatisticsView(String viewName) {
super(viewName);
+ /*
+ * Create a fake parent for initialization purpose, than set the parent
+ * as soon as createPartControl is called.
+ */
+ Composite temporaryParent = new Shell();
+ fStatsViewers = new TmfViewerFolder(temporaryParent);
}
/**
*/
@Override
public void createPartControl(Composite parent) {
- fParent = parent;
+ fStatsViewers.setParent(parent);
TmfExperiment currentExperiment = TmfExperiment.getCurrentExperiment();
// Read current data if any available
if (currentExperiment != null) {
experimentSelected(signal);
return;
}
- fStatsViewer = createStatisticsViewer();
+ createStatisticsViewers();
/*
* Updates the experiment field only at the end because
* experimentSelected signal verifies the old selected experiment to
fExperiment = currentExperiment;
}
- /**
- * Handles the signal about disposal of the current experiment.
- *
- * @param signal
- * The disposed signal
- */
- @TmfSignalHandler
- public void experimentDisposed(TmfExperimentDisposedSignal signal) {
- if (signal.getExperiment() != TmfExperiment.getCurrentExperiment()) {
- return;
- }
-
- /*
- * Make sure there is no request running before removing the statistics
- * tree
- */
- cancelOngoingRequest(fRequestRange);
- cancelOngoingRequest(fRequest);
- }
-
/**
* Handler called when an experiment is selected. Checks if the experiment
* has changed and requests the selected experiment if it has not yet been
* Dispose the current viewer and adapt the new one to the trace
* type of the experiment selected
*/
- if (fStatsViewer != null) {
- fStatsViewer.dispose();
- }
+ fStatsViewers.clear();
// Update the current experiment
fExperiment = signal.getExperiment();
- fStatsViewer = createStatisticsViewer();
- fParent.layout();
-
- String experimentName = fExperiment.getName();
- String treeID = fStatsViewer.getTreeID(experimentName);
-
- setInput(treeID, fExperiment.getTraces());
+ createStatisticsViewers();
+ fStatsViewers.layout();
+
+ TmfStatisticsViewer statViewer;
+ for (ITmfViewer viewer : fStatsViewers.getViewers()) {
+ if (!(viewer instanceof TmfStatisticsViewer)) {
+ Activator.getDefault().logError("Error - cannot cast viewer to a statistics viewer"); //$NON-NLS-1$
+ continue;
+ }
+ statViewer = (TmfStatisticsViewer) viewer;
+ setInput(statViewer, fExperiment.getTraces());
+ }
if (fRequestData) {
- requestData(fExperiment, fExperiment.getTimeRange());
+ TmfExperimentRangeUpdatedSignal updateSignal = new TmfExperimentRangeUpdatedSignal(null, fExperiment, fExperiment.getTimeRange());
+ TmfStatisticsViewer statsViewer;
+ // Synchronizes the request to make them coalesced
+ fExperiment.startSynch(new TmfStartSynchSignal(0));
+ for (ITmfViewer viewer : fStatsViewers.getViewers()) {
+ if (!(viewer instanceof TmfStatisticsViewer)) {
+ Activator.getDefault().logError("Error - cannot cast viewer to a statistics viewer"); //$NON-NLS-1$
+ continue;
+ }
+ statsViewer = (TmfStatisticsViewer) viewer;
+ statsViewer.experimentRangeUpdated(updateSignal);
+ }
+ fExperiment.endSynch(new TmfEndSynchSignal(0));
fRequestData = false;
}
}
}
/**
- * Initialize the viewer with the information received.
+ * Initializes the viewer with the information received.
*
- * @param treeID
- * The unique ID of the tree that is returned by
- * {@link TmfStatisticsViewer#getTreeID(String)}
+ * @param statViewer
+ * The statistics viewer for which the input will be set
* @param traces
- * The list of the traces to add in the tree.
+ * The list of traces to add in the tree.
* @since 2.0
*/
- public void setInput(String treeID, ITmfTrace[] traces) {
+ public void setInput(TmfStatisticsViewer statViewer, ITmfTrace[] traces) {
+ String treeID = statViewer.getTreeID();
if (TmfStatisticsTreeRootFactory.containsTreeRoot(treeID)) {
// The experiment root is already present
TmfStatisticsTreeNode experimentTreeNode = TmfStatisticsTreeRootFactory.getStatTreeRoot(treeID);
if (same) {
// no need to reload data, all traces are already loaded
- fStatsViewer.setInput(experimentTreeNode);
-
- resetUpdateSynchronization();
+ statViewer.setInput(experimentTreeNode);
return;
}
experimentTreeNode.reset();
}
} else {
- TmfStatisticsTreeRootFactory.addStatsTreeRoot(treeID, fStatsViewer.getStatisticData());
+ TmfStatisticsTreeRootFactory.addStatsTreeRoot(treeID, statViewer.getStatisticData());
}
- resetUpdateSynchronization();
-
TmfStatisticsTreeNode treeModelRoot = TmfStatisticsTreeRootFactory.getStatTreeRoot(treeID);
// if the model has contents, clear to start over
}
// set input to a clean data model
- fStatsViewer.setInput(treeModelRoot);
- }
-
- /**
- * Refresh the view.
- *
- * @param complete Should a pending update be sent afterwards or not
- */
- public void modelInputChanged(boolean complete) {
- Control viewerControl = fStatsViewer.getControl();
- // Ignore update if disposed
- if (viewerControl.isDisposed()) {
- return;
- }
-
- fStatsViewer.getControl().getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- if (!fStatsViewer.getControl().isDisposed()) {
- fStatsViewer.refresh();
- }
- }
- });
-
- if (complete) {
- sendPendingUpdate();
- }
- }
-
- /**
- * Called when an experiment request has failed or has been cancelled.
- * Remove the data retrieved from the experiment from the statistics tree.
- *
- * @param name
- * The experiment name
- */
- public void modelIncomplete(String name) {
- Object input = fStatsViewer.getInput();
- if (input != null && input instanceof TmfStatisticsTreeNode) {
- /*
- * The data from this experiment is invalid and shall be removed to
- * refresh upon next selection
- */
- TmfStatisticsTreeRootFactory.removeStatTreeRoot(fStatsViewer.getTreeID(name));
-
- // Reset synchronization information
- resetUpdateSynchronization();
- modelInputChanged(false);
- }
- fStatsViewer.waitCursor(false);
- }
-
- /**
- * Handles the signal about new experiment range.
- *
- * @param signal
- * The experiment range updated signal
- */
- @TmfSignalHandler
- public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal) {
- TmfExperiment experiment = signal.getExperiment();
- // validate
- if (!experiment.equals(TmfExperiment.getCurrentExperiment())) {
- return;
- }
-
- // Calculate the selected timerange to request
- long startTime = signal.getRange().getStartTime().normalize(0, TIME_SCALE).getValue();
- TmfTimestamp startTS = new TmfTimestamp(startTime, TIME_SCALE);
- TmfTimestamp endTS = new TmfTimestamp(startTime + INITIAL_WINDOW_SPAN, TIME_SCALE);
- TmfTimeRange timeRange = new TmfTimeRange(startTS, endTS);
-
- requestTimeRangeData(experiment, timeRange);
- requestData(experiment, signal.getRange());
+ statViewer.setInput(treeModelRoot);
}
/*
@Override
public void dispose() {
super.dispose();
- fStatsViewer.dispose();
-
- /*
- * Make sure there is no request running before removing the statistics
- * tree.
- */
- cancelOngoingRequest(fRequestRange);
- cancelOngoingRequest(fRequest);
+ fStatsViewers.dispose();
// clean the model
TmfStatisticsTreeRootFactory.removeAll();
}
*/
@Override
public void setFocus() {
- fStatsViewer.setFocus();
+ fStatsViewers.setFocus();
}
/**
- * Handles the experiment updated signal. This will detect new events in
- * case the indexing is not coalesced with a statistics request.
+ * Creates the statistics viewers for all traces in the experiment and
+ * popupale a viewer folder. Each viewer is placed in a different tab and
+ * the first one is selected automatically.
*
- * @param signal
- * The experiment updated signal
+ * It uses the extension point that defines the statistics viewer to build
+ * from the trace type. If no viewer is defined, another tab won't be
+ * created, since the global viewer already contains all the basic
+ * statistics. If the experiment is empty, a global statistics viewer will
+ * still be created.
*
- * @since 1.1
- */
- @TmfSignalHandler
- public void experimentUpdated(TmfExperimentUpdatedSignal signal) {
- TmfExperiment experiment = signal.getExperiment();
- if (!experiment.equals(TmfExperiment.getCurrentExperiment())) {
- return;
- }
-
- int nbEvents = 0;
- for (TmfStatisticsTreeNode node : ((TmfStatisticsTreeNode) fStatsViewer.getInput()).getChildren()) {
- nbEvents += (int) node.getValue().getTotal();
- }
-
- /*
- * In the normal case, the statistics request is coalesced with indexing
- * and the number of events are the same, there is nothing to do. But if
- * it's not the case, trigger a new request to count the new events.
- */
- if (nbEvents < experiment.getNbEvents()) {
- requestData(experiment, experiment.getTimeRange());
- }
- }
-
- /**
- * * Handles the time range updated signal. It updates the time range
- * statistics.
- *
- * @param signal
- * Contains the information about the new selected time range.
* @since 2.0
*/
- @TmfSignalHandler
- public void timeRangeUpdated(TmfRangeSynchSignal signal) {
- /*
- * It is possible that the time range changes while a request is
- * processing
- */
- cancelOngoingRequest(fRequestRange);
+ protected void createStatisticsViewers() {
+ // Default style for the tabs that will be created
+ int defaultStyle = SWT.NONE;
- requestTimeRangeData(TmfExperiment.getCurrentExperiment(), signal.getCurrentRange());
- }
+ // The folder composite that will contain the tabs
+ Composite folder = fStatsViewers.getParentFolder();
- /**
- * Get the statistics viewer for an experiment. If all traces in the
- * experiment are of the same type, use the extension point specified.
- *
- * @return a statistics viewer of the appropriate type
- * @since 2.0
- */
- protected TmfStatisticsViewer createStatisticsViewer() {
- if (fExperiment == null) {
- return new TmfStatisticsViewer(fParent);
- }
- String commonTraceType = null;
- try {
- /*
- * Determine if the traces of the experiment are of the same type.
- * If not, it uses the most generic one.
- */
+ // Instantiation of the global viewer
+ TmfStatisticsViewer globalViewer = new TmfStatisticsViewer();
+ if (fExperiment != null) {
+ // Shows the name of the experiment in the global tab
+ globalViewer.init( folder, Messages.TmfStatisticsView_GlobalTabName + " - " + fExperiment.getName(), fExperiment); //$NON-NLS-1$
+ fStatsViewers.addTab(globalViewer, Messages.TmfStatisticsView_GlobalTabName, defaultStyle);
+
+ String traceName;
+ IResource traceResource;
+ // Creates a statistics viewer for each traces.
for (ITmfTrace trace : fExperiment.getTraces()) {
- IResource resource = trace.getResource();
- if (resource == null) {
- return new TmfStatisticsViewer(fParent);
- }
- String traceType = resource.getPersistentProperty(TmfCommonConstants.TRACETYPE);
- if (commonTraceType != null && !commonTraceType.equals(traceType)) {
- return new TmfStatisticsViewer(fParent);
- }
- commonTraceType = traceType;
- }
- if (commonTraceType == null) {
- return new TmfStatisticsViewer(fParent);
- }
- /*
- * Search in the configuration if there is any viewer specified for
- * this kind of trace type.
- */
- for (IConfigurationElement ce : TmfTraceType.getTypeElements()) {
- if (ce.getAttribute(TmfTraceType.ID_ATTR).equals(commonTraceType)) {
- IConfigurationElement[] statisticsViewerCE = ce.getChildren(TmfTraceType.STATISTICS_VIEWER_ELEM);
- if (statisticsViewerCE.length != 1) {
- break;
- }
- String statisticsViewer = statisticsViewerCE[0].getAttribute(TmfTraceType.CLASS_ATTR);
- if (statisticsViewer == null || statisticsViewer.length() == 0) {
- break;
- }
- Bundle bundle = Platform.getBundle(ce.getContributor().getName());
- Class<?> c = bundle.loadClass(statisticsViewer);
- Class<?>[] constructorArgs = new Class[] { Composite.class };
- Constructor<?> constructor = c.getConstructor(constructorArgs);
- Object[] args = new Object[] { fParent };
- return (TmfStatisticsViewer) constructor.newInstance(args);
+ traceName = trace.getName();
+ traceResource = trace.getResource();
+ TmfStatisticsViewer viewer = getStatisticsViewer(traceResource);
+ /*
+ * Adds a new viewer only if there is one defined for the
+ * selected trace type, since the global tab already contains
+ * all the basic event counts for the trace(s)
+ */
+ if (viewer != null) {
+ viewer.init(folder, traceName, trace);
+ fStatsViewers.addTab(viewer, viewer.getName(), defaultStyle);
}
}
- } catch (CoreException e) {
- Activator.getDefault().logError("Error creating statistics viewer : cannot find the property TmfCommonConstants.TRACETYPE", e); //$NON-NLS-1$
- } catch (ClassNotFoundException e) {
- Activator.getDefault().logError("Error creating statistics viewer : cannot load the statistics viewer class", e); //$NON-NLS-1$
- } catch (NoSuchMethodException e) {
- Activator.getDefault().logError("Error creating statistics viewer : constructor of the viewer doesn't exist", e); //$NON-NLS-1$
- } catch (InstantiationException e) {
- Activator.getDefault().logError("Error creating statistics viewer : cannot instantiate the statistics viewer", e); //$NON-NLS-1$
- } catch (IllegalAccessException e) {
- Activator.getDefault().logError("Error creating statistics viewer : cannot access the constructor of the viewer", e); //$NON-NLS-1$
- } catch (IllegalArgumentException e) {
- Activator.getDefault().logError("Error creating statistics viewer : argument(s) sent to the constructor are illegal", e); //$NON-NLS-1$
- } catch (InvocationTargetException e) {
- Activator.getDefault().logError("Error creating statistics viewer : the constructor of the viewer sent an exception", e); //$NON-NLS-1$
- }
- return new TmfStatisticsViewer(fParent);
- }
-
- /**
- * Performs the request for an experiment and populates the statistics tree
- * with events.
- *
- * @param experiment
- * Experiment for which we need the statistics data.
- * @param timeRange
- * to request
- */
- protected void requestData(final TmfExperiment experiment, TmfTimeRange timeRange) {
- if (experiment != null) {
-
- // Check if an update is already ongoing
- if (checkUpdateBusy(timeRange)) {
- return;
- }
-
- int index = 0;
- for (TmfStatisticsTreeNode node : ((TmfStatisticsTreeNode) fStatsViewer.getInput()).getChildren()) {
- index += (int) node.getValue().getTotal();
- }
-
- // Prepare the global event request
- fRequest = new TmfStatisticsRequest(this, fStatsViewer, experiment, timeRange, index, ExecutionType.BACKGROUND, true);
-
- experiment.sendRequest(fRequest);
- fStatsViewer.waitCursor(true);
+ } else {
+ // There is no experiment selected. Shows an empty global tab
+ globalViewer.init(folder, Messages.TmfStatisticsView_GlobalTabName, fExperiment);
+ fStatsViewers.addTab(globalViewer, Messages.TmfStatisticsView_GlobalTabName, defaultStyle);
}
+ // Makes the global viewer visible
+ fStatsViewers.setSelection(0);
}
/**
- * Performs the time range request for an experiment and populates the
- * statistics tree with events.
+ * Retrieves and instantiates a viewer based on his plug-in definition for a
+ * specific trace type. It is specific to the statistics viewer.
*
- * @param experiment
- * Experiment for which we need the statistics data.
- * @param timeRange
- * To request
- * @since 2.0
- */
- protected void requestTimeRangeData(final TmfExperiment experiment, TmfTimeRange timeRange) {
- if (experiment != null) {
- resetTimeRangeValue();
- // Prepare the partial event request
- fRequestRange = new TmfStatisticsRequest(this, fStatsViewer, experiment, timeRange, 0, ExecutionType.FOREGROUND, false);
- experiment.sendRequest(fRequestRange);
- }
- }
-
- /**
- * Reset the number of events within the time range
+ * It only calls the 0-parameter constructor without performing any other
+ * initialization on the viewer.
*
+ * @param resource
+ * The resource where to find the information about the trace
+ * properties
+ * @return a new statistics viewer based on his plug-in definition, or null
+ * if no statistics definition was found for the trace type.
* @since 2.0
*/
- protected void resetTimeRangeValue() {
- // Reset the number of events in the time range
- String treeID = fStatsViewer.getTreeID(TmfExperiment.getCurrentExperiment().getName());
- TmfStatisticsTreeNode treeModelRoot = TmfStatisticsTreeRootFactory.getStatTreeRoot(treeID);
- if (treeModelRoot.hasChildren()) {
- treeModelRoot.resetTimeRangeValue();
- }
- }
-
- /**
- * Return the size of the request when performing background request.
- *
- * @return the block size for background request.
- */
- protected int getIndexPageSize() {
- return PAGE_SIZE;
- }
-
- /**
- * Cancels the current ongoing request
- *
- * @param request
- * The request to be canceled
- * @since 2.0
- */
- protected void cancelOngoingRequest(ITmfEventRequest request) {
- if (request != null && !request.isCompleted()) {
- request.cancel();
- }
- }
-
- /**
- * Reset update synchronization information
- */
- protected void resetUpdateSynchronization() {
- synchronized (fStatisticsUpdateSyncObj) {
- fStatisticsUpdateBusy = false;
- fStatisticsUpdatePending = false;
- fStatisticsUpdateRange = null;
- }
- }
-
- /**
- * Checks if statistic update is ongoing. If it is ongoing the new time
- * range is stored as pending
- *
- * @param timeRange
- * - new time range
- * @return true if statistic update is ongoing else false
- */
- protected boolean checkUpdateBusy(TmfTimeRange timeRange) {
- synchronized (fStatisticsUpdateSyncObj) {
- if (fStatisticsUpdateBusy) {
- fStatisticsUpdatePending = true;
- if (fStatisticsUpdateRange == null
- || timeRange.getEndTime().compareTo(fStatisticsUpdateRange.getEndTime()) > 0) {
- fStatisticsUpdateRange = timeRange;
- }
- return true;
- }
- fStatisticsUpdateBusy = true;
- return false;
- }
- }
-
- /**
- * Sends pending request (if any)
- */
- protected void sendPendingUpdate() {
- synchronized (fStatisticsUpdateSyncObj) {
- fStatisticsUpdateBusy = false;
- if (fStatisticsUpdatePending) {
- fStatisticsUpdatePending = false;
- requestData(TmfExperiment.getCurrentExperiment(), fStatisticsUpdateRange);
- fStatisticsUpdateRange = null;
- }
- }
+ protected static TmfStatisticsViewer getStatisticsViewer(IResource resource) {
+ return (TmfStatisticsViewer) TmfTraceType.getTraceTypeElement(resource, TmfTraceType.STATISTICS_VIEWER_ELEM);
}
}
--- /dev/null
+TmfStatisticsView_GlobalTabName=Global
--- /dev/null
+/*******************************************************************************
+ * 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:
+ * Mathieu Denis <mathieu.denis@polymtl.ca> - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.widgets.tabsview;
+
+import java.util.Collection;
+import java.util.HashMap;
+
+import org.eclipse.linuxtools.tmf.ui.viewers.ITmfViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Allows the user to create multiple tabs which makes it look like folders. It
+ * simplifies the management of the viewer contained in each tab.
+ *
+ * The indexing of the viewers is based on their name.
+ *
+ * @author Mathieu Denis
+ * @version 2.0
+ * @since 2.0
+ */
+public class TmfViewerFolder extends Composite {
+
+ /**
+ * The list of viewers in the folder
+ */
+ private final HashMap<String, ITmfViewer> fViewers;
+
+ /**
+ * The parent folder that contains all viewers
+ */
+ private CTabFolder fFolder;
+
+ /**
+ * Constructor with empty style
+ *
+ * @param parent
+ * The parent composite
+ */
+ public TmfViewerFolder(Composite parent) {
+ this(parent, SWT.NONE);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param parent
+ * The parent composite
+ * @param style
+ * The style of the view that will be created
+ */
+ public TmfViewerFolder(Composite parent, int style) {
+ super(parent, style);
+ setLayout(new FillLayout());
+
+ fViewers = new HashMap<String, ITmfViewer>();
+ initFolder();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.swt.widgets.Widget#dispose()
+ */
+ @Override
+ public void dispose() {
+ super.dispose();
+ for (ITmfViewer viewer : fViewers.values()) {
+ viewer.dispose();
+ }
+ if (fFolder != null) {
+ fFolder.dispose();
+ }
+ }
+
+ /**
+ * Disposes of all the viewers contained in the folder and restart to a
+ * clean state.
+ */
+ public void clear() {
+ for (ITmfViewer viewer : fViewers.values()) {
+ viewer.dispose();
+ }
+ fViewers.clear();
+ fFolder.dispose();
+ initFolder();
+ }
+
+ /**
+ * Create a new tab that will hold the viewer content. The viewer name will
+ * be used as the name for the tab. The viewer ID must be unique and can be
+ * used to retrieve the viewer from the folder.
+ *
+ * The parent of the viewer control must be the folder returned by
+ * {@link #getParentFolder()}
+ *
+ * @param viewer
+ * The viewer to put in the new tab
+ * @param viewerID
+ * The ID that will be assigned to this viewer for easy
+ * retrieving
+ * @param style
+ * The style of the widget to build
+ * @return true on success, false otherwise
+ */
+ public boolean addTab(ITmfViewer viewer, String viewerID, int style) {
+ if (fFolder == null
+ || viewer.getControl().getParent() != fFolder
+ || fViewers.containsKey(viewerID)) {
+ return false;
+ }
+ CTabItem item = new CTabItem(fFolder, style);
+ item.setText(viewer.getName());
+ item.setControl(viewer.getControl());
+ // Register the viewer in the map to dispose it at closing time
+ fViewers.put(viewerID, viewer);
+ return true;
+ }
+
+ /**
+ * Gets the folder that will be use as the parent of tabs that will hold the
+ * viewer.
+ *
+ * In order to be able to add new tabs in this view, the parent of the
+ * viewer control has to be this composite.
+ *
+ * @return the folder composite to use as the parent for the viewer control
+ * to create.
+ */
+ public Composite getParentFolder() {
+ return fFolder;
+ }
+
+ /**
+ * Gets a viewer based on his name.
+ *
+ * @param viewerName
+ * The name of the viewer to find in the folder
+ * @return The viewer which name is viewerName, or null if there is no such
+ * viewer
+ */
+ public ITmfViewer getViewer(String viewerName) {
+ return fViewers.get(viewerName);
+ }
+
+ /**
+ * Gets the viewers list contained in the folder view. The list can return
+ * the viewers in any order. It is not to be assumed that the viewers are
+ * returned in the same order as they were inserted.
+ *
+ * @return a collection of viewers contained in this view.
+ */
+ public Collection<ITmfViewer> getViewers() {
+ return fViewers.values();
+ }
+
+ /**
+ * Selects the tab at the specified index from the insertion order
+ *
+ * @param index
+ * The index of the tab to be selected
+ * @throws SWTException
+ * <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed
+ * </li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the receiver</li>
+ * </ul>
+ */
+ public void setSelection(int index) throws SWTException {
+ fFolder.setSelection(index);
+ }
+
+ /**
+ * Initializes the folder or put it a back to a clean state.
+ */
+ private void initFolder() {
+ if (fFolder != null) {
+ fFolder.dispose();
+ }
+ fFolder = new CTabFolder(this, SWT.LEFT | SWT.BORDER);
+ fFolder.setSimple(false);
+ }
+}