\r
package org.eclipse.linuxtools.tmf.ui.viewers.events;\r
\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.jobs.Job;\r
import org.eclipse.linuxtools.tmf.component.ITmfDataProvider;\r
import org.eclipse.linuxtools.tmf.component.TmfComponent;\r
import org.eclipse.linuxtools.tmf.event.TmfEvent;\r
import org.eclipse.linuxtools.tmf.signal.TmfTimeSynchSignal;\r
import org.eclipse.linuxtools.tmf.signal.TmfTraceUpdatedSignal;\r
import org.eclipse.linuxtools.tmf.trace.ITmfTrace;\r
+import org.eclipse.linuxtools.tmf.ui.TmfUiPlugin;\r
import org.eclipse.linuxtools.tmf.ui.widgets.ColumnData;\r
import org.eclipse.linuxtools.tmf.ui.widgets.TmfVirtualTable;\r
import org.eclipse.swt.SWT;\r
fTable.addListener(SWT.SetData, new Listener() {\r
\r
@Override\r
- @SuppressWarnings("unchecked")\r
public void handleEvent(Event event) {\r
\r
final TableItem item = (TableItem) event.item;\r
final int index = fTable.indexOf(item);\r
\r
- // Note: this works because handleEvent() is called once for each row, in sequence \r
+ // If available, return the cached data \r
if ((index >= fCacheStartIndex) && (index < fCacheEndIndex)) {\r
int i = index - fCacheStartIndex;\r
item.setText(extractItemFields(fCache[i]));\r
return;\r
}\r
\r
- fCacheStartIndex = index;\r
- fCacheEndIndex = index;\r
-\r
- TmfDataRequest<TmfEvent> request = new TmfDataRequest<TmfEvent>(TmfEvent.class, index, fCacheSize) {\r
- private int count = 0;\r
-\r
- @Override\r
- public void handleData(TmfEvent event) {\r
- super.handleData(event);\r
- if (event != null) {\r
- fCache[count++] = event.clone();\r
- fCacheEndIndex++;\r
- }\r
- }\r
-\r
- };\r
-\r
- ((ITmfDataProvider<TmfEvent>) fTrace).sendRequest(request);\r
- try {\r
- request.waitForCompletion();\r
- } catch (InterruptedException e) {\r
- e.printStackTrace();\r
- }\r
- \r
- if (fCache[0] != null && fCacheStartIndex == index) {\r
- item.setText(extractItemFields(fCache[0]));\r
- item.setData(new TmfTimestamp(fCache[0].getTimestamp()));\r
- packColumns();\r
- }\r
- \r
+ // Else, fill the cache asynchronously (and off the UI thread)\r
+ populateCache(index);\r
}\r
});\r
\r
}\r
}\r
\r
+ // ------------------------------------------------------------------------\r
+ // Event cache population\r
+ // ------------------------------------------------------------------------\r
+ \r
+ // The event fetching job\r
+ private Job job;\r
+\r
+ private synchronized void populateCache(final int index) {\r
+\r
+ /* Check if the current job will fetch the requested event:\r
+ * 1. The job must exist\r
+ * 2. It must be running (i.e. not completed)\r
+ * 3. The requested index must be within the cache range\r
+ * \r
+ * If the job meets these conditions, we simply exit.\r
+ * Otherwise, we create a new job but we might have to cancel\r
+ * an existing job for an obsolete range.\r
+ */\r
+ if (job != null) {\r
+ if (job.getState() != Job.NONE) {\r
+ if (index >= fCacheStartIndex && index < (fCacheStartIndex + fCacheSize)) {\r
+ return;\r
+ }\r
+ // The new index is out of the requested range\r
+ // Kill the job and start a new one\r
+ job.cancel();\r
+ }\r
+ }\r
+ \r
+ fCacheStartIndex = index;\r
+ fCacheEndIndex = index;\r
+\r
+ job = new Job("Fetching Events") { //$NON-NLS-1$\r
+ @Override\r
+ @SuppressWarnings("unchecked")\r
+ protected IStatus run(final IProgressMonitor monitor) {\r
+\r
+ TmfDataRequest<TmfEvent> request = new TmfDataRequest<TmfEvent>(TmfEvent.class, index, fCacheSize) {\r
+ private int count = 0;\r
+ @Override\r
+ public void handleData(TmfEvent event) {\r
+ // If the job is canceled, cancel the request so waitForCompletion() will unlock\r
+ if (monitor.isCanceled()) {\r
+ cancel();\r
+ return;\r
+ }\r
+ super.handleData(event);\r
+ if (event != null) {\r
+ fCache[count++] = event.clone();\r
+ fCacheEndIndex++; // TODO: Need to protect this??\r
+ }\r
+ }\r
+ };\r
+\r
+ ((ITmfDataProvider<TmfEvent>) fTrace).sendRequest(request);\r
+ try {\r
+ request.waitForCompletion();\r
+ } catch (InterruptedException e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+ // Event cache is now updated. Perform update on the UI thread\r
+ if (!fTable.isDisposed() && !monitor.isCanceled()) {\r
+ fTable.getDisplay().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ if (!fTable.isDisposed()) {\r
+ fTable.refresh();\r
+ }\r
+ }\r
+ });\r
+ }\r
+ \r
+ // Flag the UI thread that the cache is ready\r
+ if (monitor.isCanceled()) {\r
+ return new Status(IStatus.CANCEL, TmfUiPlugin.PLUGIN_ID, "Canceled"); //$NON-NLS-1$\r
+ }\r
+ else {\r
+ return new Status(IStatus.OK, TmfUiPlugin.PLUGIN_ID, "Completed"); //$NON-NLS-1$\r
+ }\r
+ }\r
+ };\r
+ job.setPriority(Job.SHORT);\r
+ job.schedule();\r
+ }\r
}\r
setDataItem(i, fTableItems[i]);
}
}
-
- fSlider.setSelection(fSelectedEventRank);
- fTable.setSelection(fSelectedRow);
- fTable.showSelection();
- fSelectedItems[0] = fTable.getSelection()[0];
-
- TmfTimestamp ts = (TmfTimestamp) fSelectedItems[0].getData();
- TmfSignalManager.dispatchSignal(new TmfTimeSynchSignal(this, ts));
- }
-
- private void setDataItem(int index, TableItem item) {
- if( index != -1) {
- Event event = new Event();
- event.item = item;
- event.index = index + fTableTopEventRank;
- event.doit = true;
- notifyListeners(SWT.SetData, event);
+ else {
+ notifyUpdatedSelection();
}
}
+ private void setDataItem(int index, TableItem item) {
+ if( index != -1) {
+ Event event = new Event();
+ event.item = item;
+ event.index = index + fTableTopEventRank;
+ event.doit = true;
+ notifyListeners(SWT.SetData, event);
+ }
+ }
+
+ public void notifyUpdatedSelection() {
+ fSlider.setSelection(fSelectedEventRank);
+ fTable.setSelection(fSelectedRow);
+ fTable.showSelection();
+ TableItem[] tableSelection = fTable.getSelection();
+ if (tableSelection.length > 0 && tableSelection[0] != null) {
+ fSelectedItems[0] = tableSelection[0];
+ TmfTimestamp ts = (TmfTimestamp) fSelectedItems[0].getData();
+ TmfSignalManager.dispatchSignal(new TmfTimeSynchSignal(this, ts));
+ }
+ }
+
// ------------------------------------------------------------------------
// Slider handling
// ------------------------------------------------------------------------
public void refresh() {
refreshTable();
+ notifyUpdatedSelection();
}
public void setColumnHeaders(ColumnData columnData[]) {