tmf: Fix Marker Set action handling
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / internal / tmf / ui / markers / ConfigurableMarkerEventSource.java
CommitLineData
c1ed0a0c 1/*******************************************************************************
aa67df36 2 * Copyright (c) 2017 Ericsson
c1ed0a0c
PT
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.tracecompass.internal.tmf.ui.markers;
14
15import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
17import java.util.ArrayList;
18import java.util.Comparator;
19import java.util.HashMap;
20import java.util.LinkedHashSet;
21import java.util.List;
22import java.util.Map;
23import java.util.Set;
24import java.util.stream.Collectors;
25
aa67df36 26import org.eclipse.core.runtime.IAdaptable;
c1ed0a0c
PT
27import org.eclipse.core.runtime.IProgressMonitor;
28import org.eclipse.jdt.annotation.NonNull;
aa67df36 29import org.eclipse.jdt.annotation.Nullable;
c1ed0a0c
PT
30import org.eclipse.swt.graphics.RGB;
31import org.eclipse.swt.graphics.RGBA;
32import org.eclipse.tracecompass.internal.tmf.core.markers.IMarkerConstants;
33import org.eclipse.tracecompass.internal.tmf.core.markers.Marker;
34import org.eclipse.tracecompass.internal.tmf.core.markers.Marker.PeriodicMarker;
35import org.eclipse.tracecompass.internal.tmf.core.markers.MarkerSegment;
36import org.eclipse.tracecompass.internal.tmf.core.markers.MarkerSet;
37import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker;
38import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker.SplitMarker;
39import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker.WeightedMarker;
f16950de
PT
40import org.eclipse.tracecompass.tmf.core.signal.TmfMarkerEventSourceUpdatedSignal;
41import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
42import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
43import org.eclipse.tracecompass.tmf.core.trace.AbstractTmfTraceAdapterFactory.IDisposableAdapter;
980ca0c9 44import org.eclipse.tracecompass.tmf.core.trace.ICyclesConverter;
c1ed0a0c 45import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
a5c7cc1d 46import org.eclipse.tracecompass.tmf.ui.colors.X11Color;
aa67df36 47import org.eclipse.tracecompass.tmf.ui.markers.IMarkerReferenceProvider;
c1ed0a0c
PT
48import org.eclipse.tracecompass.tmf.ui.markers.PeriodicMarkerEventSource;
49import org.eclipse.tracecompass.tmf.ui.markers.PeriodicMarkerEventSource.Reference;
50import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEvent;
51import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEventSource;
52import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.MarkerEvent;
53
54import com.google.common.collect.Lists;
55import com.google.common.collect.RangeSet;
56
57/**
58 * Configurable marker event source.
59 */
f16950de 60public class ConfigurableMarkerEventSource implements IMarkerEventSource, IDisposableAdapter {
c1ed0a0c
PT
61
62 private static final long NANO_PER_MILLI = 1000000L;
63 private static final long NANO_PER_MICRO = 1000L;
64 private static final int MIN_PERIOD = 5; // in units of resolution intervals
65 private static final int ALPHA = 10;
66 private static final String COLOR_REGEX = "#[A-Fa-f0-9]{6}"; //$NON-NLS-1$
67
68 private List<IConfigurableMarkerEventSource> fMarkerEventSources;
69 private Map<Marker, RGBA> fColors = new HashMap<>();
aa67df36 70 private final ITmfTrace fTrace;
c1ed0a0c
PT
71
72 /**
73 * Constructor
74 *
75 * @param trace
76 * the trace
77 */
78 public ConfigurableMarkerEventSource(ITmfTrace trace) {
79 fMarkerEventSources = new ArrayList<>();
aa67df36 80 fTrace = trace;
f16950de
PT
81 TmfSignalManager.register(this);
82 }
83
84 @Override
85 public void dispose() {
86 TmfSignalManager.deregister(this);
c1ed0a0c
PT
87 }
88
89 /**
90 * Configure the marker source from the specified marker set
91 *
92 * @param markerSet
93 * the marker set, or null to clear the configuration
94 */
95 public void configure(MarkerSet markerSet) {
96 fMarkerEventSources.clear();
97 if (markerSet != null) {
98 for (Marker marker : markerSet.getMarkers()) {
99 configure(marker);
100 }
101 }
102 }
103
104 private void configure(Marker marker) {
105 if (marker instanceof PeriodicMarker) {
106 PeriodicMarker periodicMarker = (PeriodicMarker) marker;
aa67df36
PT
107 String referenceId = periodicMarker.getReferenceId();
108 Reference baseReference = null;
109 if (fTrace instanceof IAdaptable && !referenceId.isEmpty()) {
110 @Nullable IMarkerReferenceProvider adapter = ((IAdaptable) fTrace).getAdapter(IMarkerReferenceProvider.class);
111 if (adapter != null) {
112 baseReference = adapter.getReference(referenceId);
113 }
114 }
115 if (baseReference == null) {
116 baseReference = Reference.ZERO;
117 }
c1ed0a0c
PT
118 long rollover = periodicMarker.getRange().hasUpperBound() ? (periodicMarker.getRange().upperEndpoint() - periodicMarker.getRange().lowerEndpoint() + 1) : 0;
119 RGBA evenColor = getColor(periodicMarker);
120 RGBA oddColor = getOddColor(evenColor);
121 double period = convertToNanos(periodicMarker.getPeriod(), periodicMarker.getUnit());
aa67df36 122 Reference reference = new Reference(baseReference.getTime() + Math.round(convertToNanos(periodicMarker.getOffset(), periodicMarker.getUnit())), baseReference.getIndex());
c1ed0a0c
PT
123 ConfigurablePeriodicMarkerEventSource markerEventSource = new ConfigurablePeriodicMarkerEventSource(marker, checkNotNull(periodicMarker.getName()), reference, period, rollover, evenColor, oddColor, false, periodicMarker.getRange().lowerEndpoint(), checkNotNull(periodicMarker.getLabel()), periodicMarker.getIndexRange());
124 fMarkerEventSources.add(markerEventSource);
125 }
126 }
127
980ca0c9 128 private double convertToNanos(double number, String unit) {
c1ed0a0c
PT
129 if (unit.equalsIgnoreCase(IMarkerConstants.MS)) {
130 return number * NANO_PER_MILLI;
131 } else if (unit.equalsIgnoreCase(IMarkerConstants.US)) {
132 return number * NANO_PER_MICRO;
133 } else if (unit.equalsIgnoreCase(IMarkerConstants.NS)) {
134 return number;
980ca0c9
PT
135 } else if (unit.equalsIgnoreCase(IMarkerConstants.CYCLES) &&
136 fTrace instanceof IAdaptable) {
137 ICyclesConverter adapter = ((IAdaptable) fTrace).getAdapter(ICyclesConverter.class);
138 if (adapter != null) {
139 return adapter.cyclesToNanos((long) number);
140 }
c1ed0a0c
PT
141 }
142 return number;
143 }
144
145 private @NonNull RGBA getColor(Marker marker) {
146 RGBA color = fColors.get(marker);
147 if (color == null) {
148 color = parseColor(marker.getColor());
149 fColors.put(marker, color);
150 }
151 return color;
152 }
153
154 private static @NonNull RGBA getOddColor(RGBA color) {
155 return new RGBA(color.rgb.red, color.rgb.green, color.rgb.blue, 0);
156 }
157
158 private static @NonNull RGBA parseColor(String color) {
159 RGB rgb = null;
160 if (color.matches(COLOR_REGEX)) {
161 rgb = new RGB(Integer.valueOf(color.substring(1, 3), 16),
162 Integer.valueOf(color.substring(3, 5), 16),
163 Integer.valueOf(color.substring(5, 7), 16));
164 } else {
a5c7cc1d
PT
165 rgb = X11Color.toRGB(color);
166 if (rgb == null) {
167 rgb = new RGB(0, 0, 0);
168 }
c1ed0a0c
PT
169 }
170 return new RGBA(rgb.red, rgb.green, rgb.blue, ALPHA);
171 }
172
173 @Override
174 public List<String> getMarkerCategories() {
175 Set<String> categories = new LinkedHashSet<>();
176 for (IConfigurableMarkerEventSource source : fMarkerEventSources) {
177 categories.addAll(source.getMarkerCategories());
178 getSubMarkerCategories(categories, source.getSubMarkers());
179 }
180 return checkNotNull(Lists.newArrayList(categories));
181 }
182
183 private void getSubMarkerCategories(Set<String> categories, List<SubMarker> subMarkers) {
184 for (SubMarker subMarker : subMarkers) {
185 categories.add(subMarker.getName());
186 getSubMarkerCategories(categories, subMarker.getSubMarkers());
187 if (subMarker instanceof WeightedMarker) {
188 for (MarkerSegment segment : ((WeightedMarker) subMarker).getSegments()) {
189 getSubMarkerCategories(categories, segment.getSubMarkers());
190 }
191 }
192 }
193 }
194
195 @Override
196 public List<IMarkerEvent> getMarkerList(String category, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
197 return getMarkerList(startTime, endTime, resolution, monitor).stream()
198 .filter((marker) -> marker.getCategory().equals(category))
199 .collect(Collectors.toList());
200 }
201
202 @Override
203 public List<IMarkerEvent> getMarkerList(long startTime, long endTime, long resolution, IProgressMonitor monitor) {
204 @NonNull List<@NonNull IMarkerEvent> markerList = new ArrayList<>();
205 for (IConfigurableMarkerEventSource source : fMarkerEventSources) {
206 long minDuration = resolution * MIN_PERIOD;
207 if (source.getMaxDuration() > minDuration) {
208 @NonNull List<@NonNull IMarkerEvent> list = source.getMarkerList(startTime, endTime, resolution, monitor);
209 for (IMarkerEvent markerEvent : list) {
210 for (SubMarker subMarker : source.getSubMarkers()) {
211 getSubMarkerList(subMarker, markerEvent, markerList, startTime, endTime, minDuration);
212 }
213 markerList.add(markerEvent);
214 }
215 }
216 }
217 markerList.sort(Comparator.comparingLong(marker -> marker.getTime()));
218 return markerList;
219 }
220
221 private void getSubMarkerList(SubMarker subMarker, IMarkerEvent markerEvent, @NonNull List<@NonNull IMarkerEvent> markerList, long startTime, long endTime, long minDuration) {
222 if (subMarker instanceof SplitMarker) {
223 getSubMarkerList((SplitMarker) subMarker, markerEvent, markerList, startTime, endTime, minDuration);
224 } else if (subMarker instanceof WeightedMarker) {
225 getSubMarkerList((WeightedMarker) subMarker, markerEvent, markerList, startTime, endTime, minDuration);
226 }
227 }
228
229 private void getSubMarkerList(SplitMarker splitMarker, IMarkerEvent markerEvent, @NonNull List<@NonNull IMarkerEvent> markerList, long startTime, long endTime, long minDuration) {
230 if (markerEvent.getTime() > endTime || markerEvent.getTime() + markerEvent.getDuration() < startTime) {
231 return;
232 }
233 long lower = splitMarker.getRange().lowerEndpoint();
234 long upper = splitMarker.getRange().upperEndpoint();
235 long segments = upper - lower + 1;
236 long start = markerEvent.getTime();
237 for (int i = 0; i < segments; i++) {
238 long end = markerEvent.getTime() + Math.round((double) (i + 1) / segments * markerEvent.getDuration());
239 long duration = end - start;
240 long labelIndex = lower + i;
241 if (end >= startTime && duration > minDuration && splitMarker.getIndexRange().contains(labelIndex)) {
242 RGBA color = (labelIndex & 1) == 0 ? getColor(splitMarker) : getOddColor(getColor(splitMarker));
243 IMarkerEvent subMarkerEvent = new MarkerEvent(null, start, end - start, splitMarker.getName(), color, String.format(splitMarker.getLabel(), labelIndex), false);
244 for (SubMarker subMarker : splitMarker.getSubMarkers()) {
245 getSubMarkerList(subMarker, subMarkerEvent, markerList, startTime, endTime, minDuration);
246 }
247 markerList.add(subMarkerEvent);
248 }
249 if (start >= endTime) {
250 break;
251 }
252 start = end;
253 }
254 }
255
256 private void getSubMarkerList(WeightedMarker weightedMarker, IMarkerEvent markerEvent, @NonNull List<@NonNull IMarkerEvent> markerList, long startTime, long endTime, long minDuration) {
257 if (markerEvent.getTime() > endTime || markerEvent.getTime() + markerEvent.getDuration() < startTime) {
258 return;
259 }
260 long start = markerEvent.getTime();
261 long length = 0;
262 for (int i = 0; i < weightedMarker.getSegments().size(); i++) {
263 MarkerSegment segment = weightedMarker.getSegments().get(i);
264 length += segment.getLength();
265 long end = markerEvent.getTime() + Math.round((length / (double) weightedMarker.getTotalLength()) * markerEvent.getDuration());
266 long duration = end - start;
267 if (end >= startTime && duration > minDuration && !segment.getColor().isEmpty()) {
268 RGBA color = getColor(segment);
269 IMarkerEvent subMarkerEvent = new MarkerEvent(null, start, end - start, weightedMarker.getName(), color, String.format(segment.getLabel(), i), false);
270 for (SubMarker subMarker : segment.getSubMarkers()) {
271 getSubMarkerList(subMarker, subMarkerEvent, markerList, startTime, endTime, minDuration);
272 }
273 for (SubMarker subMarker : weightedMarker.getSubMarkers()) {
274 getSubMarkerList(subMarker, subMarkerEvent, markerList, startTime, endTime, minDuration);
275 }
276 markerList.add(subMarkerEvent);
277 }
278 if (start >= endTime) {
279 break;
280 }
281 start = end;
282 }
283 }
284
285 private static interface IConfigurableMarkerEventSource extends IMarkerEventSource {
286 double getMaxDuration();
287
288 public List<SubMarker> getSubMarkers();
289 }
290
291 private class ConfigurablePeriodicMarkerEventSource extends PeriodicMarkerEventSource implements IConfigurableMarkerEventSource {
292
293 private final Marker fMarker;
294 private final long fStartIndex;
295 private final String fLabel;
296 private final RangeSet<Long> fIndexRange;
297 private final double fMaxDuration;
298
299 public ConfigurablePeriodicMarkerEventSource(Marker marker, @NonNull String category, @NonNull Reference reference, double period, long rollover, @NonNull RGBA evenColor, @NonNull RGBA oddColor, boolean foreground, long startIndex, @NonNull String label, RangeSet<Long> indexRange) {
300 super(category, reference, period, rollover, evenColor, oddColor, foreground);
301 fMarker = marker;
302 fStartIndex = startIndex;
303 fLabel = label;
304 fIndexRange = indexRange;
305 fMaxDuration = period;
306 }
307
308 @Override
309 public @NonNull String getMarkerLabel(long index) {
310 return checkNotNull(String.format(fLabel, fStartIndex + index));
311 }
312
313 @Override
314 public boolean isApplicable(long index) {
315 if (fIndexRange != null) {
316 return fIndexRange.contains(fStartIndex + index);
317 }
318 return true;
319 }
320
321 @Override
322 public double getMaxDuration() {
323 return fMaxDuration;
324 }
325
326 @Override
327 public List<SubMarker> getSubMarkers() {
328 return fMarker.getSubMarkers();
329 }
330 }
f16950de
PT
331
332 /**
333 * A marker event source has been updated
334 *
335 * @param signal
336 * the signal
337 */
338 @TmfSignalHandler
339 public void markerEventSourceUpdated(final TmfMarkerEventSourceUpdatedSignal signal) {
340 configure(MarkerUtils.getDefaultMarkerSet());
341 }
c1ed0a0c 342}
This page took 0.037777 seconds and 5 git commands to generate.