times) {
+ if (times.isEmpty()) {
+ throw new IllegalArgumentException("The requested times is empty"); //$NON-NLS-1$
+ }
if (!Ordering.natural().isOrdered(times)) {
throw new IllegalArgumentException("List of times is not sorted"); //$NON-NLS-1$
}
@@ -70,7 +79,10 @@ public TimeQueryFilter(List times) {
* @return The array of requested times
*/
public long[] getTimesRequested() {
- return fTimesRequested;
+ if (fTimesRequested == null) {
+ fTimesRequested = splitRangeIntoEqualParts(fStart, fEnd, fNbSamples);
+ }
+ return Objects.requireNonNull(fTimesRequested);
}
/**
@@ -79,7 +91,10 @@ public long[] getTimesRequested() {
* @return The first time
*/
public long getStart() {
- return fTimesRequested[0];
+ if (fTimesRequested != null) {
+ return fTimesRequested[0];
+ }
+ return fStart;
}
/**
@@ -88,7 +103,23 @@ public long getStart() {
* @return The last time
*/
public long getEnd() {
- return fTimesRequested[Integer.max(0, fTimesRequested.length - 1)];
+ if (fTimesRequested != null) {
+ return fTimesRequested[Integer.max(0, Objects.requireNonNull(fTimesRequested).length - 1)];
+ }
+ return fEnd;
+ }
+
+ /**
+ * Gets the number of samples
+ *
+ * @return The the number of samples
+ * @since 10.1
+ */
+ public int getNumberOfSamples() {
+ if (fTimesRequested != null) {
+ return Objects.requireNonNull(fTimesRequested).length;
+ }
+ return fNbSamples;
}
/**
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/genericxy/AbstractTreeGenericXYCommonXDataProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/genericxy/AbstractTreeGenericXYCommonXDataProvider.java
new file mode 100644
index 0000000000..7721129d7c
--- /dev/null
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/genericxy/AbstractTreeGenericXYCommonXDataProvider.java
@@ -0,0 +1,160 @@
+/**********************************************************************
+ * Copyright (c) 2025 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License 2.0 which
+ * accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ **********************************************************************/
+package org.eclipse.tracecompass.tmf.core.model.genericxy;
+
+import org.eclipse.tracecompass.tmf.core.model.tree.AbstractTreeDataProvider;
+import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataModel;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
+import java.util.logging.Level;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.tmf.core.model.TmfXyResponseFactory;
+import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
+import org.eclipse.tracecompass.tmf.core.model.CommonStatusMessage;
+import org.eclipse.tracecompass.tmf.core.model.ISampling;
+import org.eclipse.tracecompass.tmf.core.model.filters.SelectionTimeQueryFilter;
+import org.eclipse.tracecompass.tmf.core.model.xy.ISeriesModel.DisplayType;
+import org.eclipse.tracecompass.tmf.core.model.xy.ITmfTreeXYDataProvider;
+import org.eclipse.tracecompass.tmf.core.model.xy.ITmfXyModel;
+import org.eclipse.tracecompass.tmf.core.model.xy.IYModel;
+import org.eclipse.tracecompass.tmf.core.model.xy.TmfXYAxisDescription;
+import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
+import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.util.Pair;
+import org.eclipse.tracecompass.traceeventlogger.LogUtils.FlowScopeLog;
+import org.eclipse.tracecompass.traceeventlogger.LogUtils.FlowScopeLogBuilder;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Abstract base class for tree-based data providers support xy chart with
+ * non-time x-axis visualizations. Default visualization type is set to bars.
+ *
+ * This class extends {@link AbstractTreeDataProvider} to handle hierarchical
+ * tree data, while also implementing {@link ITmfGenericXYDataProvider} to
+ * supply generic xy chart data for views. It is meant to be sub-classed by
+ * concrete providers that use generic xy chart representations.
+ *
+ *
+ * @param
+ * The type of analysis module used, which must extend
+ * {@link TmfStateSystemAnalysisModule}
+ * @param
+ * The type of tree data model, which must implement
+ * {@link ITmfTreeDataModel}
+ * @author Siwei Zhang
+ * @since 10.1
+ */
+public abstract class AbstractTreeGenericXYCommonXDataProvider
+ extends AbstractTreeDataProvider implements ITmfTreeXYDataProvider {
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * The trace associated with this data provider
+ * @param analysisModule
+ * The analysis module used to compute data
+ */
+ public AbstractTreeGenericXYCommonXDataProvider(ITmfTrace trace, A analysisModule) {
+ super(trace, analysisModule);
+ }
+
+ @Override
+ public TmfModelResponse fetchXY(Map fetchParameters, @Nullable IProgressMonitor monitor) {
+ A module = getAnalysisModule();
+
+ SelectionTimeQueryFilter filter = FetchParametersUtils.createSelectionTimeQueryWithSamples(fetchParameters);
+ if (filter == null) {
+ return TmfXyResponseFactory.createFailedResponse(CommonStatusMessage.INCORRECT_QUERY_PARAMETERS);
+ }
+
+ TmfModelResponse res = verifyParameters(module, filter, monitor);
+ if (res != null) {
+ return res;
+ }
+
+ ITmfStateSystem ss = Objects.requireNonNull(module.getStateSystem(),
+ "Statesystem should have been verified by verifyParameters"); //$NON-NLS-1$
+ long currentEnd = ss.getCurrentEndTime();
+ boolean complete = ss.waitUntilBuilt(0) || filter.getEnd() <= currentEnd;
+
+ try (FlowScopeLog scope = new FlowScopeLogBuilder(LOGGER, Level.FINE, "AbstractTreeGenericXYCommonXDataProvider#fetchXY") //$NON-NLS-1$
+ .setCategory(getClass().getSimpleName()).build()) {
+ Pair> xAxisAndYSeriesModels = getXAxisAndYSeriesModels(ss, fetchParameters, monitor);
+ if (xAxisAndYSeriesModels == null) {
+ // getModels returns null if the query was cancelled.
+ return TmfXyResponseFactory.createCancelledResponse(CommonStatusMessage.TASK_CANCELLED);
+ }
+ return TmfXyResponseFactory.create(
+ getTitle(),
+ xAxisAndYSeriesModels.getFirst(),
+ ImmutableList.copyOf(xAxisAndYSeriesModels.getSecond()),
+ getDisplayType(),
+ getXAxisDescription(),
+ complete);
+ } catch (StateSystemDisposedException | TimeRangeException | IndexOutOfBoundsException e) {
+ return TmfXyResponseFactory.createFailedResponse(String.valueOf(e.getMessage()));
+ }
+ }
+
+ /**
+ * Get the display type for series.
+ *
+ * @return Description for series
+ */
+ protected DisplayType getDisplayType() {
+ return DisplayType.BAR;
+ }
+
+ /**
+ * Get description for x axis.
+ *
+ * @return Description for x axis
+ */
+ protected abstract TmfXYAxisDescription getXAxisDescription();
+
+ /**
+ * Abstract method to be implemented by the providers to return the x axis
+ * and height of bars. The child class should check the validity of values
+ * inside query parameters.
+ *
+ * @param ss
+ * the {@link TmfStateSystemAnalysisModule}'s
+ * {@link ITmfStateSystem}
+ * @param fetchParameters
+ * the query's filter
+ * @param monitor
+ * progress monitor
+ * @return a pair, the first element is x values, and the second element is
+ * Y models; null if the query was cancelled
+ * @throws StateSystemDisposedException
+ * if the state system was closed during the query or could not
+ * be queried.
+ */
+ protected abstract @Nullable Pair> getXAxisAndYSeriesModels(ITmfStateSystem ss,
+ Map fetchParameters, @Nullable IProgressMonitor monitor)
+ throws StateSystemDisposedException;
+
+ /**
+ * Getter for the title of this provider
+ *
+ * @return this provider's title
+ */
+ protected abstract String getTitle();
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/genericxy/package-info.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/genericxy/package-info.java
new file mode 100644
index 0000000000..22cb8c9165
--- /dev/null
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/genericxy/package-info.java
@@ -0,0 +1,13 @@
+/*******************************************************************************
+ * Copyright (c) 2025 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License 2.0 which
+ * accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.tmf.core.model.genericxy;
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/tree/AbstractTreeDataProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/tree/AbstractTreeDataProvider.java
index bb7af58c7d..4875c7cf99 100644
--- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/tree/AbstractTreeDataProvider.java
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/tree/AbstractTreeDataProvider.java
@@ -203,15 +203,14 @@ protected long getEntryId(Object key) {
}
/**
- * Get selected entries from the filter for this provider
+ * Get selected entries from the filter for this provider.
*
- * @param filter
- * {@link SelectionTimeQueryFilter}.
- * @return a map of the valid entries' ID from the filter to their respective
- * quark
+ * @param selectedItems
+ * the collection of selected item IDs
+ * @return a map of the valid entries' ID to their respective quark
*/
- protected Map getSelectedEntries(SelectionTimeQueryFilter filter) {
- return getSelectedEntries(filter.getSelectedItems());
+ protected Map getSelectedEntries(SelectionTimeQueryFilter selectedItems) {
+ return getSelectedEntries(selectedItems.getSelectedItems());
}
/**
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/xy/ISeriesModel.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/xy/ISeriesModel.java
index 421934a7de..c53b560c44 100644
--- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/xy/ISeriesModel.java
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/xy/ISeriesModel.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2017 École Polytechnique de Montréal
+ * Copyright (c) 2017, 2025 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
@@ -14,6 +14,7 @@
import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.internal.tmf.core.model.xy.Messages;
import org.eclipse.tracecompass.tmf.core.model.CoreFilterProperty;
+import org.eclipse.tracecompass.tmf.core.model.ISampling;
/**
* This represents a model for a series in a XY chart. I should be used to
@@ -34,13 +35,18 @@ public interface ISeriesModel {
*/
public enum DisplayType {
/**
- * Line
+ * Line (only for XY line charts)
*/
LINE,
/**
- * Scatter
+ * Scatter (only for XY line charts)
*/
- SCATTER
+ SCATTER,
+ /**
+ * Bars (only for generic XY charts)
+ * @since 10.1
+ */
+ BAR
}
/**
@@ -91,9 +97,22 @@ default DisplayType getDisplayType() {
* Get the X values
*
* @return The x values
+ * @deprecated Use {@link #getSampling()} instead for support of categorical axes.
*/
+ @Deprecated(since = "10.1", forRemoval = true)
long[] getXAxis();
+ /**
+ * Sampling points for the X-axis, supporting both time-based and categorical domains.
+ *
+ * @return the X-axis sampling representation
+ * @since 10.1
+ */
+ default ISampling getSampling() {
+ long[] legacy = getXAxis();
+ return new ISampling.Timestamps(legacy);
+ }
+
/**
* Get the y values
*
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/xy/TmfXYAxisDescription.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/xy/TmfXYAxisDescription.java
index cc0fe27064..3394d8ae5f 100644
--- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/xy/TmfXYAxisDescription.java
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/model/xy/TmfXYAxisDescription.java
@@ -1,5 +1,5 @@
/**********************************************************************
- * Copyright (c) 2019 Ericsson
+ * Copyright (c) 2019, 2025 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
@@ -15,6 +15,7 @@
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.tmf.core.dataprovider.DataType;
+import org.eclipse.tracecompass.tmf.core.model.IAxisDomain;
/**
* Represent a XY Axis description
@@ -26,6 +27,7 @@ public class TmfXYAxisDescription {
private String fLabel;
private String fUnit;
private DataType fDataType;
+ @Nullable private IAxisDomain fAxisDomain;
/**
* Constructor
@@ -57,6 +59,27 @@ public TmfXYAxisDescription(String label, String unit, DataType dataType) {
fDataType = dataType;
}
+ /**
+ * Constructor
+ *
+ * @param label
+ * Label for the axis
+ * @param unit
+ * Unit type
+ * @param dataType
+ * The type of data this series represents
+ * @param axisDomain
+ * The available values for this axis
+ * @since 10.1
+ */
+ public TmfXYAxisDescription(String label, String unit, DataType dataType, IAxisDomain axisDomain) {
+ super();
+ fLabel = label;
+ fUnit = unit;
+ fDataType = dataType;
+ fAxisDomain = axisDomain;
+ }
+
/**
* Get the axis label
*
@@ -85,6 +108,16 @@ public DataType getDataType() {
return fDataType;
}
+ /**
+ * Get the available values for this axis
+ *
+ * @return The available values for this axis
+ * @since 10.1
+ */
+ public @Nullable IAxisDomain getAxisDomain() {
+ return fAxisDomain;
+ }
+
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
@@ -99,11 +132,12 @@ public boolean equals(@Nullable Object obj) {
TmfXYAxisDescription other = (TmfXYAxisDescription) obj;
return fLabel.equals(other.getLabel())
&& fUnit.equals(other.getUnit())
- && Objects.equals(fDataType, other.fDataType);
+ && Objects.equals(fDataType, other.fDataType)
+ && Objects.equals(fAxisDomain, other.fAxisDomain);
}
@Override
public int hashCode() {
- return Objects.hash(fLabel, fUnit, fDataType);
+ return Objects.hash(fLabel, fUnit, fDataType, fAxisDomain);
}
}