Commit | Line | Data |
---|---|---|
b9fff7ad | 1 | /******************************************************************************* |
edded5c1 | 2 | * Copyright (c) 2015, 2016 Ericsson |
b9fff7ad BH |
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 | * France Lapointe Nguyen - Initial API and implementation | |
11 | * Bernd Hufmann - Move abstract class to TMF | |
12 | *******************************************************************************/ | |
13 | ||
edded5c1 | 14 | package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table; |
b9fff7ad BH |
15 | |
16 | import org.eclipse.jdt.annotation.Nullable; | |
17 | import org.eclipse.jface.action.Action; | |
18 | import org.eclipse.jface.action.IAction; | |
19 | import org.eclipse.jface.action.IMenuManager; | |
20 | import org.eclipse.jface.viewers.ColumnLabelProvider; | |
21 | import org.eclipse.jface.viewers.IStructuredSelection; | |
22 | import org.eclipse.jface.viewers.StructuredSelection; | |
23 | import org.eclipse.jface.viewers.TableViewer; | |
fce7c48b | 24 | import org.eclipse.swt.SWT; |
b9fff7ad BH |
25 | import org.eclipse.swt.events.SelectionAdapter; |
26 | import org.eclipse.swt.events.SelectionEvent; | |
27 | import org.eclipse.swt.widgets.Display; | |
fce7c48b BH |
28 | import org.eclipse.swt.widgets.Event; |
29 | import org.eclipse.swt.widgets.Listener; | |
30 | import org.eclipse.swt.widgets.TableColumn; | |
b9fff7ad BH |
31 | import org.eclipse.tracecompass.analysis.timing.core.segmentstore.AbstractSegmentStoreAnalysisModule; |
32 | import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener; | |
33 | import org.eclipse.tracecompass.common.core.NonNullUtils; | |
edded5c1 BH |
34 | import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.table.Messages; |
35 | import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.table.SegmentStoreContentProvider; | |
b9fff7ad BH |
36 | import org.eclipse.tracecompass.segmentstore.core.ISegment; |
37 | import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; | |
38 | import org.eclipse.tracecompass.segmentstore.core.SegmentComparators; | |
39 | import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect; | |
40 | import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal; | |
41 | import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; | |
42 | import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager; | |
43 | import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal; | |
44 | import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; | |
45 | import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal; | |
46 | import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp; | |
47 | import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp; | |
48 | import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat; | |
49 | import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; | |
50 | import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; | |
51 | import org.eclipse.tracecompass.tmf.ui.viewers.table.TmfSimpleTableViewer; | |
52 | ||
53 | /** | |
54 | * Displays the segment store analysis data in a column table | |
55 | * | |
56 | * @author France Lapointe Nguyen | |
57 | * @since 2.0 | |
58 | */ | |
59 | public abstract class AbstractSegmentStoreTableViewer extends TmfSimpleTableViewer { | |
60 | ||
61 | // ------------------------------------------------------------------------ | |
62 | // Attributes | |
63 | // ------------------------------------------------------------------------ | |
64 | ||
65 | /** | |
66 | * Abstract class for the column label provider for the segment store | |
67 | * analysis table viewer | |
68 | */ | |
69 | private abstract class SegmentStoreTableColumnLabelProvider extends ColumnLabelProvider { | |
70 | ||
71 | @Override | |
72 | public String getText(@Nullable Object input) { | |
73 | if (!(input instanceof ISegment)) { | |
74 | /* Doubles as a null check */ | |
75 | return ""; //$NON-NLS-1$ | |
76 | } | |
77 | return getTextForSegment((ISegment) input); | |
78 | } | |
79 | ||
80 | public abstract String getTextForSegment(ISegment input); | |
81 | } | |
82 | ||
83 | /** | |
84 | * Listener to update the model with the segment store analysis results | |
85 | * once the analysis is fully completed | |
86 | */ | |
87 | private final class AnalysisProgressListener implements IAnalysisProgressListener { | |
88 | @Override | |
89 | public void onComplete(AbstractSegmentStoreAnalysisModule activeAnalysis, ISegmentStore<ISegment> data) { | |
90 | // Check if the active trace was changed while the analysis was | |
91 | // running | |
92 | if (activeAnalysis.equals(fAnalysisModule)) { | |
93 | updateModel(data); | |
94 | } | |
95 | } | |
96 | } | |
97 | ||
98 | /** | |
99 | * Listener to select a range in other viewers when a cell of the segment | |
100 | * store table view is selected | |
101 | */ | |
102 | private class TableSelectionListener extends SelectionAdapter { | |
103 | @Override | |
104 | public void widgetSelected(@Nullable SelectionEvent e) { | |
105 | ISegment selectedSegment = ((ISegment) NonNullUtils.checkNotNull(e).item.getData()); | |
106 | ITmfTimestamp start = new TmfNanoTimestamp(selectedSegment.getStart()); | |
107 | ITmfTimestamp end = new TmfNanoTimestamp(selectedSegment.getEnd()); | |
108 | TmfSignalManager.dispatchSignal(new TmfSelectionRangeUpdatedSignal(AbstractSegmentStoreTableViewer.this, start, end)); | |
109 | } | |
110 | } | |
111 | ||
112 | /** | |
113 | * Current segment store analysis module | |
114 | */ | |
115 | private @Nullable AbstractSegmentStoreAnalysisModule fAnalysisModule = null; | |
116 | ||
117 | /** | |
118 | * Analysis progress listener | |
119 | */ | |
120 | private AnalysisProgressListener fListener; | |
121 | ||
122 | /** | |
123 | * Flag to create columns once | |
124 | */ | |
125 | boolean fColumnsCreated = false; | |
126 | ||
127 | // ------------------------------------------------------------------------ | |
128 | // Constructor | |
129 | // ------------------------------------------------------------------------ | |
130 | ||
131 | /** | |
132 | * Constructor | |
133 | * | |
134 | * @param tableViewer | |
135 | * Table viewer of the view | |
136 | */ | |
137 | public AbstractSegmentStoreTableViewer(TableViewer tableViewer) { | |
138 | super(tableViewer); | |
139 | // Sort order of the content provider is by start time by default | |
140 | getTableViewer().setContentProvider(new SegmentStoreContentProvider()); | |
141 | ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace(); | |
142 | if (trace != null) { | |
143 | fAnalysisModule = getSegmentStoreAnalysisModule(trace); | |
144 | } | |
145 | createColumns(); | |
146 | getTableViewer().getTable().addSelectionListener(new TableSelectionListener()); | |
fce7c48b | 147 | addPackListener(); |
b9fff7ad BH |
148 | fListener = new AnalysisProgressListener(); |
149 | } | |
150 | ||
151 | // ------------------------------------------------------------------------ | |
152 | // Operations | |
153 | // ------------------------------------------------------------------------ | |
154 | ||
155 | /** | |
156 | * Create default columns for start time, end time and duration | |
157 | */ | |
158 | private void createColumns() { | |
159 | createColumn(Messages.SegmentStoreTableViewer_startTime, new SegmentStoreTableColumnLabelProvider() { | |
160 | @Override | |
161 | public String getTextForSegment(ISegment input) { | |
162 | return NonNullUtils.nullToEmptyString(TmfTimestampFormat.getDefaulTimeFormat().format(input.getStart())); | |
163 | } | |
164 | }, SegmentComparators.INTERVAL_START_COMPARATOR); | |
165 | ||
166 | createColumn(Messages.SegmentStoreTableViewer_endTime, new SegmentStoreTableColumnLabelProvider() { | |
167 | @Override | |
168 | public String getTextForSegment(ISegment input) { | |
169 | return NonNullUtils.nullToEmptyString(TmfTimestampFormat.getDefaulTimeFormat().format(input.getEnd())); | |
170 | } | |
171 | }, SegmentComparators.INTERVAL_END_COMPARATOR); | |
172 | ||
173 | createColumn(Messages.SegmentStoreTableViewer_duration, new SegmentStoreTableColumnLabelProvider() { | |
174 | @Override | |
175 | public String getTextForSegment(ISegment input) { | |
176 | return NonNullUtils.nullToEmptyString(Long.toString(input.getLength())); | |
177 | } | |
178 | }, SegmentComparators.INTERVAL_LENGTH_COMPARATOR); | |
179 | } | |
180 | ||
181 | /** | |
182 | * Create columns specific to the analysis | |
183 | */ | |
184 | protected void createAnalysisColumns() { | |
185 | if (!fColumnsCreated) { | |
186 | AbstractSegmentStoreAnalysisModule analysis = getAnalysisModule(); | |
187 | if (analysis != null) { | |
188 | for (final ISegmentAspect aspect : analysis.getSegmentAspects()) { | |
189 | createColumn(aspect.getName(), new SegmentStoreTableColumnLabelProvider() { | |
190 | @Override | |
191 | public String getTextForSegment(ISegment input) { | |
192 | return NonNullUtils.nullToEmptyString(aspect.resolve(input)); | |
193 | } | |
194 | }, | |
6ad9d1cb | 195 | aspect.getComparator()); |
b9fff7ad BH |
196 | } |
197 | } | |
198 | fColumnsCreated = true; | |
199 | } | |
200 | } | |
201 | ||
202 | /** | |
203 | * Update the data in the table viewer | |
204 | * | |
205 | * @param dataInput | |
206 | * New data input | |
207 | */ | |
bd53eb28 | 208 | public void updateModel(final @Nullable Object dataInput) { |
b9fff7ad BH |
209 | final TableViewer tableViewer = getTableViewer(); |
210 | Display.getDefault().asyncExec(new Runnable() { | |
211 | @Override | |
212 | public void run() { | |
213 | if (!tableViewer.getTable().isDisposed()) { | |
214 | // Go to the top of the table | |
215 | tableViewer.getTable().setTopIndex(0); | |
216 | // Reset selected row | |
217 | tableViewer.setSelection(StructuredSelection.EMPTY); | |
218 | if (dataInput == null) { | |
219 | tableViewer.setInput(null); | |
220 | tableViewer.setItemCount(0); | |
221 | return; | |
222 | } | |
fce7c48b | 223 | addPackListener(); |
b9fff7ad BH |
224 | tableViewer.setInput(dataInput); |
225 | SegmentStoreContentProvider contentProvider = (SegmentStoreContentProvider) getTableViewer().getContentProvider(); | |
226 | tableViewer.setItemCount(contentProvider.getSegmentCount()); | |
227 | } | |
228 | } | |
229 | }); | |
230 | } | |
231 | ||
232 | /** | |
233 | * Set the data into the viewer. Will update model is analysis is completed | |
234 | * or run analysis if not completed | |
235 | * | |
236 | * @param analysis | |
237 | * segment store analysis module | |
238 | */ | |
239 | public void setData(@Nullable AbstractSegmentStoreAnalysisModule analysis) { | |
240 | // Set the current segment store analysis module | |
241 | fAnalysisModule = analysis; | |
242 | if (analysis == null) { | |
243 | updateModel(null); | |
244 | return; | |
245 | } | |
246 | ||
247 | createAnalysisColumns(); | |
248 | ||
249 | ISegmentStore<ISegment> results = analysis.getResults(); | |
250 | // If results are not null, then analysis is completed and model can be | |
251 | // updated | |
252 | if (results != null) { | |
253 | updateModel(results); | |
254 | return; | |
255 | } | |
256 | // If results are null, then add completion listener and run analysis | |
257 | updateModel(null); | |
258 | analysis.addListener(fListener); | |
259 | analysis.schedule(); | |
260 | } | |
261 | ||
262 | /** | |
263 | * Returns the segment store analysis module | |
264 | * @param trace | |
265 | * The trace to consider | |
266 | * @return the segment store analysis module | |
267 | */ | |
268 | protected @Nullable abstract AbstractSegmentStoreAnalysisModule getSegmentStoreAnalysisModule(ITmfTrace trace); | |
269 | ||
270 | @Override | |
271 | protected void appendToTablePopupMenu(IMenuManager manager, IStructuredSelection sel) { | |
272 | final ISegment segment = (ISegment) sel.getFirstElement(); | |
8ef16fe6 BH |
273 | if (segment != null) { |
274 | IAction gotoStartTime = new Action(Messages.SegmentStoreTableViewer_goToStartEvent) { | |
275 | @Override | |
276 | public void run() { | |
277 | broadcast(new TmfSelectionRangeUpdatedSignal(AbstractSegmentStoreTableViewer.this, new TmfNanoTimestamp(segment.getStart()))); | |
278 | } | |
279 | }; | |
b9fff7ad | 280 | |
8ef16fe6 BH |
281 | IAction gotoEndTime = new Action(Messages.SegmentStoreTableViewer_goToEndEvent) { |
282 | @Override | |
283 | public void run() { | |
284 | broadcast(new TmfSelectionRangeUpdatedSignal(AbstractSegmentStoreTableViewer.this, new TmfNanoTimestamp(segment.getEnd()))); | |
285 | } | |
286 | }; | |
b9fff7ad | 287 | |
8ef16fe6 BH |
288 | manager.add(gotoStartTime); |
289 | manager.add(gotoEndTime); | |
290 | } | |
b9fff7ad BH |
291 | } |
292 | ||
293 | // ------------------------------------------------------------------------ | |
294 | // Getters | |
295 | // ------------------------------------------------------------------------ | |
296 | ||
297 | /** | |
298 | * Get current segment store analysis module | |
299 | * | |
300 | * @return current segment store analysis module | |
301 | */ | |
302 | public @Nullable AbstractSegmentStoreAnalysisModule getAnalysisModule() { | |
303 | return fAnalysisModule; | |
304 | } | |
305 | ||
306 | // ------------------------------------------------------------------------ | |
307 | // Signal handlers | |
308 | // ------------------------------------------------------------------------ | |
309 | ||
310 | /** | |
311 | * Trace selected handler | |
312 | * | |
313 | * @param signal | |
314 | * Different opened trace (on which segment store analysis as | |
315 | * already been performed) has been selected | |
316 | */ | |
317 | @TmfSignalHandler | |
318 | public void traceSelected(TmfTraceSelectedSignal signal) { | |
319 | ITmfTrace trace = signal.getTrace(); | |
320 | if (trace != null) { | |
321 | setData(getSegmentStoreAnalysisModule(trace)); | |
322 | } | |
323 | } | |
324 | ||
325 | /** | |
326 | * Trace opened handler | |
327 | * | |
328 | * @param signal | |
329 | * New trace (on which segment store analysis has not been | |
330 | * performed) is opened | |
331 | */ | |
332 | @TmfSignalHandler | |
333 | public void traceOpened(TmfTraceOpenedSignal signal) { | |
334 | ITmfTrace trace = signal.getTrace(); | |
335 | if (trace != null) { | |
336 | setData(getSegmentStoreAnalysisModule(trace)); | |
337 | } | |
338 | } | |
339 | ||
340 | /** | |
341 | * Trace closed handler | |
342 | * | |
343 | * @param signal | |
344 | * Last opened trace was closed | |
345 | */ | |
346 | @TmfSignalHandler | |
347 | public void traceClosed(TmfTraceClosedSignal signal) { | |
348 | // Check if there is no more opened trace | |
349 | if (TmfTraceManager.getInstance().getActiveTrace() == null) { | |
350 | if (!getTableViewer().getTable().isDisposed()) { | |
351 | getTableViewer().setInput(null); | |
0945d5a8 | 352 | getTableViewer().setItemCount(0); |
b9fff7ad BH |
353 | refresh(); |
354 | } | |
76be6c00 BH |
355 | |
356 | AbstractSegmentStoreAnalysisModule analysis = getAnalysisModule(); | |
357 | if ((analysis != null)) { | |
358 | analysis.removeListener(fListener); | |
359 | } | |
b9fff7ad BH |
360 | } |
361 | } | |
fce7c48b BH |
362 | |
363 | // ------------------------------------------------------------------------ | |
364 | // Helper methods | |
365 | // ------------------------------------------------------------------------ | |
b2f6d73d | 366 | |
fce7c48b BH |
367 | /* |
368 | * Add the listener for SetData on the table | |
369 | */ | |
370 | private void addPackListener() { | |
371 | getControl().addListener(SWT.SetData, new Listener() { | |
372 | @Override | |
373 | public void handleEvent(@Nullable Event event) { | |
b2f6d73d PT |
374 | // Remove the listener before the pack |
375 | getControl().removeListener(SWT.SetData, this); | |
376 | ||
fce7c48b BH |
377 | // Pack the column the first time data is set |
378 | TableViewer tableViewer = getTableViewer(); | |
379 | if (tableViewer != null) { | |
380 | for (TableColumn col : tableViewer.getTable().getColumns()) { | |
381 | col.pack(); | |
382 | } | |
fce7c48b BH |
383 | } |
384 | } | |
385 | }); | |
386 | } | |
b9fff7ad | 387 | } |