/*******************************************************************************
- * Copyright (c) 2010 Ericsson
- *
+ * Copyright (c) 2010, 2013 Ericsson
+ *
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
- *
+ *
* Contributors:
* Matthew Khouzam - Initial API and implementation
- * Francois Chouinard - Refactoring, slider support, bug fixing
+ * Francois Chouinard - Refactoring, slider support, bug fixing
* Patrick Tasse - Improvements and bug fixing
* Xavier Raynaud - Improvements
******************************************************************************/
* <p>
* TmfVirtualTable allows for the tabular display of arbitrarily large data sets
* (well, up to Integer.MAX_VALUE or ~2G rows).
- *
+ *
* It is essentially a Composite of Table and Slider, where the number of rows
* in the table is set to fill the table display area. The slider is rank-based.
- *
+ *
* 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
+ * @author Matthew Khouzam, Francois Chouinard, Patrick Tasse, Xavier Raynaud
+ * @version $Revision: 1.0
*/
public class TmfVirtualTable extends Composite {
// The table
+ /**
+ * Field fTable.
+ */
private Table fTable;
+ /**
+ * Field fTableRows.
+ */
private int fTableRows = 0; // Number of table rows
+ /**
+ * Field fFullyVisibleRows.
+ */
private int fFullyVisibleRows = 0; // Number of fully visible table rows
+ /**
+ * Field fFrozenRowCount.
+ */
private int fFrozenRowCount = 0; // Number of frozen table rows at top of table
+ /**
+ * Field fTableTopEventRank.
+ */
private int fTableTopEventRank = 0; // Global rank of the first entry displayed
+ /**
+ * Field fSelectedEventRank.
+ */
private int fSelectedEventRank = 0; // Global rank of the selected event
+ /**
+ * Field fPendingSelection.
+ */
private boolean fPendingSelection = false; // Pending selection update
+ /**
+ * Field fTableItemCount.
+ */
private int fTableItemCount = 0;
// The slider
+ /**
+ * Field fSlider.
+ */
private Slider fSlider;
+ /**
+ * Field fLinuxItemHeight.
+ */
private int fLinuxItemHeight = 0; // Calculated item height for Linux workaround
+ /**
+ * Field tooltipProvider.
+ */
private TooltipProvider tooltipProvider = null;
+ /**
+ * Field doubleClickListener.
+ */
private IDoubleClickListener doubleClickListener = null;
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
/**
+ * Standard constructor
+ *
* @param parent
+ * The parent composite object
* @param style
+ * The style to use
*/
public TmfVirtualTable(Composite parent, int style) {
super(parent, style & (~SWT.H_SCROLL) & (~SWT.V_SCROLL) & (~SWT.SINGLE) & (~SWT.FULL_SELECTION) & (~SWT.HIDE_SELECTION) & (~SWT.CHECK));
case SWT.MouseWheel:
shell.dispose ();
break;
+ default:
+ break;
}
}
};
case SWT.Dispose:
case SWT.KeyDown:
case SWT.MouseMove: {
- if (tip == null) break;
+ if (tip == null) {
+ break;
+ }
tip.dispose ();
tip = null;
label = null;
case SWT.MouseHover: {
TableItem item = fTable.getItem (new Point(event.x, event.y));
if (item != null) {
- for(int i=0;i<fTable.getColumnCount();i++){
+ 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 (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;
+ 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;
}
+ default:
+ break;
}
}
};
@Override
public void controlResized(ControlEvent event) {
resize();
+ if (fTableItemCount > 0) {
+ fSlider.setThumb(Math.max(1, Math.min(fTableRows, fFullyVisibleRows)));
+ }
}
});
/**
* Create the table and add listeners
+ * @param style int can be H_SCROLL, V_SCROLL, SINGLE, CHECK, FULL_SELECTION, HIDE_SELECTION, NO_SCROLL
*/
private void createTable(int style) {
fTable = new Table(this, style | SWT.NO_SCROLL);
display.asyncExec(new Runnable() {
@Override
public void run() {
- if (fTable.isDisposed()) return;
+ if (fTable.isDisposed()) {
+ return;
+ }
int topIndex = fTable.getTopIndex();
if (topIndex != 0) {
fTableTopEventRank += topIndex;
/**
* Handle key-based navigation in table.
- *
+ *
* @param event
*/
private void handleTableKeyEvent(KeyEvent event) {
if (fSelectedEventRank < lastEventRank) {
fSelectedEventRank++;
selectedRow = fSelectedEventRank - fTableTopEventRank;
- if (selectedRow >= fFullyVisibleRows) {
+ if (selectedRow == fFullyVisibleRows) {
fTableTopEventRank++;
needsRefresh = true;
+ } else if (selectedRow < fFrozenRowCount || selectedRow > fFullyVisibleRows) {
+ fTableTopEventRank = Math.max(0, Math.min(fSelectedEventRank - fFrozenRowCount, lastPageTopEntryRank));
+ needsRefresh = true;
}
}
break;
if (fSelectedEventRank > 0) {
fSelectedEventRank--;
selectedRow = fSelectedEventRank - fTableTopEventRank;
- if (selectedRow < fFrozenRowCount && fTableTopEventRank > 0) {
+ if (selectedRow == fFrozenRowCount - 1 && fTableTopEventRank > 0) {
fTableTopEventRank--;
needsRefresh = true;
+ } else if (selectedRow < fFrozenRowCount || selectedRow > fFullyVisibleRows) {
+ fTableTopEventRank = Math.max(0, Math.min(fSelectedEventRank - fFrozenRowCount, lastPageTopEntryRank));
+ needsRefresh = true;
}
}
break;
fSelectedEventRank = lastEventRank;
}
selectedRow = fSelectedEventRank - fTableTopEventRank;
- if (selectedRow > fFullyVisibleRows - 1) {
+ if (selectedRow > fFullyVisibleRows + fFrozenRowCount - 1 && selectedRow < 2 * fFullyVisibleRows) {
fTableTopEventRank += fFullyVisibleRows;
if (fTableTopEventRank > lastPageTopEntryRank) {
fTableTopEventRank = lastPageTopEntryRank;
}
needsRefresh = true;
+ } else if (selectedRow < fFrozenRowCount || selectedRow >= 2 * fFullyVisibleRows) {
+ fTableTopEventRank = Math.max(0, Math.min(fSelectedEventRank - fFrozenRowCount, lastPageTopEntryRank));
+ needsRefresh = true;
}
}
break;
fSelectedEventRank = fFrozenRowCount;
}
selectedRow = fSelectedEventRank - fTableTopEventRank;
- if (selectedRow < 0) {
+ if (selectedRow < fFrozenRowCount && selectedRow > -fFullyVisibleRows) {
fTableTopEventRank -= fFullyVisibleRows;
if (fTableTopEventRank < 0) {
fTableTopEventRank = 0;
}
needsRefresh = true;
+ } else if (selectedRow <= -fFullyVisibleRows || selectedRow >= fFullyVisibleRows) {
+ fTableTopEventRank = Math.max(0, Math.min(fSelectedEventRank - fFrozenRowCount, lastPageTopEntryRank));
+ needsRefresh = true;
}
}
break;
fSlider.setSelection(fTableTopEventRank);
}
- if (fSelectedEventRank != previousSelectedEventRank && fTable.getSelection().length > 0) {
+ if (fSelectedEventRank != previousSelectedEventRank && fSelectedEventRank < fTableItemCount) {
if (done) {
Event e = new Event();
e.item = fTable.getSelection()[0];
}
}
+ /**
+ * Method setDataItem.
+ * @param index int
+ * @param item TableItem
+ * @return boolean
+ */
private boolean setDataItem(int index, TableItem item) {
if (index != -1) {
Event event = new Event();
// Slider handling
// ------------------------------------------------------------------------
+ /**
+ * Method createSlider.
+ * @param style int
+ */
private void createSlider(int style) {
fSlider = new Slider(this, SWT.VERTICAL | SWT.NO_FOCUS);
fSlider.setMinimum(0);
refreshTable();
break;
}
+ default:
+ break;
}
}
});
// Simulated Table API
// ------------------------------------------------------------------------
+ /**
+ * Method setHeaderVisible.
+ * @param b boolean
+ */
public void setHeaderVisible(boolean b) {
fTable.setHeaderVisible(b);
}
+ /**
+ * Method setLinesVisible.
+ * @param b boolean
+ */
public void setLinesVisible(boolean b) {
fTable.setLinesVisible(b);
}
+ /**
+ * Method getSelection.
+ * @return TableItem[] the items that are selected.
+ */
public TableItem[] getSelection() {
return fTable.getSelection();
}
+ /**
+ * Method addListener.
+ * @param eventType int
+ * @param listener Listener
+ */
@Override
public void addListener(int eventType, Listener listener) {
fTable.addListener(eventType, listener);
}
+ /**
+ * Method addKeyListener.
+ * @param listener KeyListener
+ */
@Override
public void addKeyListener(KeyListener listener) {
fTable.addKeyListener(listener);
}
+ /**
+ * Method addMouseListener.
+ * @param listener MouseListener
+ */
@Override
public void addMouseListener(MouseListener listener) {
fTable.addMouseListener(listener);
}
+ /**
+ * Method addSelectionListener.
+ * @param listener SelectionListener
+ */
public void addSelectionListener(SelectionListener listener) {
fTable.addSelectionListener(listener);
}
+ /**
+ * Method setMenu sets the menu
+ * @param menu Menu the menu
+ */
@Override
public void setMenu(Menu menu) {
fTable.setMenu(menu);
}
+ /**
+ * Gets the menu of this table
+ * @return a Menu
+ */
+ @Override
+ public Menu getMenu() {
+ return fTable.getMenu();
+ }
+
+ /**
+ * Method clearAll empties a table.
+ */
public void clearAll() {
setItemCount(0);
}
+ /**
+ * Method setItemCount
+ * @param nbItems int the number of items in the table
+ *
+ */
public void setItemCount(int nbItems) {
- nbItems = Math.max(0, nbItems);
+ final int nb = Math.max(0, nbItems);
- if (nbItems != fTableItemCount) {
- fTableItemCount = nbItems;
+ if (nb != fTableItemCount) {
+ fTableItemCount = nb;
fTable.remove(fTableItemCount, fTable.getItemCount() - 1);
- fSlider.setMaximum(nbItems);
+ fSlider.setMaximum(nb);
resize();
int tableHeight = Math.max(0, fTable.getClientArea().height - fTable.getHeaderHeight());
fFullyVisibleRows = tableHeight / getItemHeight();
}
}
+ /**
+ * Method getItemCount.
+ * @return int the number of items in the table
+ */
public int getItemCount() {
return fTableItemCount;
}
+ /**
+ * Method getItemHeight.
+ * @return int the height of a table item in pixels. (may vary from one os to another)
+ */
public int getItemHeight() {
/*
* Bug in Linux. The method getItemHeight doesn't always return the correct value.
return fTable.getItemHeight();
}
+ /**
+ * Method getHeaderHeight.
+ * @return int get the height of the header in pixels.
+ */
+ public int getHeaderHeight() {
+ return fTable.getHeaderHeight();
+ }
+
+ /**
+ * Method getTopIndex.
+ * @return int get the first data item index, if you have a header it is offset.
+ */
public int getTopIndex() {
return fTableTopEventRank + fFrozenRowCount;
}
- public void setTopIndex(int i) {
+ /**
+ * Method setTopIndex.
+ * @param index int suggested top index for the table.
+ */
+ public void setTopIndex(int index) {
if (fTableItemCount > 0) {
- i = Math.min(i, fTableItemCount - 1);
+ int i = Math.min(index, fTableItemCount - 1);
i = Math.max(i, fFrozenRowCount);
fTableTopEventRank = i - fFrozenRowCount;
}
}
+ /**
+ * Method indexOf. Return the index of a table item
+ * @param ti TableItem the table item to search for in the table
+ * @return int the index of the first match. (there should only be one match)
+ */
public int indexOf(TableItem ti) {
int index = fTable.indexOf(ti);
if (index < fFrozenRowCount) {
return index;
- } else {
- return (index - fFrozenRowCount) + getTopIndex();
}
+ return (index - fFrozenRowCount) + getTopIndex();
}
+ /**
+ * Method getColumns.
+ * @return TableColumn[] the table columns
+ */
public TableColumn[] getColumns() {
return fTable.getColumns();
}
+ /**
+ * Method getItem.
+ * @param point Point the coordinates in the table
+ * @return TableItem the corresponding table item
+ */
public TableItem getItem(Point point) {
return fTable.getItem(point);
}
+ /**
+ * Method resize.
+ */
private void resize() {
// Compute the numbers of rows that fit the new area
int tableHeight = Math.max(0, getSize().y - fTable.getHeaderHeight());
// Controls interactions
// ------------------------------------------------------------------------
+ /**
+ * Method setFocus.
+ * @return boolean is this visible?
+ */
@Override
public boolean setFocus() {
boolean isVisible = isVisible();
return isVisible;
}
+ /**
+ * Method refresh.
+ */
public void refresh() {
boolean done = refreshTable();
if (fPendingSelection && done) {
}
}
+ /**
+ * Method setColumnHeaders.
+ * @param columnData ColumnData[] the columndata array.
+ */
public void setColumnHeaders(ColumnData columnData[]) {
for (int i = 0; i < columnData.length; i++) {
TableColumn column = new TableColumn(fTable, columnData[i].alignment, i);
}
}
+ /**
+ * Method removeAll.
+ * @return int 0 the number of elements in the table
+ */
public int removeAll() {
setItemCount(0);
fSlider.setMaximum(0);
return 0;
}
+ /**
+ * Method refreshTable.
+ * @return boolean did all the items regresh properly?
+ */
private boolean refreshTable() {
boolean done = true;
for (int i = 0; i < fTableRows; i++) {
return done;
}
- public void setSelection(int i) {
+ /**
+ * Method setSelection.
+ * @param index int the item number to select in the table.
+ */
+ public void setSelection(int index) {
if (fTableItemCount > 0) {
- i = Math.min(i, fTableItemCount - 1);
+ int i = Math.min(index, fTableItemCount - 1);
i = Math.max(i, 0);
fSelectedEventRank = i;
if ((i < fTableTopEventRank + fFrozenRowCount && i >= fFrozenRowCount) ||
(i >= fTableTopEventRank + fFullyVisibleRows)) {
- fTableTopEventRank = Math.max(0, i - fFrozenRowCount - fFullyVisibleRows / 2);
+ int lastPageTopEntryRank = Math.max(0, fTableItemCount - fFullyVisibleRows);
+ fTableTopEventRank = Math.max(0, Math.min(lastPageTopEntryRank, i - fFrozenRowCount - fFullyVisibleRows / 2));
}
if (fFullyVisibleRows < fTableItemCount) {
fSlider.setSelection(fTableTopEventRank);
}
}
+ /**
+ * Method getSelectionIndex.
+ * @return int the table index of the selected event. not necessarrily the index of the event due to filtering.
+ */
public int getSelectionIndex() {
int index = fTable.getSelectionIndex();
if (index == -1) {
}
if (index < fFrozenRowCount) {
return index;
- } else {
- return (index - fFrozenRowCount) + getTopIndex();
}
+ return (index - fFrozenRowCount) + getTopIndex();
}
+ /**
+ * Method setFrozenRowCount.
+ * @param count int the number of rows to freeze from the top row
+ */
public void setFrozenRowCount(int count) {
fFrozenRowCount = count;
refreshTable();
}
+ /**
+ * Method createTableEditor.
+ * @return a TableEditor of the table
+ */
public TableEditor createTableEditor() {
return new TableEditor(fTable);
}
+ /**
+ * Method createTableEditorControl.
+ * @param control Class<? extends Control>
+ * @return Control
+ */
public Control createTableEditorControl(Class<? extends Control> control) {
try {
- return (Control) control.getConstructor(Composite.class, int.class).newInstance(new Object[] {fTable, SWT.NONE});
+ return control.getConstructor(Composite.class, int.class).newInstance(new Object[] {fTable, SWT.NONE});
} catch (Exception e) {
Activator.getDefault().logError("Error creating table editor control", e); //$NON-NLS-1$
}
/**
* @return the tooltipProvider
- */
+ */
public TooltipProvider getTooltipProvider() {
return tooltipProvider;
}
/**
* @return the doubleClickListener
- */
+ */
public IDoubleClickListener getDoubleClickListener() {
return doubleClickListener;
}