package com.netifera.platform.ui.updater;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.eclipse.jface.viewers.AbstractTableViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.widgets.Table;
public class TableUpdater extends ControlUpdater {
private final AbstractTableViewer tableViewer;
private Object newInput;
private Object currentInput;
private volatile boolean refresh;
private volatile boolean setInput;
private volatile boolean clear;
private boolean setItemCount;
private int itemCount;
private boolean autoScroll = true;
//TODO: the use of ConcurrentMap seems pointless, we are using synchronized() locking, but
// changing it to TreeMap or HashMap seems to be worst. investigate it with more time.
private final ConcurrentMap<Integer, Object> indexToElement = new ConcurrentHashMap<Integer, Object>();
/* private constructor to force to use the get method */
private TableUpdater(AbstractTableViewer tableViewer) {
super(tableViewer.getControl());
this.tableViewer = tableViewer;
currentInput = tableViewer.getInput();
}
/*
* Updater must be created with this method to avoid creating more than one
* wrapper for the same viewer control
*/
public static TableUpdater get(AbstractTableViewer tableViewer) {
ControlUpdater controlUpdater = ControlUpdater.get(tableViewer.getControl());
/* return existing updater */
if(controlUpdater instanceof TableUpdater) {
return (TableUpdater)controlUpdater;
}
/* the existing updater is of different class */
if(controlUpdater != null) {
throw new IllegalArgumentException("The control has a registered updater of different class.");
}
/* create, register and return a new updater */
return new TableUpdater(tableViewer);
}
/**
* updateControl() is synchronized and is executed in the UI thread, content
* providers calling TableUpdater methods will be blocked while this method
* executes. And the UI thread will be blocked while content providers
* invoke this updater methods below.
*/
protected void updateControl() {
synchronized(this) {
if(checkDisposed()) {
return;
}
tableViewer.getControl().setRedraw(false);
/* .clear() */
if (clear) {
itemCount = 0;
indexToElement.clear();
clear = false;
tableViewer.setItemCount(itemCount);
}
/* .setInput() */
if (setInput) {
currentInput = newInput;
newInput = null;
setInput = false;
tableViewer.setInput(currentInput);
}
/* .setItemCount() */
if (setItemCount) {
tableViewer.setItemCount(itemCount);
if (autoScroll && (tableViewer instanceof TableViewer)) {
Table table = ((TableViewer)tableViewer).getTable();
/* int clientHeight = table.getClientArea().height;
if (table.getHeaderVisible())
clientHeight -= table.getHeaderHeight();
int visibleCount = (clientHeight + table.getItemHeight() - 1) / table.getItemHeight();
if (visibleCount > 0)
table.setTopIndex(itemCount - (itemCount < visibleCount ? itemCount : visibleCount));
*/ table.setTopIndex(itemCount - 1);
}
setItemCount = false;
}
/* .refresh() */
if(refresh) {
refresh = false;
tableViewer.refresh();
}
/* ILazyContentProvider updateElement() */
for (Entry<Integer, Object> e : indexToElement.entrySet()) {
tableViewer.replace(e.getValue(), e.getKey());
indexToElement.remove(e.getKey());
}
tableViewer.getControl().setRedraw(true);
}/* synchronized block ends here */
}
/* the following methods are called from content providers */
public synchronized void refresh() {
refresh = true;
indexToElement.clear();
scheduleUpdate();
}
public void clear() {
clear = true;
scheduleUpdate();
}
public synchronized void setInput(Object input) {
if (input == null || !input.equals(this.currentInput)) {
indexToElement.clear();
clear = true;
newInput = input;
setInput = true;
refresh = true;//XXX necessary?
scheduleUpdate();
}
}
public void replace(Object element, int index) {
// XXX if newInput is set should ignore?
if(element == null) {
return;
}
indexToElement.put(index, element);
scheduleUpdate();
}
public synchronized void setItemCount(int itemCount) {
if(this.itemCount == itemCount) {
return;
}
if (itemCount == 0) {
indexToElement.clear();
}
this.itemCount = itemCount;
setItemCount = true;
scheduleUpdate();
}
public void setAutoScroll(boolean autoScroll) {
this.autoScroll = autoScroll;
}
public boolean getAutoScroll() {
return autoScroll;
}
}