tmf.core: Introduce TmfTimestamp factory methods
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.timing.ui / src / org / eclipse / tracecompass / analysis / timing / ui / views / segmentstore / table / AbstractSegmentStoreTableViewer.java
1 /*******************************************************************************
2 * Copyright (c) 2015, 2016 Ericsson
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
14 package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table;
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;
24 import org.eclipse.swt.SWT;
25 import org.eclipse.swt.events.SelectionAdapter;
26 import org.eclipse.swt.events.SelectionEvent;
27 import org.eclipse.swt.widgets.Display;
28 import org.eclipse.swt.widgets.Event;
29 import org.eclipse.swt.widgets.Listener;
30 import org.eclipse.swt.widgets.TableColumn;
31 import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener;
32 import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider;
33 import org.eclipse.tracecompass.common.core.NonNullUtils;
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;
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.analysis.IAnalysisModule;
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;
48 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
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 /**
55 * Displays the segment store provider data in a column table
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
68 * provider table viewer
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 /**
85 * Listener to update the model with the segment store provider results once
86 * its store is fully completed
87 */
88 private final class SegmentStoreProviderProgressListener implements IAnalysisProgressListener {
89 @Override
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)) {
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());
107 ITmfTimestamp start = TmfTimestamp.fromNanos(selectedSegment.getStart());
108 ITmfTimestamp end = TmfTimestamp.fromNanos(selectedSegment.getEnd());
109 TmfSignalManager.dispatchSignal(new TmfSelectionRangeUpdatedSignal(AbstractSegmentStoreTableViewer.this, start, end));
110 }
111 }
112
113 /**
114 * Current segment store provider
115 */
116 private @Nullable ISegmentStoreProvider fSegmentProvider = null;
117
118 /**
119 * provider progress listener
120 */
121 private SegmentStoreProviderProgressListener fListener;
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) {
144 fSegmentProvider = getSegmentStoreProvider(trace);
145 }
146 createColumns();
147 getTableViewer().getTable().addSelectionListener(new TableSelectionListener());
148 addPackListener();
149 fListener = new SegmentStoreProviderProgressListener();
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 /**
183 * Create columns specific to the provider
184 */
185 protected void createProviderColumns() {
186 if (!fColumnsCreated) {
187 ISegmentStoreProvider provider = getSegmentProvider();
188 if (provider != null) {
189 for (final ISegmentAspect aspect : provider.getSegmentAspects()) {
190 createColumn(aspect.getName(), new SegmentStoreTableColumnLabelProvider() {
191 @Override
192 public String getTextForSegment(ISegment input) {
193 return NonNullUtils.nullToEmptyString(aspect.resolve(input));
194 }
195 },
196 aspect.getComparator());
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 */
209 public void updateModel(final @Nullable Object dataInput) {
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 }
224 addPackListener();
225 tableViewer.setInput(dataInput);
226 SegmentStoreContentProvider contentProvider = (SegmentStoreContentProvider) getTableViewer().getContentProvider();
227 tableViewer.setItemCount(contentProvider.getSegmentCount());
228 }
229 }
230 });
231 }
232
233 /**
234 * Set the data into the viewer. It will update the model. If the provider
235 * is an analysis, the analysis will be scheduled.
236 *
237 * @param provider
238 * segment store provider
239 */
240 public void setData(@Nullable ISegmentStoreProvider provider) {
241 // Set the current segment store provider
242 fSegmentProvider = provider;
243 if (provider == null) {
244 updateModel(null);
245 return;
246 }
247
248 createProviderColumns();
249
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
253 if (segStore != null) {
254 updateModel(segStore);
255 return;
256 }
257 // If results are null, then add completion listener and if the provider
258 // is an analysis, run the analysis
259 updateModel(null);
260 provider.addListener(fListener);
261 if (provider instanceof IAnalysisModule) {
262 ((IAnalysisModule) provider).schedule();
263 }
264 }
265
266 /**
267 * Returns the segment store provider
268 *
269 * @param trace
270 * The trace to consider
271 * @return the segment store provider
272 */
273 protected @Nullable abstract ISegmentStoreProvider getSegmentStoreProvider(ITmfTrace trace);
274
275 @Override
276 protected void appendToTablePopupMenu(IMenuManager manager, IStructuredSelection sel) {
277 final ISegment segment = (ISegment) sel.getFirstElement();
278 if (segment != null) {
279 IAction gotoStartTime = new Action(Messages.SegmentStoreTableViewer_goToStartEvent) {
280 @Override
281 public void run() {
282 broadcast(new TmfSelectionRangeUpdatedSignal(AbstractSegmentStoreTableViewer.this, TmfTimestamp.fromNanos(segment.getStart())));
283 }
284 };
285
286 IAction gotoEndTime = new Action(Messages.SegmentStoreTableViewer_goToEndEvent) {
287 @Override
288 public void run() {
289 broadcast(new TmfSelectionRangeUpdatedSignal(AbstractSegmentStoreTableViewer.this, TmfTimestamp.fromNanos(segment.getEnd())));
290 }
291 };
292
293 manager.add(gotoStartTime);
294 manager.add(gotoEndTime);
295 }
296 }
297
298 // ------------------------------------------------------------------------
299 // Getters
300 // ------------------------------------------------------------------------
301
302 /**
303 * Get current segment store provider
304 *
305 * @return current segment store provider
306 */
307 public @Nullable ISegmentStoreProvider getSegmentProvider() {
308 return fSegmentProvider;
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) {
326 setData(getSegmentStoreProvider(trace));
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) {
341 setData(getSegmentStoreProvider(trace));
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);
357 getTableViewer().setItemCount(0);
358 refresh();
359 }
360
361 ISegmentStoreProvider provider = getSegmentProvider();
362 if ((provider != null)) {
363 provider.removeListener(fListener);
364 }
365 }
366 }
367
368 // ------------------------------------------------------------------------
369 // Helper methods
370 // ------------------------------------------------------------------------
371
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) {
379 // Remove the listener before the pack
380 getControl().removeListener(SWT.SetData, this);
381
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 }
388 }
389 }
390 });
391 }
392 }
This page took 0.097949 seconds and 5 git commands to generate.