Have you often asked yourself which items are visibile in Table/Tree. Maybe you need these informations to dispose system-resources (e.g. if you have different images in every row you can easily run out of system resources).
What to do? There's no SWT-API available to calculate this information. So we need a bunch of custom code to make this work. The following codefragements are only a first rough test case and they need JFace from 3.3M4 and a patch from
bug 151295 .
Step 1: Setup the infrastructure
- Event object to inform consumers about the change of visible rows
public class ViewerRowStateChangedEvent extends EventObject {
private static final long serialVersionUID = 1L;
public ArrayList itemsHidden;
public ArrayList itemsVisible;
public ViewerRowStateChangedEvent(Object source) {
super(source);
}
}
- ViewerRowStateChangeListener for consumers to implement
public interface ViewerRowStateChangeListener {
public void itemStateChangedListener(ViewerRowStateChangedEvent event);
}
Step 2: Create an AbstractClass implementing the visible row logic on base of ViewerRow and the new API whichn will hopefully added by
bug 151295.
public abstract class AbstractViewerRowVisibilityStateSupport {
private ArrayList currentItems = new ArrayList();
private ColumnViewer columnViewer;
private ListenerList listenerList = new ListenerList();
public AbstractViewerRowVisibilityStateSupport(ColumnViewer columnViewer) {
this.columnViewer = columnViewer;
Listener l = new Listener() {
public void handleEvent(Event event) {
ArrayList list = recalculateVisibleItems();
ArrayList itemsVisible = new ArrayList();
Iterator it = list.iterator();
Object obj;
while( it.hasNext() ) {
obj = it.next();
if( ! currentItems.remove(obj) ) {
itemsVisible.add(obj);
}
}
ArrayList hiddenItems = currentItems;
currentItems = list;
if( itemsVisible.size() > 0 || hiddenItems.size() > 0 ) {
if( ! listenerList.isEmpty() ) {
ColumnViewer v;
v = AbstractViewerRowVisibilityStateSupport.this.columnViewer;
ViewerRowStateChangedEvent ev = new ViewerRowStateChangedEvent(v);
ev.itemsHidden = hiddenItems;
ev.itemsVisible = itemsVisible;
Object[] listeners = listenerList.getListeners();
ViewerRowStateChangeListener l;
for( int i = 0; i < listeners.length; i++ ) {
l = (ViewerRowStateChangeListener)listeners[i];
l.itemStateChangedListener(ev);
}
}
}
}
};
addListeners(getControl(),l);
}
protected abstract void addListeners(Scrollable control, Listener l);
protected abstract ViewerRow getTopRow();
protected Scrollable getControl() {
return (Scrollable)columnViewer.getControl();
}
public void addItemStateListener(ViewerRowStateChangeListener listener) {
listenerList.add(listener);
}
private ArrayList recalculateVisibleItems() {
ArrayList list = new ArrayList(100);
ViewerRow topRow = getTopRow();
if( topRow != null ) {
int totalHeight = getControl().getClientArea().height;
int itemHeight = topRow.getBounds().height;
list.add(topRow);
int tmp = topRow.getBounds().x+itemHeight;
// tmp += itemHeight;
// this would be more precise but half rows
// would be marked as non-visible
// run until we reached the end of the client-area
while( tmp < totalHeight ) {
tmp += itemHeight;
topRow = topRow.getNeighbor(ViewerRow.BELOW, false);
if( topRow == null ) {
break;
}
list.add(topRow);
}
}
return list;
}
}
We simply listen to events who can change the items shown in the Scrollable make a diff to the last state and inform all consumers about the change.
But what are the events how modify the items shown? This is delegated to specialized classes for Table and Tree because those may differ from control to control.
Step 3: Provide specialized implementation for Tree and Table
- An implementation for SWT-Table
public class TableViewerRowVisibilityStateSupport extends
AbstractViewerRowVisibilityStateSupport {
public TableViewerRowVisibilityStateSupport(TableViewer columnViewer) {
super(columnViewer);
}
protected void addListeners(Scrollable control, Listener l) {
control.getVerticalBar().addListener(SWT.Selection, l);
control.addListener(SWT.Resize, l);
control.addListener(SWT.KeyUp, l);
}
protected ViewerRow getTopRow() {
Table t = (Table)getControl();
int index = t.getTopIndex();
TableItem topItem = t.getItem(index);
if( topItem != null ) {
return (ViewerRow) topItem.getData(ViewerRow.ROWPART_KEY);
}
return null;
}
}
- An implementation for SWT-Tree
public class TreeViewerRowVisibilityStateSupport extends
AbstractViewerRowVisibilityStateSupport {
public TreeViewerRowVisibilityStateSupport(TreeViewer columnViewer) {
super(columnViewer);
}
protected void addListeners(Scrollable control, Listener l) {
control.getVerticalBar().addListener(SWT.Selection, l);
control.addListener(SWT.Resize, l);
control.addListener(SWT.MouseUp, l);
control.addListener(SWT.KeyUp, l);
}
protected ViewerRow getTopRow() {
TreeItem topItem = ((Tree)getControl()).getTopItem();
if( topItem != null ) {
return (ViewerRow) topItem.getData(ViewerRow.ROWPART_KEY);
}
return null;
}
}
As said this is very rough first draft how this could work. I'll post this got some coments about possible issues this could provoke.