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