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