Commit | Line | Data |
---|---|---|
abfad0aa FC |
1 | /*******************************************************************************\r |
2 | * Copyright (c) 2010 Ericsson\r | |
3 | * \r | |
4 | * All rights reserved. This program and the accompanying materials are\r | |
5 | * made available under the terms of the Eclipse Public License v1.0 which\r | |
6 | * accompanies this distribution, and is available at\r | |
7 | * http://www.eclipse.org/legal/epl-v10.html\r | |
8 | * \r | |
9 | * Contributors:\r | |
10 | * Francois Chouinard - Initial API and implementation\r | |
11 | * Patrick Tasse - Factored out from events view\r | |
12 | *******************************************************************************/\r | |
13 | \r | |
14 | package org.eclipse.linuxtools.tmf.ui.viewers.events;\r | |
15 | \r | |
16 | import org.eclipse.linuxtools.tmf.component.ITmfDataProvider;\r | |
17 | import org.eclipse.linuxtools.tmf.component.TmfComponent;\r | |
18 | import org.eclipse.linuxtools.tmf.event.TmfEvent;\r | |
19 | import org.eclipse.linuxtools.tmf.event.TmfTimestamp;\r | |
20 | import org.eclipse.linuxtools.tmf.request.TmfDataRequest;\r | |
21 | import org.eclipse.linuxtools.tmf.signal.TmfExperimentUpdatedSignal;\r | |
22 | import org.eclipse.linuxtools.tmf.signal.TmfRangeSynchSignal;\r | |
23 | import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler;\r | |
24 | import org.eclipse.linuxtools.tmf.signal.TmfTimeSynchSignal;\r | |
25 | import org.eclipse.linuxtools.tmf.signal.TmfTraceUpdatedSignal;\r | |
26 | import org.eclipse.linuxtools.tmf.trace.ITmfTrace;\r | |
27 | import org.eclipse.swt.SWT;\r | |
28 | import org.eclipse.swt.events.SelectionAdapter;\r | |
29 | import org.eclipse.swt.events.SelectionEvent;\r | |
30 | import org.eclipse.swt.layout.GridData;\r | |
31 | import org.eclipse.swt.widgets.Composite;\r | |
32 | import org.eclipse.swt.widgets.Event;\r | |
33 | import org.eclipse.swt.widgets.Listener;\r | |
34 | import org.eclipse.swt.widgets.Table;\r | |
35 | import org.eclipse.swt.widgets.TableColumn;\r | |
36 | import org.eclipse.swt.widgets.TableItem;\r | |
37 | \r | |
38 | /**\r | |
39 | * <b><u>TmfEventsTable</u></b>\r | |
40 | */\r | |
41 | public class TmfEventsTable extends TmfComponent {\r | |
42 | \r | |
43 | // private Shell fShell;\r | |
44 | \r | |
45 | // ------------------------------------------------------------------------\r | |
46 | // Table data\r | |
47 | // ------------------------------------------------------------------------\r | |
48 | \r | |
49 | protected Table fTable;\r | |
50 | protected ITmfTrace fTrace;\r | |
51 | protected boolean fPackDone = false;\r | |
52 | \r | |
53 | // Table column names\r | |
54 | private final String TIMESTAMP_COLUMN = "Timestamp";\r | |
55 | private final String SOURCE_COLUMN = "Source";\r | |
56 | private final String TYPE_COLUMN = "Type";\r | |
57 | private final String REFERENCE_COLUMN = "File";\r | |
58 | private final String CONTENT_COLUMN = "Content";\r | |
59 | private final String[] columnProperties = new String[] {\r | |
60 | TIMESTAMP_COLUMN,\r | |
61 | SOURCE_COLUMN,\r | |
62 | TYPE_COLUMN,\r | |
63 | REFERENCE_COLUMN,\r | |
64 | CONTENT_COLUMN\r | |
65 | };\r | |
66 | \r | |
67 | // Column data\r | |
68 | private class ColumnData {\r | |
69 | public final String header;\r | |
70 | public final int width;\r | |
71 | public final int alignment;\r | |
72 | \r | |
73 | public ColumnData(String h, int w, int a) {\r | |
74 | header = h;\r | |
75 | width = w;\r | |
76 | alignment = a;\r | |
77 | }\r | |
78 | };\r | |
79 | \r | |
80 | private ColumnData[] columnData = new ColumnData[] {\r | |
81 | new ColumnData(columnProperties[0], 100, SWT.LEFT),\r | |
82 | new ColumnData(columnProperties[1], 100, SWT.LEFT),\r | |
83 | new ColumnData(columnProperties[2], 100, SWT.LEFT),\r | |
84 | new ColumnData(columnProperties[3], 100, SWT.LEFT),\r | |
85 | new ColumnData(columnProperties[4], 100, SWT.LEFT)\r | |
86 | };\r | |
87 | \r | |
88 | // ------------------------------------------------------------------------\r | |
89 | // Event cache\r | |
90 | // ------------------------------------------------------------------------\r | |
91 | \r | |
92 | private final int fCacheSize;\r | |
93 | private TmfEvent[] cache = new TmfEvent[1];\r | |
94 | private int cacheStartIndex = 0;\r | |
95 | private int cacheEndIndex = 0;\r | |
96 | // private IResourceChangeListener fResourceChangeListener;\r | |
97 | \r | |
98 | // ------------------------------------------------------------------------\r | |
99 | // Constructor\r | |
100 | // ------------------------------------------------------------------------\r | |
101 | \r | |
102 | public TmfEventsTable(Composite parent, int cacheSize) {\r | |
103 | super("TmfEventsTable");\r | |
104 | \r | |
105 | fCacheSize = cacheSize;\r | |
106 | \r | |
107 | // fShell = parent.getShell();\r | |
108 | \r | |
109 | // Create a virtual table\r | |
110 | // TODO: change SINGLE to MULTI line selection and adjust the selection listener\r | |
111 | final int style = SWT.SINGLE | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.VIRTUAL;\r | |
112 | fTable = new Table(parent, style);\r | |
113 | \r | |
114 | // Set the table layout\r | |
115 | GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);\r | |
116 | fTable.setLayoutData(layoutData);\r | |
117 | \r | |
118 | // Some cosmetic enhancements\r | |
119 | fTable.setHeaderVisible(true);\r | |
120 | fTable.setLinesVisible(true);\r | |
121 | \r | |
122 | // Set the columns\r | |
123 | createColumnHeaders(fTable);\r | |
124 | \r | |
125 | // Handle the table item requests \r | |
126 | fTable.addSelectionListener(new SelectionAdapter() {\r | |
127 | \r | |
128 | @Override\r | |
129 | public void widgetSelected(SelectionEvent e) {\r | |
130 | TmfTimestamp ts = (TmfTimestamp) fTable.getSelection()[0].getData();\r | |
131 | broadcast(new TmfTimeSynchSignal(fTable, ts));\r | |
132 | }\r | |
133 | });\r | |
134 | \r | |
135 | // Handle the table item requests \r | |
136 | fTable.addListener(SWT.SetData, new Listener() {\r | |
137 | \r | |
138 | @SuppressWarnings("unchecked")\r | |
139 | public void handleEvent(Event event) {\r | |
140 | \r | |
141 | final TableItem item = (TableItem) event.item;\r | |
142 | final int index = fTable.indexOf(item);\r | |
143 | \r | |
144 | // Note: this works because handleEvent() is called once for each row, in sequence \r | |
145 | if ((index >= cacheStartIndex ) && (index < cacheEndIndex)) {\r | |
146 | int i = index - cacheStartIndex;\r | |
147 | item.setText(extractItemFields(cache[i]));\r | |
148 | item.setData(new TmfTimestamp(cache[i].getTimestamp()));\r | |
149 | return;\r | |
150 | }\r | |
151 | \r | |
152 | TmfDataRequest<TmfEvent> request = new TmfDataRequest<TmfEvent>(TmfEvent.class, index, fCacheSize) {\r | |
153 | @Override\r | |
154 | public void handleData() {\r | |
155 | TmfEvent[] tmpEvent = getData();\r | |
156 | if ((tmpEvent != null) && (tmpEvent.length > 0)) {\r | |
157 | cache = tmpEvent;\r | |
158 | cacheStartIndex = index;\r | |
159 | cacheEndIndex = index + tmpEvent.length;\r | |
160 | }\r | |
161 | }\r | |
162 | };\r | |
163 | ((ITmfDataProvider<TmfEvent>) fTrace).sendRequest(request);\r | |
164 | try {\r | |
165 | request.waitForCompletion();\r | |
166 | } catch (InterruptedException e) {\r | |
167 | e.printStackTrace();\r | |
168 | }\r | |
169 | \r | |
170 | if (cache[0] != null && cacheStartIndex == index) {\r | |
171 | item.setText(extractItemFields(cache[0]));\r | |
172 | item.setData(new TmfTimestamp(cache[0].getTimestamp()));\r | |
173 | packColumns(fTable);\r | |
174 | }\r | |
175 | \r | |
176 | }\r | |
177 | });\r | |
178 | \r | |
179 | fTable.setItemCount(0);\r | |
180 | }\r | |
181 | \r | |
182 | public void dispose() {\r | |
183 | fTable.dispose();\r | |
184 | if (fTrace != null) {\r | |
185 | fTrace.dispose();\r | |
186 | }\r | |
187 | super.dispose();\r | |
188 | }\r | |
189 | \r | |
190 | public Table getTable() {\r | |
191 | return fTable;\r | |
192 | }\r | |
193 | \r | |
194 | /**\r | |
195 | * @param table\r | |
196 | * \r | |
197 | * FIXME: Add support for column selection\r | |
198 | */\r | |
78c0de16 | 199 | protected void createColumnHeaders(Table table) {\r |
abfad0aa FC |
200 | for (int i = 0; i < columnData.length; i++) {\r |
201 | TableColumn column = new TableColumn(table, columnData[i].alignment, i);\r | |
202 | column.setText(columnData[i].header);\r | |
203 | column.setWidth(columnData[i].width);\r | |
204 | }\r | |
205 | }\r | |
206 | \r | |
207 | protected void packColumns(Table table) {\r | |
208 | if (fPackDone) return;\r | |
209 | for (TableColumn column : fTable.getColumns()) {\r | |
210 | int headerWidth = column.getWidth();\r | |
211 | column.pack();\r | |
212 | if (column.getWidth() < headerWidth) {\r | |
213 | column.setWidth(headerWidth);\r | |
214 | }\r | |
215 | }\r | |
216 | fPackDone = true;\r | |
217 | }\r | |
218 | \r | |
219 | /**\r | |
220 | * @param event\r | |
221 | * @return\r | |
222 | * \r | |
223 | * FIXME: Add support for column selection\r | |
224 | */\r | |
78c0de16 | 225 | protected String[] extractItemFields(TmfEvent event) {\r |
abfad0aa FC |
226 | String[] fields = new String[0];\r |
227 | if (event != null) {\r | |
228 | fields = new String[] {\r | |
229 | new Long(event.getTimestamp().getValue()).toString(), \r | |
230 | event.getSource().getSourceId().toString(),\r | |
231 | event.getType().getTypeId().toString(),\r | |
232 | event.getReference().getReference().toString(),\r | |
233 | event.getContent().toString()\r | |
234 | };\r | |
235 | }\r | |
236 | return fields;\r | |
237 | }\r | |
238 | \r | |
239 | public void setFocus() {\r | |
240 | fTable.setFocus();\r | |
241 | }\r | |
242 | \r | |
243 | public void setTrace(ITmfTrace trace) {\r | |
244 | fTrace = trace;\r | |
245 | \r | |
246 | // Perform the updates on the UI thread\r | |
247 | fTable.getDisplay().syncExec(new Runnable() {\r | |
248 | public void run() {\r | |
249 | //fTable.setSelection(0); PATA\r | |
250 | fTable.removeAll();\r | |
251 | cacheStartIndex = cacheEndIndex = 0; // Clear the cache\r | |
252 | \r | |
253 | if (!fTable.isDisposed() && fTrace != null) {\r | |
254 | //int nbEvents = (int) fTrace.getNbEvents();\r | |
255 | //fTable.setItemCount((nbEvents > 100) ? nbEvents : 100);\r | |
256 | fTable.setItemCount((int) fTrace.getNbEvents());\r | |
257 | }\r | |
258 | }\r | |
259 | });\r | |
260 | // ProgressMonitorDialog dialog = new ProgressMonitorDialog(fShell);\r | |
261 | // try {\r | |
262 | // dialog.run(false, false, new IRunnableWithProgress() {\r | |
263 | // public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {\r | |
264 | // monitor.beginTask("Cleaning up, please wait", 0);\r | |
265 | //\r | |
266 | //\r | |
267 | // monitor.done();\r | |
268 | // }\r | |
269 | // });\r | |
270 | // } catch (InvocationTargetException e) {\r | |
271 | // } catch (InterruptedException e) {\r | |
272 | // }\r | |
273 | }\r | |
274 | \r | |
275 | // ------------------------------------------------------------------------\r | |
276 | // Signal handlers\r | |
277 | // ------------------------------------------------------------------------\r | |
278 | \r | |
279 | @TmfSignalHandler\r | |
280 | public void experimentUpdated(TmfExperimentUpdatedSignal signal) {\r | |
281 | if (signal.getExperiment() != fTrace) return;\r | |
282 | // Perform the refresh on the UI thread\r | |
283 | fTable.getDisplay().asyncExec(new Runnable() {\r | |
284 | public void run() {\r | |
285 | if (!fTable.isDisposed() && fTrace != null) {\r | |
286 | fTable.setItemCount((int) fTrace.getNbEvents());\r | |
287 | }\r | |
288 | }\r | |
289 | });\r | |
290 | }\r | |
291 | \r | |
292 | @TmfSignalHandler\r | |
293 | public void traceUpdated(TmfTraceUpdatedSignal signal) {\r | |
294 | if (signal.getTrace() != fTrace) return;\r | |
295 | // Perform the refresh on the UI thread\r | |
296 | fTable.getDisplay().asyncExec(new Runnable() {\r | |
297 | public void run() {\r | |
298 | if (!fTable.isDisposed() && fTrace != null) {\r | |
299 | //int nbEvents = (int) fTrace.getNbEvents();\r | |
300 | //fTable.setItemCount((nbEvents > 100) ? nbEvents : 100);\r | |
301 | fTable.setItemCount((int) fTrace.getNbEvents());\r | |
302 | }\r | |
303 | }\r | |
304 | });\r | |
305 | }\r | |
306 | \r | |
307 | private boolean fRefreshPending = false;\r | |
308 | @TmfSignalHandler\r | |
309 | public synchronized void rangeSynched(TmfRangeSynchSignal signal) {\r | |
310 | if (!fRefreshPending) {\r | |
311 | // Perform the refresh on the UI thread\r | |
312 | fRefreshPending = true;\r | |
313 | fTable.getDisplay().asyncExec(new Runnable() {\r | |
314 | public void run() {\r | |
315 | fRefreshPending = false;\r | |
316 | if (!fTable.isDisposed() && fTrace != null) {\r | |
317 | fTable.setItemCount((int) fTrace.getNbEvents());\r | |
318 | }\r | |
319 | }\r | |
320 | });\r | |
321 | }\r | |
322 | }\r | |
323 | \r | |
324 | @TmfSignalHandler\r | |
325 | public void currentTimeUpdated(TmfTimeSynchSignal signal) {\r | |
326 | if (signal.getSource() != fTable && fTrace != null) {\r | |
327 | final int index = (int) fTrace.getRank(signal.getCurrentTime());\r | |
328 | // Perform the updates on the UI thread\r | |
329 | fTable.getDisplay().asyncExec(new Runnable() {\r | |
330 | public void run() {\r | |
331 | fTable.setSelection(index);\r | |
332 | // The timestamp might not correspond to an actual event\r | |
333 | // and the selection will point to the next experiment event.\r | |
334 | // But we would like to display both the event before and\r | |
335 | // after the selected timestamp.\r | |
336 | // This works fine by default except when the selected event\r | |
337 | // is the top displayed event. The following ensures that we\r | |
338 | // always see both events.\r | |
339 | if ((index > 0) && (index == fTable.getTopIndex())) {\r | |
340 | fTable.setTopIndex(index - 1);\r | |
341 | }\r | |
342 | }\r | |
343 | });\r | |
344 | }\r | |
345 | }\r | |
346 | }\r |