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