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