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