1 /*******************************************************************************
2 * Copyright (c) 2010 Ericsson
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
10 * Francois Chouinard - Initial API and implementation
11 * Patrick Tasse - Factored out from events view
12 * Francois Chouinard - Replaced Table by TmfVirtualTable
13 *******************************************************************************/
15 package org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.events
;
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
;
43 * <b><u>TmfEventsTable</u></b>
45 public class TmfEventsTable
extends TmfComponent
{
47 // ------------------------------------------------------------------------
49 // ------------------------------------------------------------------------
51 protected TmfVirtualTable fTable
;
52 protected ITmfTrace fTrace
;
53 protected boolean fPackDone
= false;
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
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
)
72 // ------------------------------------------------------------------------
74 // ------------------------------------------------------------------------
76 private final int fCacheSize
;
77 private TmfEvent
[] fCache
;
78 private int fCacheStartIndex
= 0;
79 private int fCacheEndIndex
= 0;
81 private boolean fDisposeOnClose
;
83 // ------------------------------------------------------------------------
85 // ------------------------------------------------------------------------
87 public TmfEventsTable(Composite parent
, int cacheSize
) {
88 this(parent
, cacheSize
, COLUMN_DATA
);
91 public TmfEventsTable(Composite parent
, int cacheSize
, ColumnData
[] columnData
) {
92 super("TmfEventsTable"); //$NON-NLS-1$
94 fCacheSize
= cacheSize
;
95 fCache
= new TmfEvent
[fCacheSize
];
97 // Create a virtual table
98 final int style
= SWT
.SINGLE
| SWT
.FULL_SELECTION
| SWT
.BORDER
;
99 fTable
= new TmfVirtualTable(parent
, style
);
101 // Set the table layout
102 GridData layoutData
= new GridData(SWT
.FILL
, SWT
.FILL
, true, true);
103 fTable
.setLayoutData(layoutData
);
105 // Some cosmetic enhancements
106 fTable
.setHeaderVisible(true);
107 fTable
.setLinesVisible(true);
110 setColumnHeaders(columnData
);
112 // Handle the table item requests
113 fTable
.addSelectionListener(new SelectionAdapter() {
115 public void widgetSelected(SelectionEvent e
) {
116 TmfTimestamp ts
= (TmfTimestamp
) fTable
.getSelection()[0].getData();
117 broadcast(new TmfTimeSynchSignal(fTable
, ts
));
121 // Handle the table item requests
122 fTable
.addListener(SWT
.SetData
, new Listener() {
125 @SuppressWarnings("unchecked")
126 public void handleEvent(Event event
) {
128 final TableItem item
= (TableItem
) event
.item
;
129 final int index
= fTable
.indexOf(item
);
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()));
139 fCacheStartIndex
= index
;
140 fCacheEndIndex
= index
;
142 TmfDataRequest
<TmfEvent
> request
= new TmfDataRequest
<TmfEvent
>(TmfEvent
.class, index
, fCacheSize
) {
143 private int count
= 0;
146 public void handleData(TmfEvent event
) {
147 super.handleData(event
);
149 fCache
[count
++] = event
.clone();
156 ((ITmfDataProvider
<TmfEvent
>) fTrace
).sendRequest(request
);
158 request
.waitForCompletion();
159 } catch (InterruptedException e
) {
163 if (fCache
[0] != null && fCacheStartIndex
== index
) {
164 item
.setText(extractItemFields(fCache
[0]));
165 item
.setData(new TmfTimestamp(fCache
[0].getTimestamp()));
172 fTable
.setItemCount(0);
176 public void dispose() {
178 if (fTrace
!= null && fDisposeOnClose
) {
184 public TmfVirtualTable
getTable() {
191 * FIXME: Add support for column selection
193 protected void setColumnHeaders(ColumnData
[] columnData
) {
194 fTable
.setColumnHeaders(columnData
);
197 protected void packColumns() {
198 if (fPackDone
) return;
199 for (TableColumn column
: fTable
.getColumns()) {
200 int headerWidth
= column
.getWidth();
202 if (column
.getWidth() < headerWidth
) {
203 column
.setWidth(headerWidth
);
213 * FIXME: Add support for column selection
215 protected String
[] extractItemFields(TmfEvent event
) {
216 String
[] fields
= new String
[0];
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()
229 public void setFocus() {
235 * @param disposeOnClose true if the trace should be disposed when the table is disposed
237 public void setTrace(ITmfTrace trace
, boolean disposeOnClose
) {
238 if (fTrace
!= null && fDisposeOnClose
) {
242 fDisposeOnClose
= disposeOnClose
;
244 // Perform the updates on the UI thread
245 fTable
.getDisplay().syncExec(new Runnable() {
248 //fTable.setSelection(0);
250 fCacheStartIndex
= fCacheEndIndex
= 0; // Clear the cache
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());
261 // ------------------------------------------------------------------------
263 // ------------------------------------------------------------------------
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() {
272 if (!fTable
.isDisposed() && fTrace
!= null) {
273 fTable
.setItemCount((int) fTrace
.getNbEvents());
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() {
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());
296 private boolean fRefreshPending
= false;
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() {
305 fRefreshPending
= false;
306 if (!fTable
.isDisposed() && fTrace
!= null) {
307 fTable
.setItemCount((int) fTrace
.getNbEvents());
315 public void currentTimeUpdated(final TmfTimeSynchSignal signal
) {
316 if ((signal
.getSource() != fTable
) && (fTrace
!= null) && (!fTable
.isDisposed())) {
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
) {
324 public void handleData(TmfEvent event
) {
325 super.handleData(event
);
329 public void handleCompleted() {
330 // Get the rank for the event selection in the table
331 final int index
= (int) fTrace
.getRank(signal
.getCurrentTime());
333 fTable
.getDisplay().asyncExec(new Runnable() {
336 // Return if table is disposed
337 if (fTable
.isDisposed()) return;
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);
352 super.handleCompleted();
356 @SuppressWarnings("unchecked")
357 TmfExperiment
<TmfEvent
> experiment
= (TmfExperiment
<TmfEvent
>)TmfExperiment
.getCurrentExperiment();
358 if (experiment
!= null) {
359 experiment
.sendRequest(subRequest
);