2010-11-09 Francois Chouinard <fchouinard@gmail.com> Contribution for Bug315307
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / viewers / events / TmfEventsTable.java
1 /*******************************************************************************
2 * Copyright (c) 2010 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 * Francois Chouinard - Initial API and implementation
11 * Patrick Tasse - Factored out from events view
12 * Francois Chouinard - Replaced Table by TmfVirtualTable
13 *******************************************************************************/
14
15 package org.eclipse.linuxtools.tmf.ui.viewers.events;
16
17 import org.eclipse.linuxtools.tmf.component.ITmfDataProvider;
18 import org.eclipse.linuxtools.tmf.component.TmfComponent;
19 import org.eclipse.linuxtools.tmf.event.TmfEvent;
20 import org.eclipse.linuxtools.tmf.event.TmfTimestamp;
21 import org.eclipse.linuxtools.tmf.experiment.TmfExperiment;
22 import org.eclipse.linuxtools.tmf.request.ITmfDataRequest.ExecutionType;
23 import org.eclipse.linuxtools.tmf.request.TmfDataRequest;
24 import org.eclipse.linuxtools.tmf.signal.TmfExperimentUpdatedSignal;
25 import org.eclipse.linuxtools.tmf.signal.TmfRangeSynchSignal;
26 import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler;
27 import org.eclipse.linuxtools.tmf.signal.TmfTimeSynchSignal;
28 import org.eclipse.linuxtools.tmf.signal.TmfTraceUpdatedSignal;
29 import org.eclipse.linuxtools.tmf.trace.ITmfTrace;
30 import org.eclipse.linuxtools.tmf.ui.widgets.ColumnData;
31 import org.eclipse.linuxtools.tmf.ui.widgets.TmfVirtualTable;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.events.SelectionAdapter;
34 import org.eclipse.swt.events.SelectionEvent;
35 import org.eclipse.swt.layout.GridData;
36 import org.eclipse.swt.widgets.Composite;
37 import org.eclipse.swt.widgets.Event;
38 import org.eclipse.swt.widgets.Listener;
39 import org.eclipse.swt.widgets.TableColumn;
40 import org.eclipse.swt.widgets.TableItem;
41
42 /**
43 * <b><u>TmfEventsTable</u></b>
44 */
45 public class TmfEventsTable extends TmfComponent {
46
47 // ------------------------------------------------------------------------
48 // Table data
49 // ------------------------------------------------------------------------
50
51 protected TmfVirtualTable fTable;
52 protected ITmfTrace fTrace;
53 protected boolean fPackDone = false;
54
55 // Table column names
56 static private final String TIMESTAMP_COLUMN = "Timestamp";
57 static private final String SOURCE_COLUMN = "Source";
58 static private final String TYPE_COLUMN = "Type";
59 static private final String REFERENCE_COLUMN = "File";
60 static private final String CONTENT_COLUMN = "Content";
61 static private final String[] COLUMN_NAMES = new String[] {
62 TIMESTAMP_COLUMN,
63 SOURCE_COLUMN,
64 TYPE_COLUMN,
65 REFERENCE_COLUMN,
66 CONTENT_COLUMN
67 };
68
69 static private ColumnData[] COLUMN_DATA = new ColumnData[] {
70 new ColumnData(COLUMN_NAMES[0], 100, SWT.LEFT),
71 new ColumnData(COLUMN_NAMES[1], 100, SWT.LEFT),
72 new ColumnData(COLUMN_NAMES[2], 100, SWT.LEFT),
73 new ColumnData(COLUMN_NAMES[3], 100, SWT.LEFT),
74 new ColumnData(COLUMN_NAMES[4], 100, SWT.LEFT)
75 };
76
77 // ------------------------------------------------------------------------
78 // Event cache
79 // ------------------------------------------------------------------------
80
81 private final int fCacheSize;
82 private TmfEvent[] fCache;
83 private int fCacheStartIndex = 0;
84 private int fCacheEndIndex = 0;
85
86 private boolean fDisposeOnClose;
87
88 // ------------------------------------------------------------------------
89 // Constructor
90 // ------------------------------------------------------------------------
91
92 public TmfEventsTable(Composite parent, int cacheSize) {
93 this(parent, cacheSize, COLUMN_DATA);
94 }
95
96 public TmfEventsTable(Composite parent, int cacheSize, ColumnData[] columnData) {
97 super("TmfEventsTable"); //$NON-NLS-1$
98
99 fCacheSize = cacheSize;
100 fCache = new TmfEvent[fCacheSize];
101
102 // Create a virtual table
103 final int style = SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER;
104 fTable = new TmfVirtualTable(parent, style);
105
106 // Set the table layout
107 GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
108 fTable.setLayoutData(layoutData);
109
110 // Some cosmetic enhancements
111 fTable.setHeaderVisible(true);
112 fTable.setLinesVisible(true);
113
114 // Set the columns
115 setColumnHeaders(columnData);
116
117 // Handle the table item requests
118 fTable.addSelectionListener(new SelectionAdapter() {
119 @Override
120 public void widgetSelected(SelectionEvent e) {
121 TmfTimestamp ts = (TmfTimestamp) fTable.getSelection()[0].getData();
122 broadcast(new TmfTimeSynchSignal(fTable, ts));
123 }
124 });
125
126 // Handle the table item requests
127 fTable.addListener(SWT.SetData, new Listener() {
128
129 @Override
130 @SuppressWarnings("unchecked")
131 public void handleEvent(Event event) {
132
133 final TableItem item = (TableItem) event.item;
134 final int index = fTable.indexOf(item);
135
136 // Note: this works because handleEvent() is called once for each row, in sequence
137 if ((index >= fCacheStartIndex) && (index < fCacheEndIndex)) {
138 int i = index - fCacheStartIndex;
139 item.setText(extractItemFields(fCache[i]));
140 item.setData(new TmfTimestamp(fCache[i].getTimestamp()));
141 return;
142 }
143
144 fCacheStartIndex = index;
145 fCacheEndIndex = index;
146
147 TmfDataRequest<TmfEvent> request = new TmfDataRequest<TmfEvent>(TmfEvent.class, index, fCacheSize) {
148 private int count = 0;
149
150 @Override
151 public void handleData(TmfEvent event) {
152 super.handleData(event);
153 if (event != null) {
154 fCache[count++] = event.clone();
155 fCacheEndIndex++;
156 }
157 }
158
159 };
160
161 ((ITmfDataProvider<TmfEvent>) fTrace).sendRequest(request);
162 try {
163 request.waitForCompletion();
164 } catch (InterruptedException e) {
165 e.printStackTrace();
166 }
167
168 if (fCache[0] != null && fCacheStartIndex == index) {
169 item.setText(extractItemFields(fCache[0]));
170 item.setData(new TmfTimestamp(fCache[0].getTimestamp()));
171 packColumns();
172 }
173
174 }
175 });
176
177 fTable.setItemCount(0);
178 }
179
180 @Override
181 public void dispose() {
182 fTable.dispose();
183 if (fTrace != null && fDisposeOnClose) {
184 fTrace.dispose();
185 }
186 super.dispose();
187 }
188
189 public TmfVirtualTable getTable() {
190 return fTable;
191 }
192
193 /**
194 * @param table
195 *
196 * FIXME: Add support for column selection
197 */
198 protected void setColumnHeaders(ColumnData[] columnData) {
199 fTable.setColumnHeaders(columnData);
200 }
201
202 protected void packColumns() {
203 if (fPackDone) return;
204 for (TableColumn column : fTable.getColumns()) {
205 int headerWidth = column.getWidth();
206 column.pack();
207 if (column.getWidth() < headerWidth) {
208 column.setWidth(headerWidth);
209 }
210 }
211 fPackDone = true;
212 }
213
214 /**
215 * @param event
216 * @return
217 *
218 * FIXME: Add support for column selection
219 */
220 protected String[] extractItemFields(TmfEvent event) {
221 String[] fields = new String[0];
222 if (event != null) {
223 fields = new String[] {
224 new Long(event.getTimestamp().getValue()).toString(),
225 event.getSource().getSourceId().toString(),
226 event.getType().getTypeId().toString(),
227 event.getReference().getReference().toString(),
228 event.getContent().toString()
229 };
230 }
231 return fields;
232 }
233
234 public void setFocus() {
235 fTable.setFocus();
236 }
237
238 /**
239 * @param trace
240 * @param disposeOnClose true if the trace should be disposed when the table is disposed
241 */
242 public void setTrace(ITmfTrace trace, boolean disposeOnClose) {
243 if (fTrace != null && fDisposeOnClose) {
244 fTrace.dispose();
245 }
246 fTrace = trace;
247 fDisposeOnClose = disposeOnClose;
248
249 // Perform the updates on the UI thread
250 fTable.getDisplay().syncExec(new Runnable() {
251 @Override
252 public void run() {
253 //fTable.setSelection(0);
254 fTable.removeAll();
255 fCacheStartIndex = fCacheEndIndex = 0; // Clear the cache
256
257 if (!fTable.isDisposed() && fTrace != null) {
258 //int nbEvents = (int) fTrace.getNbEvents();
259 //fTable.setItemCount((nbEvents > 100) ? nbEvents : 100);
260 fTable.setItemCount((int) fTrace.getNbEvents());
261 }
262 }
263 });
264 }
265
266 // ------------------------------------------------------------------------
267 // Signal handlers
268 // ------------------------------------------------------------------------
269
270 @TmfSignalHandler
271 public void experimentUpdated(TmfExperimentUpdatedSignal signal) {
272 if ((signal.getExperiment() != fTrace) || fTable.isDisposed()) return;
273 // Perform the refresh on the UI thread
274 fTable.getDisplay().asyncExec(new Runnable() {
275 @Override
276 public void run() {
277 if (!fTable.isDisposed() && fTrace != null) {
278 fTable.setItemCount((int) fTrace.getNbEvents());
279 fTable.refresh();
280 }
281 }
282 });
283 }
284
285 @TmfSignalHandler
286 public void traceUpdated(TmfTraceUpdatedSignal signal) {
287 if ((signal.getTrace() != fTrace ) || fTable.isDisposed()) return;
288 // Perform the refresh on the UI thread
289 fTable.getDisplay().asyncExec(new Runnable() {
290 @Override
291 public void run() {
292 if (!fTable.isDisposed() && fTrace != null) {
293 //int nbEvents = (int) fTrace.getNbEvents();
294 //fTable.setItemCount((nbEvents > 100) ? nbEvents : 100);
295 fTable.setItemCount((int) fTrace.getNbEvents());
296 }
297 }
298 });
299 }
300
301 private boolean fRefreshPending = false;
302 @TmfSignalHandler
303 public synchronized void rangeSynched(TmfRangeSynchSignal signal) {
304 if (!fRefreshPending && !fTable.isDisposed()) {
305 // Perform the refresh on the UI thread
306 fRefreshPending = true;
307 fTable.getDisplay().asyncExec(new Runnable() {
308 @Override
309 public void run() {
310 fRefreshPending = false;
311 if (!fTable.isDisposed() && fTrace != null) {
312 fTable.setItemCount((int) fTrace.getNbEvents());
313 }
314 }
315 });
316 }
317 }
318
319 @TmfSignalHandler
320 public void currentTimeUpdated(final TmfTimeSynchSignal signal) {
321 if ((signal.getSource() != fTable) && (fTrace != null) && (!fTable.isDisposed())) {
322
323 // Create a request for one event that will be queued after other ongoing requests. When this request is completed
324 // do the work to select the actual event with the timestamp specified in the signal. This procedure prevents
325 // the method fTrace.getRank() from interfering and delaying ongoing requests.
326 final TmfDataRequest<TmfEvent> subRequest = new TmfDataRequest<TmfEvent>(TmfEvent.class, 0, 1, ExecutionType.FOREGROUND) {
327
328 @Override
329 public void handleData(TmfEvent event) {
330 super.handleData(event);
331 }
332
333 @Override
334 public void handleCompleted() {
335 // Get the rank for the event selection in the table
336 final int index = (int) fTrace.getRank(signal.getCurrentTime());
337
338 fTable.getDisplay().asyncExec(new Runnable() {
339 @Override
340 public void run() {
341 // Return if table is disposed
342 if (fTable.isDisposed()) return;
343
344 fTable.setSelection(index);
345 // The timestamp might not correspond to an actual event
346 // and the selection will point to the next experiment event.
347 // But we would like to display both the event before and
348 // after the selected timestamp.
349 // This works fine by default except when the selected event
350 // is the top displayed event. The following ensures that we
351 // always see both events.
352 if ((index > 0) && (index == fTable.getTopIndex())) {
353 fTable.setTopIndex(index - 1);
354 }
355 }
356 });
357 super.handleCompleted();
358 }
359 };
360
361 @SuppressWarnings("unchecked")
362 TmfExperiment<TmfEvent> experiment = (TmfExperiment<TmfEvent>)TmfExperiment.getCurrentExperiment();
363 if (experiment != null) {
364 experiment.sendRequest(subRequest);
365 }
366 }
367 }
368
369 }
This page took 0.038832 seconds and 5 git commands to generate.