package edu.ualberta.med.biobank.widgets.infotables;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import edu.ualberta.med.biobank.common.util.ListChangeEvent;
import edu.ualberta.med.biobank.common.util.ListChangeHandler;
import edu.ualberta.med.biobank.gui.common.BgcPlugin;
import edu.ualberta.med.biobank.gui.common.widgets.AbstractInfoTableWidget;
import edu.ualberta.med.biobank.gui.common.widgets.BgcTableSorter;
import edu.ualberta.med.biobank.gui.common.widgets.Messages;
public abstract class InfoTableBgrLoader<T> extends AbstractInfoTableWidget<T> {
@SuppressWarnings("unused")
private final Queue<ListUpdater> updateListQueue =
new LinkedList<ListUpdater>();
private final InfoTableListChangeHandler infoTableListChangeHandler =
new InfoTableListChangeHandler();
private Thread previousThread;
public InfoTableBgrLoader(Composite parent, List<T> list,
String[] headings, int[] columnWidths, int rowsPerPage) {
super(parent, headings, columnWidths, rowsPerPage);
addListChangeHandler(infoTableListChangeHandler);
setList(list);
}
/**
* This method is used to load object model data in the background thread.
*
* @param item the model object representing the base object to get
* information from.
* @return an non-object model object with the table data.
*
* @throws Exception
*/
protected abstract void tableLoader(final List<T> list, final T Selection);
@Override
public synchronized void setList(List<T> collection) {
setList(collection, null);
}
public synchronized void setList(final List<T> list, final T selection) {
if (list == null) return;
final ListUpdater updater = new ListUpdater(list, selection);
final Thread previousThread = this.previousThread;
// set the list here, which sets the delegate, so events fired by the
// delegate can be properly paid attention to or ignored.
super.setList(list);
resizeTable();
Thread thread = new Thread() {
@Override
public void run() {
boolean ran = false;
while (!ran) {
try {
if (previousThread != null) {
// if there is a previous thread, wait until it
// finishes
previousThread.join();
}
ran = true;
updater.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread.start();
this.previousThread = thread;
}
private class ListUpdater implements Runnable {
private final List<T> list;
private final T selection;
private ListUpdater(List<T> list, T selection) {
this.list = list;
this.selection = selection;
}
@Override
public void run() {
try {
final Display display = getTableViewer()
.getTable().getDisplay();
display.syncExec(new Runnable() {
@Override
public void run() {
if (paginationRequired) {
showPaginationWidget();
paginationWidget.setPageLabelText();
enablePaginationWidget(false);
} else if (paginationWidget != null) {
paginationWidget.setVisible(false);
}
tableLoader(list, selection);
if (autoSizeColumns) {
autoSizeColumns();
}
}
});
} catch (Exception e) {
BgcPlugin.openAsyncError(
Messages.AbstractInfoTableWidget_load_error_title, e);
}
}
}
protected abstract void init(List<T> list);
protected abstract void setPaginationParams(List<T> list);
@Override
protected BgcTableSorter getTableSorter() {
// sorting not supported on background loading tables because
// not all rows have been populated on the client side
return null;
}
@Override
public void firstPage() {
setList(getList());
}
@Override
public void lastPage() {
setList(getList());
}
@Override
public void prevPage() {
setList(getList());
}
@Override
public void nextPage() {
setList(getList());
}
@Override
public void reload() {
setList(getList());
}
private class InfoTableListChangeHandler implements ListChangeHandler<T> {
private boolean ignoreEvents = false;
@Override
public void onListChange(ListChangeEvent<T> event) {
// init() may cause ListChangeEvent-s to be fired, so don't listen
// for them when init() is called.
if (!ignoreEvents) {
try {
ignoreEvents = true;
List<T> list = getList();
init(list);
setPaginationParams(list);
} finally {
ignoreEvents = false;
}
}
}
}
}