Commit | Line | Data |
---|---|---|
f95c9345 AM |
1 | /******************************************************************************* |
2 | * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir | |
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 | ||
10 | package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.views; | |
11 | ||
f95c9345 AM |
12 | import java.util.HashSet; |
13 | import java.util.LinkedHashSet; | |
f95c9345 | 14 | import java.util.Set; |
a805f10b | 15 | |
f95c9345 AM |
16 | import org.eclipse.jface.window.Window; |
17 | import org.eclipse.swt.widgets.Composite; | |
682c435f | 18 | import org.eclipse.swt.widgets.Shell; |
f95c9345 AM |
19 | import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiResultTable; |
20 | import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiTableEntry; | |
f95c9345 | 21 | import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.types.LamiTimeRange; |
682c435f GAPG |
22 | import org.eclipse.tracecompass.internal.provisional.tmf.chart.core.chart.ChartData; |
23 | import org.eclipse.tracecompass.internal.provisional.tmf.chart.core.chart.ChartModel; | |
24 | import org.eclipse.tracecompass.internal.provisional.tmf.chart.core.signal.ChartSelectionUpdateSignal; | |
682c435f | 25 | import org.eclipse.tracecompass.internal.provisional.tmf.chart.ui.dialog.ChartMakerDialog; |
f95c9345 AM |
26 | import org.eclipse.tracecompass.tmf.core.component.TmfComponent; |
27 | import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal; | |
28 | import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; | |
29 | import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager; | |
30 | import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp; | |
31 | import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange; | |
32 | import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp; | |
33 | import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; | |
34 | ||
35 | import com.google.common.collect.Iterables; | |
36 | ||
37 | /** | |
38 | * Sub-view of a {@link LamiReportView} that shows the contents of one table of | |
39 | * the analysis report. While it is not a View object directly, its | |
40 | * responsibilities are the same. | |
41 | * | |
42 | * @author Alexandre Montplaisir | |
43 | * @author Jonathan Rajotte-Julien | |
682c435f | 44 | * @author Gabriel-Andrew Pollo-Guilbert |
ea82729d | 45 | * @since 1.1 |
f95c9345 AM |
46 | */ |
47 | public final class LamiReportViewTabPage extends TmfComponent { | |
48 | ||
49 | // ------------------------------------------------------------------------ | |
50 | // Attributes | |
51 | // ------------------------------------------------------------------------ | |
52 | ||
53 | private final LamiResultTable fResultTable; | |
f95c9345 AM |
54 | private final LamiViewerControl fTableViewerControl; |
55 | private final Set<LamiViewerControl> fCustomGraphViewerControls = new LinkedHashSet<>(); | |
56 | private final Composite fControl; | |
57 | ||
682c435f GAPG |
58 | private Set<Object> fSelection; |
59 | ||
f95c9345 AM |
60 | // ------------------------------------------------------------------------ |
61 | // Constructor | |
62 | // ------------------------------------------------------------------------ | |
63 | ||
64 | /** | |
65 | * Constructor | |
66 | * | |
67 | * @param parent | |
68 | * Parent composite | |
69 | * @param table | |
70 | * The result table to display in this tab | |
71 | */ | |
72 | public LamiReportViewTabPage(Composite parent, LamiResultTable table) { | |
73 | super(table.getTableClass().getTableTitle()); | |
682c435f | 74 | |
f95c9345 | 75 | fResultTable = table; |
f95c9345 AM |
76 | |
77 | fControl = parent; | |
78 | ||
682c435f GAPG |
79 | /* Map the current trace selection to our lami entry */ |
80 | fSelection = getEntriesIntersectingTimerange(fResultTable, TmfTraceManager.getInstance().getCurrentTraceContext().getSelectionRange()); | |
81 | ||
f95c9345 | 82 | /* Prepare the table viewer, which is always present */ |
3f506e25 | 83 | LamiViewerControl tableViewerControl = new LamiViewerControl(fControl, this); |
f95c9345 AM |
84 | fTableViewerControl = tableViewerControl; |
85 | ||
86 | /* Automatically open the table viewer initially */ | |
682c435f | 87 | fTableViewerControl.getToggleAction().run(); |
f95c9345 AM |
88 | |
89 | /* Simulate a new external signal to the default viewer */ | |
682c435f GAPG |
90 | ChartSelectionUpdateSignal chartSignal = new ChartSelectionUpdateSignal(this, fResultTable, fSelection); |
91 | TmfSignalManager.dispatchSignal(chartSignal); | |
f95c9345 | 92 | |
682c435f | 93 | /* Dispose this class's resource */ |
f95c9345 | 94 | fControl.addDisposeListener(e -> { |
f95c9345 AM |
95 | fTableViewerControl.dispose(); |
96 | clearAllCustomViewers(); | |
97 | super.dispose(); | |
98 | }); | |
99 | } | |
100 | ||
101 | // ------------------------------------------------------------------------ | |
682c435f | 102 | // Overriden methods |
f95c9345 AM |
103 | // ------------------------------------------------------------------------ |
104 | ||
105 | @Override | |
106 | public void dispose() { | |
682c435f | 107 | /* fControl's listner will dispose other resources */ |
f95c9345 | 108 | fControl.dispose(); |
f95c9345 AM |
109 | } |
110 | ||
682c435f GAPG |
111 | // ------------------------------------------------------------------------ |
112 | // Operations | |
113 | // ------------------------------------------------------------------------ | |
f95c9345 AM |
114 | |
115 | /** | |
682c435f GAPG |
116 | * This method is used for creating a chart from the result table of the |
117 | * analyse. It uses the custom charts plugin to configure and create the | |
118 | * chart. | |
f95c9345 | 119 | */ |
682c435f GAPG |
120 | public void createNewCustomChart() { |
121 | Shell shell = this.getControl().getShell(); | |
122 | if (shell == null) { | |
123 | return; | |
124 | } | |
125 | ||
126 | /* Open the chart maker dialog */ | |
127 | ChartMakerDialog dialog = new ChartMakerDialog(shell, fResultTable); | |
128 | if (dialog.open() != Window.OK) { | |
129 | return; | |
130 | } | |
131 | ||
132 | /* Make sure the data for making a chart was generated */ | |
133 | ChartData data = dialog.getDataSeries(); | |
134 | ChartModel model = dialog.getChartModel(); | |
135 | if (data == null || model == null) { | |
136 | return; | |
137 | } | |
138 | ||
139 | /* Make a chart with the factory constructor */ | |
a805f10b GB |
140 | LamiViewerControl viewerControl = new LamiViewerControl(fControl, data, model); |
141 | fCustomGraphViewerControls.add(viewerControl); | |
142 | viewerControl.getToggleAction().run(); | |
682c435f GAPG |
143 | /* Signal the current selection to the newly created graph */ |
144 | ChartSelectionUpdateSignal signal = new ChartSelectionUpdateSignal(LamiReportViewTabPage.this, | |
145 | fResultTable, fSelection); | |
146 | TmfSignalManager.dispatchSignal(signal); | |
a805f10b GB |
147 | |
148 | ||
f95c9345 AM |
149 | } |
150 | ||
151 | /** | |
152 | * Clear all the custom graph viewers in this tab. | |
153 | */ | |
154 | public void clearAllCustomViewers() { | |
155 | fCustomGraphViewerControls.forEach(LamiViewerControl::dispose); | |
156 | fCustomGraphViewerControls.clear(); | |
157 | } | |
158 | ||
159 | /** | |
160 | * Toggle the display of the table viewer in this tab. This shows it if it | |
161 | * is currently hidden, and vice versa. | |
162 | */ | |
163 | public void toggleTableViewer() { | |
164 | fTableViewerControl.getToggleAction().run(); | |
165 | } | |
166 | ||
682c435f GAPG |
167 | // ------------------------------------------------------------------------ |
168 | // Accessors | |
169 | // ------------------------------------------------------------------------ | |
170 | ||
171 | /** | |
172 | * Get the SWT control associated with this tab page. | |
173 | * | |
174 | * @return The SWT control | |
175 | */ | |
176 | public Composite getControl() { | |
177 | return fControl; | |
178 | } | |
179 | ||
180 | /** | |
181 | * Get the result table shown in this tab. | |
182 | * | |
183 | * @return The report result table | |
184 | */ | |
185 | public LamiResultTable getResultTable() { | |
186 | return fResultTable; | |
187 | } | |
188 | ||
f95c9345 AM |
189 | // ------------------------------------------------------------------------ |
190 | // Signals | |
191 | // ------------------------------------------------------------------------ | |
192 | ||
682c435f GAPG |
193 | // Custom chart signals |
194 | /** | |
195 | * Signal handler for a chart selection update. It will try to propagate a | |
196 | * {@link TmfSelectionRangeUpdatedSignal} if possible. | |
197 | * | |
198 | * @param signal | |
199 | * The selection update signal | |
200 | */ | |
201 | @TmfSignalHandler | |
202 | public void updateSelection(ChartSelectionUpdateSignal signal) { | |
682c435f GAPG |
203 | |
204 | /* Make sure we are not sending a signal to ourself */ | |
205 | if (signal.getSource() == this) { | |
206 | return; | |
207 | } | |
208 | ||
209 | /* Make sure the signal comes from the data provider's scope */ | |
210 | if (fResultTable.hashCode() != signal.getDataProvider().hashCode()) { | |
211 | return; | |
212 | } | |
213 | ||
214 | /* Find which index row has been selected */ | |
215 | Set<Object> entries = signal.getSelectedObject(); | |
216 | ||
682c435f GAPG |
217 | /* Update the selection */ |
218 | fSelection = entries; | |
219 | ||
682c435f GAPG |
220 | /* Only propagate to all TraceCompass if there is a single selection */ |
221 | if (entries.size() == 1) { | |
222 | LamiTableEntry entry = (LamiTableEntry) Iterables.getOnlyElement(entries); | |
223 | ||
224 | /* Make sure the selection represent a time range */ | |
225 | LamiTimeRange timeRange = entry.getCorrespondingTimeRange(); | |
226 | if (timeRange == null) { | |
227 | return; | |
228 | } | |
229 | ||
230 | /* Get the timestamps from the time range */ | |
231 | /** | |
232 | * TODO: Consider low and high limits of timestamps here. | |
233 | */ | |
234 | Number tsBeginValueNumber = timeRange.getBegin().getValue(); | |
235 | Number tsEndValueNumber = timeRange.getEnd().getValue(); | |
236 | if(tsBeginValueNumber == null || tsEndValueNumber == null) { | |
237 | return; | |
238 | } | |
239 | ||
240 | /* Send Range update to other views */ | |
241 | ITmfTimestamp start = TmfTimestamp.fromNanos(tsBeginValueNumber.longValue()); | |
242 | ITmfTimestamp end = TmfTimestamp.fromNanos(tsEndValueNumber.longValue()); | |
243 | TmfSignalManager.dispatchSignal(new TmfSelectionRangeUpdatedSignal(this, start, end)); | |
244 | } | |
245 | ||
246 | } | |
247 | ||
248 | /** | |
249 | * Signal handler for a trace selection range update signal. It will try to | |
250 | * map the external selection to our lami table entry. | |
251 | * | |
252 | * @param signal | |
253 | * The received signal | |
254 | */ | |
255 | @TmfSignalHandler | |
256 | public void externalUpdateSelectionCustomCharts(TmfSelectionRangeUpdatedSignal signal) { | |
257 | /* Make sure we are not sending a signal to ourself */ | |
258 | if (signal.getSource() == this) { | |
259 | return; | |
260 | } | |
261 | ||
262 | TmfTimeRange range = new TmfTimeRange(signal.getBeginTime(), signal.getEndTime()); | |
263 | ||
682c435f GAPG |
264 | // Custom chart signal |
265 | /* Find which lami table entry intersects the signal */ | |
266 | Set<Object> selection = getEntriesIntersectingTimerange(fResultTable, range); | |
267 | ||
268 | /* Update all LamiViewer */ | |
269 | ChartSelectionUpdateSignal updateSignal = new ChartSelectionUpdateSignal(this, fResultTable, selection); | |
270 | TmfSignalManager.dispatchSignal(updateSignal); | |
271 | } | |
272 | ||
273 | // ------------------------------------------------------------------------ | |
274 | // Util methods | |
275 | // ------------------------------------------------------------------------ | |
276 | ||
277 | /** | |
278 | * Util method that returns {@link LamiTableEntry} that intersects a | |
279 | * {@link TmfTimeRange}. | |
280 | * | |
281 | * @param table | |
282 | * The result table to search for entries | |
283 | * @param range | |
284 | * The time range itself | |
285 | * @return The set of entries that intersect with the time range | |
286 | */ | |
287 | private static Set<Object> getEntriesIntersectingTimerange(LamiResultTable table, TmfTimeRange range) { | |
288 | Set<Object> entries = new HashSet<>(); | |
289 | for (LamiTableEntry entry : table.getEntries()) { | |
290 | LamiTimeRange lamiTimeRange = entry.getCorrespondingTimeRange(); | |
291 | ||
292 | /* Make sure the table has time ranges */ | |
293 | if (lamiTimeRange == null) { | |
294 | return entries; | |
295 | } | |
296 | ||
297 | /* Get the timestamps from the time range */ | |
298 | /** | |
299 | * TODO: Consider low and high limits of timestamps here. | |
300 | */ | |
301 | Number tsBeginValueNumber = lamiTimeRange.getBegin().getValue(); | |
302 | Number tsEndValueNumber = lamiTimeRange.getEnd().getValue(); | |
303 | if(tsBeginValueNumber == null || tsEndValueNumber == null) { | |
304 | return entries; | |
305 | } | |
306 | ||
307 | /* Convert the timestamps into TMF timestamps */ | |
308 | ITmfTimestamp start = TmfTimestamp.fromNanos(tsBeginValueNumber.longValue()); | |
309 | ITmfTimestamp end = TmfTimestamp.fromNanos(tsEndValueNumber.longValue()); | |
310 | ||
311 | /* Add iff the time range intersects the the signal */ | |
312 | TmfTimeRange tempTimeRange = new TmfTimeRange(start, end); | |
313 | if (tempTimeRange.getIntersection(range) != null) { | |
314 | entries.add(entry); | |
315 | } | |
316 | } | |
317 | ||
318 | return entries; | |
319 | } | |
f95c9345 | 320 | } |