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