From 05627bda133a61e3159c52fce117caf3d87c3090 Mon Sep 17 00:00:00 2001 From: Mathieu Denis Date: Fri, 10 Aug 2012 15:15:25 -0400 Subject: [PATCH] tmf: Use tabs in statistics view for each traces When an experiment/trace is selected, the statistics view creates a global viewer and a specific viewer for each trace contained in the experiment. These viewers are placed in tabs and shown in the statistics view. Also, a factory is now used to create a viewer based on his definition in the plug-in.xml from the trace type. An extension point element has been added to the trace type extension point to provide custom statistics viewer. Fixes bug 387217 on bugs.eclipse.org Signed-off-by: Mathieu Denis Change-Id: I8d380e8c28cba855b5361069200e50ab0cbca7f3 Reviewed-on: https://git.eclipse.org/r/7042 Reviewed-by: Bernd Hufmann IP-Clean: Bernd Hufmann Tested-by: Bernd Hufmann --- .../TmfBaseColumnDataProviderTest.java | 4 +- .../META-INF/MANIFEST.MF | 2 + .../tmf/ui/project/model/TmfTraceType.java | 44 ++ .../linuxtools/tmf/ui/viewers/ITmfViewer.java | 41 ++ .../linuxtools/tmf/ui/viewers/TmfViewer.java | 88 +++ .../statistics/ITmfExtraEventInfo.java | 2 +- .../tmf/ui/viewers/statistics/Messages.java | 36 +- .../statistics/TmfStatisticsRequest.java | 142 +++++ .../statistics/TmfStatisticsViewer.java | 594 +++++++++++++++--- .../ui/viewers/statistics/messages.properties | 8 +- .../ui/viewers/statistics/model/Messages.java | 32 + .../model/TmfBaseColumnDataProvider.java | 1 - .../statistics/model/messages.properties | 8 +- .../tmf/ui/views/statistics/Messages.java | 46 ++ .../statistics/TmfStatisticsRequest.java | 139 ---- .../views/statistics/TmfStatisticsView.java | 548 ++++------------ .../ui/views/statistics/messages.properties | 1 + .../ui/widgets/tabsview/TmfViewerFolder.java | 198 ++++++ 18 files changed, 1220 insertions(+), 714 deletions(-) create mode 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/ITmfViewer.java create mode 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/TmfViewer.java mode change 100755 => 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/Messages.java create mode 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/TmfStatisticsRequest.java mode change 100755 => 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/messages.properties create mode 100755 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/Messages.java delete mode 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/TmfStatisticsRequest.java create mode 100755 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/messages.properties create mode 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/tabsview/TmfViewerFolder.java diff --git a/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/statistics/TmfBaseColumnDataProviderTest.java b/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/statistics/TmfBaseColumnDataProviderTest.java index 1586ea5beb..74ff586751 100644 --- a/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/statistics/TmfBaseColumnDataProviderTest.java +++ b/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/statistics/TmfBaseColumnDataProviderTest.java @@ -41,8 +41,8 @@ public class TmfBaseColumnDataProviderTest extends TestCase { // ------------------------------------------------------------------------ // 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; diff --git a/org.eclipse.linuxtools.tmf.ui/META-INF/MANIFEST.MF b/org.eclipse.linuxtools.tmf.ui/META-INF/MANIFEST.MF index 536752a6b3..b511acf8bc 100644 --- a/org.eclipse.linuxtools.tmf.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.linuxtools.tmf.ui/META-INF/MANIFEST.MF @@ -29,6 +29,7 @@ Export-Package: org.eclipse.linuxtools.internal.tmf.ui;x-friends:="org.eclipse.l 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, @@ -53,6 +54,7 @@ Export-Package: org.eclipse.linuxtools.internal.tmf.ui;x-friends:="org.eclipse.l 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, diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/project/model/TmfTraceType.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/project/model/TmfTraceType.java index dc0c206496..0d9b8d951e 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/project/model/TmfTraceType.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/project/model/TmfTraceType.java @@ -15,8 +15,12 @@ package org.eclipse.linuxtools.tmf.ui.project.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. @@ -100,6 +104,46 @@ public class TmfTraceType { 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. diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/ITmfViewer.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/ITmfViewer.java new file mode 100644 index 0000000000..fbed37abe4 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/ITmfViewer.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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 - 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(); +} diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/TmfViewer.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/TmfViewer.java new file mode 100644 index 0000000000..82fea075ef --- /dev/null +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/TmfViewer.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * 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 - 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; + } +} diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/ITmfExtraEventInfo.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/ITmfExtraEventInfo.java index 0a507ebb82..8cac723430 100755 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/ITmfExtraEventInfo.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/ITmfExtraEventInfo.java @@ -24,7 +24,7 @@ package org.eclipse.linuxtools.tmf.ui.viewers.statistics; public interface ITmfExtraEventInfo { /** - * Returns the trace name. + * Returns the name of the trace. * * @return the name of the trace. */ diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/Messages.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/Messages.java old mode 100755 new mode 100644 index a27be40859..202aa36e92 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/Messages.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/Messages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * 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 @@ -17,46 +17,14 @@ import org.eclipse.osgi.util.NLS; /** * 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. */ diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/TmfStatisticsRequest.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/TmfStatisticsRequest.java new file mode 100644 index 0000000000..ec09c925ee --- /dev/null +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/TmfStatisticsRequest.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * 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 - 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); + } + } +} diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/TmfStatisticsViewer.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/TmfStatisticsViewer.java index 103913cf61..54f4e892d0 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/TmfStatisticsViewer.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/TmfStatisticsViewer.java @@ -19,6 +19,16 @@ import org.eclipse.jface.viewers.TreeViewerColumn; 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; @@ -32,7 +42,6 @@ import org.eclipse.swt.events.SelectionAdapter; 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; @@ -46,12 +55,37 @@ import org.eclipse.swt.widgets.Listener; * @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 @@ -59,7 +93,40 @@ public class TmfStatisticsViewer extends TmfComponent { 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; @@ -68,24 +135,295 @@ public class TmfStatisticsViewer extends TmfComponent { */ 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 null 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 columnDataList = getColumnDataProvider().getColumnData(); - parent.setLayout(new FillLayout()); fTreeViewer = new TreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); fTreeViewer.setContentProvider(new TmfTreeContentProvider()); @@ -187,137 +525,215 @@ public class TmfStatisticsViewer extends TmfComponent { } /** - * 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 null 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; + } + } } } diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/messages.properties b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/messages.properties old mode 100755 new mode 100644 index 2542d73b09..9009fe087f --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/messages.properties +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/messages.properties @@ -1,7 +1 @@ -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 diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/Messages.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/Messages.java index 08c95aeadb..2a50be4554 100755 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/Messages.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/Messages.java @@ -35,6 +35,38 @@ public class Messages extends NLS { */ 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); diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/TmfBaseColumnDataProvider.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/TmfBaseColumnDataProvider.java index 29d6e4e496..4edced393a 100755 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/TmfBaseColumnDataProvider.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/TmfBaseColumnDataProvider.java @@ -21,7 +21,6 @@ import java.util.Vector; 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; diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/messages.properties b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/messages.properties index 442d278a76..183c928ddc 100755 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/messages.properties +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/statistics/model/messages.properties @@ -1,2 +1,8 @@ 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 diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/Messages.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/Messages.java new file mode 100755 index 0000000000..cd8abf50a1 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/Messages.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * 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 - 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() { + } +} diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/TmfStatisticsRequest.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/TmfStatisticsRequest.java deleted file mode 100644 index 980b523397..0000000000 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/TmfStatisticsRequest.java +++ /dev/null @@ -1,139 +0,0 @@ -/******************************************************************************* - * 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 - 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()); - } - } -} diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/TmfStatisticsView.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/TmfStatisticsView.java index efe0608215..68b4820047 100755 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/TmfStatisticsView.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/TmfStatisticsView.java @@ -16,35 +16,25 @@ 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. @@ -60,7 +50,7 @@ import org.osgi.framework.Bundle; 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$ @@ -70,77 +60,21 @@ public class TmfStatisticsView extends TmfView { 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. @@ -149,6 +83,12 @@ public class TmfStatisticsView extends TmfView { */ 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); } /** @@ -166,7 +106,7 @@ public class TmfStatisticsView extends TmfView { */ @Override public void createPartControl(Composite parent) { - fParent = parent; + fStatsViewers.setParent(parent); TmfExperiment currentExperiment = TmfExperiment.getCurrentExperiment(); // Read current data if any available if (currentExperiment != null) { @@ -176,7 +116,7 @@ public class TmfStatisticsView extends TmfView { experimentSelected(signal); return; } - fStatsViewer = createStatisticsViewer(); + createStatisticsViewers(); /* * Updates the experiment field only at the end because * experimentSelected signal verifies the old selected experiment to @@ -185,26 +125,6 @@ public class TmfStatisticsView extends TmfView { 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 @@ -223,21 +143,36 @@ public class TmfStatisticsView extends TmfView { * 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; } } @@ -245,16 +180,16 @@ public class TmfStatisticsView extends TmfView { } /** - * 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); @@ -279,20 +214,16 @@ public class TmfStatisticsView extends TmfView { 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 @@ -301,80 +232,7 @@ public class TmfStatisticsView extends TmfView { } // 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); } /* @@ -385,14 +243,7 @@ public class TmfStatisticsView extends TmfView { @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(); } @@ -404,260 +255,77 @@ public class TmfStatisticsView extends TmfView { */ @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); } } diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/messages.properties b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/messages.properties new file mode 100755 index 0000000000..43d885ebe6 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/statistics/messages.properties @@ -0,0 +1 @@ +TmfStatisticsView_GlobalTabName=Global diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/tabsview/TmfViewerFolder.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/tabsview/TmfViewerFolder.java new file mode 100644 index 0000000000..2b6e2b8fe5 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/tabsview/TmfViewerFolder.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * 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 - 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 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(); + 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 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 + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed + *
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ */ + 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); + } +} -- 2.34.1