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