* Contributors:
* Matthew Khouzam - Initial API and implementation
* Francois Chouinard - Refactoring, slider support, bug fixing
+ * Patrick Tasse - Improvements and bug fixing
+ * Xavier Raynaud - Improvements
******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.widgets;
-import org.eclipse.linuxtools.tmf.event.TmfTimestamp;
-import org.eclipse.linuxtools.tmf.signal.TmfSignalManager;
-import org.eclipse.linuxtools.tmf.signal.TmfTimeSynchSignal;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Slider;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.PlatformUI;
/**
* <b><u>TmfVirtualTable</u></b>
*
* It differs from Table with the VIRTUAL style flag where an empty entry is
* created for each virtual row. This does not scale well for very large data sets.
+ *
+ * Styles:
+ * H_SCROLL, V_SCROLL, SINGLE, CHECK, FULL_SELECTION, HIDE_SELECTION, NO_SCROLL
*/
public class TmfVirtualTable extends Composite {
// The table
private Table fTable;
private int fTableRows = 0; // Number of table rows
- private boolean fPartialRowVisible = false; // Indicates that a row is partially displayed
- private int fSelectedRow = 0; // Currently selected row in the table
+ private int fFullyVisibleRows = 0; // Number of fully visible table rows
+ private int fFrozenRowCount = 0; // Number of frozen table rows at top of table
private int fTableTopEventRank = 0; // Global rank of the first entry displayed
private int fSelectedEventRank = 0; // Global rank of the selected event
+ private boolean fPendingSelection = false; // Pending selection update
- private TableItem fSelectedItems[] = new TableItem[1];
private int fTableItemCount = 0;
- private TableItem fTableItems[];
// The slider
private Slider fSlider;
+ private int fLinuxItemHeight = 0; // Calculated item height for Linux workaround
+ private TooltipProvider tooltipProvider = null;
+ private IDoubleClickListener doubleClickListener = null;
+
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
* @param style
*/
public TmfVirtualTable(Composite parent, int style) {
- super(parent, style | SWT.BORDER & (~SWT.H_SCROLL) & (~SWT.V_SCROLL));
+ super(parent, style & (~SWT.H_SCROLL) & (~SWT.V_SCROLL) & (~SWT.SINGLE) & (~SWT.FULL_SELECTION) & (~SWT.HIDE_SELECTION) & (~SWT.CHECK));
// Create the controls
- createTable(style);
- createSlider();
+ createTable(style & (SWT.H_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION | SWT.HIDE_SELECTION | SWT.CHECK));
+ createSlider(style & SWT.V_SCROLL);
+
+ // Prevent the slider from being traversed
+ setTabList(new Control[] { fTable });
// Set the layout
GridLayout gridLayout = new GridLayout();
// Add the listeners
fTable.addMouseWheelListener(new MouseWheelListener() {
+ @Override
public void mouseScrolled(MouseEvent event) {
+ if (fTableItemCount <= fFullyVisibleRows) {
+ return;
+ }
fTableTopEventRank -= event.count;
if (fTableTopEventRank < 0) {
fTableTopEventRank = 0;
}
- int latestFirstRowOffset = fTableItemCount - fTableRows;
+ int latestFirstRowOffset = fTableItemCount - fFullyVisibleRows;
if (fTableTopEventRank > latestFirstRowOffset) {
fTableTopEventRank = latestFirstRowOffset;
}
}
});
+ fTable.addListener(SWT.MouseWheel, new Listener() {
+ // disable mouse scroll of horizontal scroll bar
+ @Override
+ public void handleEvent(Event event) {
+ event.doit = false;
+ }
+ });
+
+ fTable.addControlListener(new ControlAdapter() {
+ @Override
+ public void controlResized(ControlEvent event) {
+ int tableHeight = Math.max(0, fTable.getClientArea().height - fTable.getHeaderHeight());
+ fFullyVisibleRows = tableHeight / getItemHeight();
+ if (fTableItemCount > 0) {
+ fSlider.setThumb(Math.max(1, Math.min(fTableRows, fFullyVisibleRows)));
+ }
+ }
+ });
+ // Implement a "fake" tooltip
+ final String TOOLTIP_DATA_KEY = "_TABLEITEM"; //$NON-NLS-1$
+ final Listener labelListener = new Listener () {
+ @Override
+ public void handleEvent (Event event) {
+ Label label = (Label)event.widget;
+ Shell shell = label.getShell ();
+ switch (event.type) {
+ case SWT.MouseDown:
+ Event e = new Event ();
+ e.item = (TableItem) label.getData (TOOLTIP_DATA_KEY);
+ // Assuming table is single select, set the selection as if
+ // the mouse down event went through to the table
+ fTable.setSelection (new TableItem [] {(TableItem) e.item});
+ fTable.notifyListeners (SWT.Selection, e);
+ shell.dispose ();
+ fTable.setFocus();
+ break;
+ case SWT.MouseExit:
+ case SWT.MouseWheel:
+ shell.dispose ();
+ break;
+ }
+ }
+ };
+
+ Listener tableListener = new Listener () {
+ Shell tip = null;
+ Label label = null;
+ @Override
+ public void handleEvent (Event event) {
+ switch (event.type) {
+ case SWT.Dispose:
+ case SWT.KeyDown:
+ case SWT.MouseMove: {
+ if (tip == null) break;
+ tip.dispose ();
+ tip = null;
+ label = null;
+ break;
+ }
+ case SWT.MouseHover: {
+ TableItem item = fTable.getItem (new Point(event.x, event.y));
+ if (item != null) {
+ for(int i=0;i<fTable.getColumnCount();i++){
+ Rectangle bounds = item.getBounds(i);
+ if (bounds.contains(event.x,event.y)){
+ if (tip != null && !tip.isDisposed()) tip.dispose();
+ if (tooltipProvider == null) {
+ return;
+ } else {
+ String tooltipText = tooltipProvider.getTooltip(i, item.getData());
+ if (tooltipText == null) return;
+ tip = new Shell(fTable.getShell(), SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL);
+ tip.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+ FillLayout layout = new FillLayout();
+ layout.marginWidth = 2;
+ tip.setLayout(layout);
+ label = new Label(tip, SWT.WRAP);
+ label.setForeground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));
+ label.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+ label.setData(TOOLTIP_DATA_KEY, item);
+ label.setText(tooltipText);
+
+ label.addListener(SWT.MouseExit, labelListener);
+ label.addListener(SWT.MouseDown, labelListener);
+ label.addListener(SWT.MouseWheel, labelListener);
+ Point size = tip.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+ Point pt = fTable.toDisplay(bounds.x, bounds.y);
+ tip.setBounds(pt.x, pt.y, size.x, size.y);
+ tip.setVisible(true);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+ fTable.addListener(SWT.Dispose, tableListener);
+ fTable.addListener(SWT.KeyDown, tableListener);
+ fTable.addListener(SWT.MouseMove, tableListener);
+ fTable.addListener(SWT.MouseHover, tableListener);
addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent event) {
resize();
}
- });
+ });
// And display
refresh();
* Create the table and add listeners
*/
private void createTable(int style) {
-
-// int tableStyle = SWT.NO_SCROLL | SWT.H_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION;
- int tableStyle = SWT.NO_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION;
- fTable = new Table(this, tableStyle);
+ fTable = new Table(this, style | SWT.NO_SCROLL);
fTable.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
- handleTableSelection();
+ if (fTable.getSelectionIndices().length > 0) {
+ handleTableSelection();
+ }
}
});
fTable.addKeyListener(new KeyListener() {
+ @Override
public void keyPressed(KeyEvent event) {
handleTableKeyEvent(event);
}
+ @Override
public void keyReleased(KeyEvent event) {
}
});
- }
+
+ fTable.addListener(
+ SWT.MouseDoubleClick, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ if (doubleClickListener != null) {
+ TableItem item = fTable.getItem (new Point (event.x, event.y));
+ if (item != null) {
+ for(int i=0;i<fTable.getColumnCount();i++){
+ Rectangle bounds = item.getBounds(i);
+ if (bounds.contains(event.x,event.y)){
+ doubleClickListener.handleDoubleClick(TmfVirtualTable.this, item, i);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ );
+ }
/**
* Update the rows and selected item
*/
private void handleTableSelection() {
- fSelectedRow = fTable.getSelectionIndices()[0];
- fSelectedEventRank = fTableTopEventRank + fSelectedRow;
- fSelectedItems[0] = fTable.getSelection()[0];
+ int selectedRow = fTable.getSelectionIndices()[0];
+ if (selectedRow < fFrozenRowCount) {
+ fSelectedEventRank = selectedRow;
+ } else {
+ fSelectedEventRank = fTableTopEventRank + selectedRow;
+ }
+
+ /*
+ * Feature in Windows. When a partially visible table item is selected,
+ * after ~500 ms the top index is changed to ensure the selected item is
+ * fully visible. This leaves a blank space at the bottom of the virtual
+ * table. The workaround is to update the top event rank, refresh the
+ * table and reset the top index to 0 after a sufficient delay.
+ */
+ if (selectedRow >= fFullyVisibleRows) {
+ final Display display = fTable.getDisplay();
+ Thread thread = new Thread("Top index check") { //$NON-NLS-1$
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(600);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ display.asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fTable.isDisposed()) return;
+ int topIndex = fTable.getTopIndex();
+ if (topIndex != 0) {
+ fTableTopEventRank += topIndex;
+ refreshTable();
+ fSlider.setSelection(fTableTopEventRank);
+ fTable.setTopIndex(0);
+ }
+ }
+ });
+ }
+ };
+ thread.start();
+ }
}
/**
private void handleTableKeyEvent(KeyEvent event) {
int lastEventRank = fTableItemCount - 1;
- int lastPageTopEntryRank = fTableItemCount - fTableRows;
-
- int lastRowIndex = ((fTableItemCount < fTableRows) ? fTableItemCount : fTableRows) - 1;
- int numberOfFullyVisibleRows = fTableRows - ((fPartialRowVisible) ? 1 : 0);
+ int lastPageTopEntryRank = Math.max(0, fTableItemCount - fFullyVisibleRows);
+ int previousSelectedEventRank = fSelectedEventRank;
+ int selectedRow = fSelectedEventRank - fTableTopEventRank;
boolean needsRefresh = false;
- // We are handling things...
- event.doit = false;
-
// In all case, perform the following steps:
// - Update the selected entry rank (within valid range)
// - Update the selected row
switch (event.keyCode) {
case SWT.ARROW_DOWN: {
+ event.doit = false;
if (fSelectedEventRank < lastEventRank) {
fSelectedEventRank++;
- fSelectedRow = fSelectedEventRank - fTableTopEventRank;
- if (fSelectedRow > lastRowIndex) {
+ selectedRow = fSelectedEventRank - fTableTopEventRank;
+ if (selectedRow >= fFullyVisibleRows) {
fTableTopEventRank++;
- fSelectedRow = lastRowIndex;
needsRefresh = true;
}
}
}
case SWT.ARROW_UP: {
+ event.doit = false;
if (fSelectedEventRank > 0) {
fSelectedEventRank--;
- fSelectedRow = fSelectedEventRank - fTableTopEventRank;
- if (fSelectedRow < 0) {
+ selectedRow = fSelectedEventRank - fTableTopEventRank;
+ if (selectedRow < fFrozenRowCount && fTableTopEventRank > 0) {
fTableTopEventRank--;
- fSelectedRow = 0;
needsRefresh = true;
}
}
}
case SWT.END: {
+ event.doit = false;
fTableTopEventRank = lastPageTopEntryRank;
fSelectedEventRank = lastEventRank;
- fSelectedRow = lastRowIndex;
needsRefresh = true;
break;
}
case SWT.HOME: {
- fSelectedEventRank = 0;
- fSelectedRow = 0;
+ event.doit = false;
+ fSelectedEventRank = fFrozenRowCount;
fTableTopEventRank = 0;
- needsRefresh = true;
+ needsRefresh = true;
break;
}
case SWT.PAGE_DOWN: {
+ event.doit = false;
if (fSelectedEventRank < lastEventRank) {
- fSelectedEventRank += numberOfFullyVisibleRows;
+ fSelectedEventRank += fFullyVisibleRows;
if (fSelectedEventRank > lastEventRank) {
fSelectedEventRank = lastEventRank;
}
- fSelectedRow = fSelectedEventRank - fTableTopEventRank;
- if (fSelectedRow > numberOfFullyVisibleRows - 1) {
- fTableTopEventRank += numberOfFullyVisibleRows;
+ selectedRow = fSelectedEventRank - fTableTopEventRank;
+ if (selectedRow > fFullyVisibleRows - 1) {
+ fTableTopEventRank += fFullyVisibleRows;
if (fTableTopEventRank > lastPageTopEntryRank) {
fTableTopEventRank = lastPageTopEntryRank;
}
- fSelectedRow = fSelectedEventRank - fTableTopEventRank;
needsRefresh = true;
}
}
}
case SWT.PAGE_UP: {
+ event.doit = false;
if (fSelectedEventRank > 0) {
- fSelectedEventRank -= numberOfFullyVisibleRows;
- if (fSelectedEventRank < 0) {
- fSelectedEventRank = 0;
+ fSelectedEventRank -= fFullyVisibleRows;
+ if (fSelectedEventRank < fFrozenRowCount) {
+ fSelectedEventRank = fFrozenRowCount;
}
- fSelectedRow = fSelectedEventRank - fTableTopEventRank;
- if (fSelectedRow < 0) {
- fSelectedRow = 0;
- fTableTopEventRank -= numberOfFullyVisibleRows;
+ selectedRow = fSelectedEventRank - fTableTopEventRank;
+ if (selectedRow < 0) {
+ fTableTopEventRank -= fFullyVisibleRows;
if (fTableTopEventRank < 0) {
fTableTopEventRank = 0;
}
- fSelectedRow = fSelectedEventRank - fTableTopEventRank;
needsRefresh = true;
}
}
break;
}
+ default: {
+ return;
+ }
}
-
+
+ boolean done = true;
if (needsRefresh) {
- for (int i = 0; i < fTableItems.length; i++) {
- setDataItem(i, fTableItems[i]);
- }
+ done = refreshTable(); // false if table items not updated yet in this thread
+ } else {
+ fTable.select(selectedRow);
}
- fSlider.setSelection(fSelectedEventRank);
- fTable.setSelection(fSelectedRow);
- fTable.showSelection();
- fSelectedItems[0] = fTable.getSelection()[0];
+ if (fFullyVisibleRows < fTableItemCount) {
+ fSlider.setSelection(fTableTopEventRank);
+ }
- TmfTimestamp ts = (TmfTimestamp) fSelectedItems[0].getData();
- TmfSignalManager.dispatchSignal(new TmfTimeSynchSignal(this, ts));
+ if (fSelectedEventRank != previousSelectedEventRank && fTable.getSelection().length > 0) {
+ if (done) {
+ Event e = new Event();
+ e.item = fTable.getSelection()[0];
+ fTable.notifyListeners(SWT.Selection, e);
+ } else {
+ fPendingSelection = true;
+ }
+ }
}
- private void setDataItem(int index, TableItem item) {
- if( index != -1) {
+ private boolean setDataItem(int index, TableItem item) {
+ if (index != -1) {
Event event = new Event();
event.item = item;
- event.index = index + fTableTopEventRank;
+ if (index < fFrozenRowCount) {
+ event.index = index;
+ } else {
+ event.index = index + fTableTopEventRank;
+ }
event.doit = true;
- notifyListeners(SWT.SetData, event);
+ fTable.notifyListeners(SWT.SetData, event);
+ return event.doit; // false if table item not updated yet in this thread
}
+ return true;
}
// ------------------------------------------------------------------------
// Slider handling
// ------------------------------------------------------------------------
- private void createSlider() {
- fSlider = new Slider(this, SWT.VERTICAL);
+ private void createSlider(int style) {
+ fSlider = new Slider(this, SWT.VERTICAL | SWT.NO_FOCUS);
fSlider.setMinimum(0);
fSlider.setMaximum(0);
+ if ((style & SWT.V_SCROLL) == 0) {
+ fSlider.setVisible(false);
+ }
fSlider.addListener(SWT.Selection, new Listener() {
+ @Override
public void handleEvent(Event event) {
switch (event.detail) {
case SWT.ARROW_DOWN:
}
public TableItem[] getSelection() {
- return fSelectedItems;
+ return fTable.getSelection();
}
+
+ @Override
+ public void addListener(int eventType, Listener listener) {
+ fTable.addListener(eventType, listener);
+ }
- public void addSelectionListener(SelectionAdapter sa) {
- fTable.addSelectionListener(sa);
- }
+ @Override
+ public void addKeyListener(KeyListener listener) {
+ fTable.addKeyListener(listener);
+ }
+
+
+ @Override
+ public void addMouseListener(MouseListener listener) {
+ fTable.addMouseListener(listener);
+ }
+
+ public void addSelectionListener(SelectionListener listener) {
+ fTable.addSelectionListener(listener);
+ }
+
+ @Override
+ public void setMenu(Menu menu) {
+ fTable.setMenu(menu);
+ }
+
+ public void clearAll() {
+ setItemCount(0);
+ }
public void setItemCount(int nbItems) {
nbItems = Math.max(0, nbItems);
+
if (nbItems != fTableItemCount) {
fTableItemCount = nbItems;
+ fTable.remove(fTableItemCount, fTable.getItemCount() - 1);
fSlider.setMaximum(nbItems);
resize();
+ int tableHeight = Math.max(0, fTable.getClientArea().height - fTable.getHeaderHeight());
+ fFullyVisibleRows = tableHeight / getItemHeight();
+ if (fTableItemCount > 0) {
+ fSlider.setThumb(Math.max(1, Math.min(fTableRows, fFullyVisibleRows)));
+ }
}
}
+ public int getItemCount() {
+ return fTableItemCount;
+ }
+
public int getItemHeight() {
+ /*
+ * Bug in Linux. The method getItemHeight doesn't always return the correct value.
+ */
+ if (fLinuxItemHeight >= 0 && System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
+ if (fLinuxItemHeight != 0) {
+ return fLinuxItemHeight;
+ }
+ if (fTable.getItemCount() > 1) {
+ int itemHeight = fTable.getItem(1).getBounds().y - fTable.getItem(0).getBounds().y;
+ if (itemHeight > 0) {
+ fLinuxItemHeight = itemHeight;
+ return fLinuxItemHeight;
+ }
+ }
+ } else {
+ fLinuxItemHeight = -1; // Not Linux, don't perform os.name check anymore
+ }
return fTable.getItemHeight();
}
public int getTopIndex() {
- return fTableTopEventRank;
+ return fTableTopEventRank + fFrozenRowCount;
}
public void setTopIndex(int i) {
- fSlider.setSelection(i);
+ if (fTableItemCount > 0) {
+ i = Math.min(i, fTableItemCount - 1);
+ i = Math.max(i, fFrozenRowCount);
+
+ fTableTopEventRank = i - fFrozenRowCount;
+ if (fFullyVisibleRows < fTableItemCount) {
+ fSlider.setSelection(fTableTopEventRank);
+ }
+
+ refreshTable();
+ }
}
-
+
public int indexOf(TableItem ti) {
- return fTable.indexOf(ti) + getTopIndex();
+ int index = fTable.indexOf(ti);
+ if (index < fFrozenRowCount) {
+ return index;
+ } else {
+ return (index - fFrozenRowCount) + getTopIndex();
+ }
}
-
+
public TableColumn[] getColumns() {
return fTable.getColumns();
}
+ public TableItem getItem(Point point) {
+ return fTable.getItem(point);
+ }
+
private void resize() {
-
// Compute the numbers of rows that fit the new area
- int tableHeight = fTable.getClientArea().height - fTable.getHeaderHeight();
-
- if (tableHeight < 0) tableHeight = 0;
- int itemHeight = fTable.getItemHeight();
- fTableRows = tableHeight / itemHeight;
- fPartialRowVisible = false;
- if (fTableRows * itemHeight < tableHeight) {
- fTableRows++; // For partial rows
- fPartialRowVisible = true;
- }
- if (fTableRows > fTableItemCount) {
- fTableRows = fTableItemCount;
- }
-
- // If we are at the end, get elements before to populate
- if (fTableTopEventRank + fTableRows >= fTableItemCount) {
- fTableTopEventRank = fTableItemCount - fTableRows;
- }
-
- // Set the slider thumb size
- if (fTableItemCount > 0) {
- fSlider.setThumb(fTableRows);
- }
-
- // Re-size and re-create the virtual table if needed
- int delta = fTable.getItemCount() - fTableRows;
- if (delta != 0) {
- fTable.removeAll();
- if (fTableItems != null) {
- for (int i = 0; i < fTableItems.length; i++) {
- if (fTableItems[i] != null) {
- fTableItems[i].dispose();
- }
- fTableItems[i] = null;
- }
- }
- fTableItems = new TableItem[fTableRows];
- for (int i = 0; i < fTableItems.length; i++) {
- fTableItems[i] = new TableItem(fTable, i);
- }
+ int tableHeight = Math.max(0, getSize().y - fTable.getHeaderHeight());
+ int itemHeight = getItemHeight();
+ fTableRows = Math.min((tableHeight + itemHeight - 1) / itemHeight, fTableItemCount);
+
+ if (fTableTopEventRank + fFullyVisibleRows > fTableItemCount) {
+ // If we are at the end, get elements before to populate
+ fTableTopEventRank = Math.max(0, fTableItemCount - fFullyVisibleRows);
+ refreshTable();
+ } else if (fTableRows > fTable.getItemCount() || fTableItemCount < fTable.getItemCount()) {
+ // Only refresh if new table items are needed or if table items need to be deleted
+ refreshTable();
}
- refresh();
}
// ------------------------------------------------------------------------
}
public void refresh() {
- refreshTable();
+ boolean done = refreshTable();
+ if (fPendingSelection && done) {
+ fPendingSelection = false;
+ if (fTable.getSelection().length > 0) {
+ Event e = new Event();
+ e.item = fTable.getSelection()[0];
+ fTable.notifyListeners(SWT.Selection, e);
+ }
+ }
}
public void setColumnHeaders(ColumnData columnData[]) {
column.pack();
}
}
- }
+ }
public int removeAll() {
+ setItemCount(0);
fSlider.setMaximum(0);
fTable.removeAll();
+ fSelectedEventRank = fFrozenRowCount;
return 0;
}
- private void refreshTable() {
- int lastRowOffset = fTableTopEventRank + fTableRows - 1;
- if ((fSelectedEventRank >= fTableTopEventRank) && (fSelectedEventRank <= lastRowOffset)) {
- fSelectedRow = fSelectedEventRank - fTableTopEventRank;
- fTable.setSelection(fSelectedRow);
- } else {
- fTable.deselect(fSelectedRow);
+ private boolean refreshTable() {
+ boolean done = true;
+ for (int i = 0; i < fTableRows; i++) {
+ if (i + fTableTopEventRank < fTableItemCount) {
+ TableItem tableItem;
+ if (i < fTable.getItemCount()) {
+ tableItem = fTable.getItem(i);
+ } else {
+ tableItem = new TableItem(fTable, SWT.NONE);
+ }
+ done &= setDataItem(i, tableItem); // false if table item not updated yet in this thread
+ } else {
+ if (fTable.getItemCount() > fTableItemCount - fTableTopEventRank) {
+ fTable.remove(fTableItemCount - fTableTopEventRank);
+ }
+ }
}
- for (int i = 0; i < fTableRows; i++) {
- setDataItem(i, fTableItems[i]);
+ int lastRowOffset = fTableTopEventRank + fTableRows - 1;
+ if ((fSelectedEventRank >= fTableTopEventRank + fFrozenRowCount) && (fSelectedEventRank <= lastRowOffset)) {
+ int selectedRow = fSelectedEventRank - fTableTopEventRank;
+ fTable.select(selectedRow);
+ } else if (fSelectedEventRank < fFrozenRowCount) {
+ fTable.select(fSelectedEventRank);
+ } else {
+ fTable.deselectAll();
}
+ return done;
}
public void setSelection(int i) {
- if (fTableItems != null) {
- i = Math.min(i, fTableItemCount);
+ if (fTableItemCount > 0) {
+ i = Math.min(i, fTableItemCount - 1);
i = Math.max(i, 0);
- fSlider.setSelection(i);
fSelectedEventRank = i;
- fTableTopEventRank = i - (fTableRows / 2);
- if (fTableTopEventRank < 0) {
- fTableTopEventRank = 0;
+ if ((i < fTableTopEventRank + fFrozenRowCount && i >= fFrozenRowCount) ||
+ (i >= fTableTopEventRank + fFullyVisibleRows)) {
+ fTableTopEventRank = Math.max(0, i - fFrozenRowCount - fFullyVisibleRows / 2);
+ }
+ if (fFullyVisibleRows < fTableItemCount) {
+ fSlider.setSelection(fTableTopEventRank);
}
- fSelectedRow = fSelectedEventRank - fTableTopEventRank;
-
+
refreshTable();
+
}
}
+ public int getSelectionIndex() {
+ int index = fTable.getSelectionIndex();
+ if (index == -1) {
+ return fSelectedEventRank;
+ }
+ if (index < fFrozenRowCount) {
+ return index;
+ } else {
+ return (index - fFrozenRowCount) + getTopIndex();
+ }
+ }
+
+ public void setFrozenRowCount(int count) {
+ fFrozenRowCount = count;
+ refreshTable();
+ }
+
+ public TableEditor createTableEditor() {
+ return new TableEditor(fTable);
+ }
+
+ public Control createTableEditorControl(Class<? extends Control> control) {
+ try {
+ return (Control) control.getConstructor(Composite.class, int.class).newInstance(new Object[] {fTable, SWT.NONE});
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * @return the tooltipProvider
+ */
+ public TooltipProvider getTooltipProvider() {
+ return tooltipProvider;
+ }
+
+ /**
+ * @param tooltipProvider the tooltipProvider to set
+ */
+ public void setTooltipProvider(TooltipProvider tooltipProvider) {
+ this.tooltipProvider = tooltipProvider;
+ }
+
+ /**
+ * @return the doubleClickListener
+ */
+ public IDoubleClickListener getDoubleClickListener() {
+ return doubleClickListener;
+ }
+
+ /**
+ * @param doubleClickListener the doubleClickListener to set
+ */
+ public void setDoubleClickListener(IDoubleClickListener doubleClickListener) {
+ this.doubleClickListener = doubleClickListener;
+ }
+
}