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