package edu.ualberta.med.biobank.widgets.trees.infos; import java.util.List; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; 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.Text; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import edu.ualberta.med.biobank.gui.common.BgcPlugin; import edu.ualberta.med.biobank.gui.common.widgets.BgcBaseWidget; import edu.ualberta.med.biobank.gui.common.widgets.BgcLabelProvider; import edu.ualberta.med.biobank.gui.common.widgets.utils.BgcClipboard; import edu.ualberta.med.biobank.treeview.Node; public abstract class AbstractInfoTreeWidget<T> extends BgcBaseWidget { class PageInformation { int page; int rowsPerPage; int pageTotal; } protected TreeViewer treeViewer; protected Thread backgroundThread; protected Menu menu; protected boolean paginationRequired; protected Composite paginationWidget; protected PageInformation pageInfo; protected Button firstButton; protected Button lastButton; protected Button prevButton; protected Button nextButton; protected Label pageLabel; private List<T> collection; protected int start; protected int end; protected boolean reloadData = false; private int size; private boolean autoSizeColumns; protected Node root; public AbstractInfoTreeWidget(Composite parent, List<T> collection, String[] headings, int[] columnWidths, int rowsPerPage) { super(parent, SWT.NONE); pageInfo = new PageInformation(); pageInfo.rowsPerPage = rowsPerPage; pageInfo.page = 0; GridLayout gl = new GridLayout(1, false); gl.verticalSpacing = 1; setLayout(gl); setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); int style = SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL; if (!isEditMode()) style = style | SWT.MULTI; treeViewer = new TreeViewer(this, style); Tree tree = treeViewer.getTree(); // table.setLayout(new TableLayout()); tree.setHeaderVisible(true); tree.setLinesVisible(true); GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); tree.setLayoutData(gd); setHeadings(headings, columnWidths); // tableViewer.setUseHashlookup(true); treeViewer.setLabelProvider(getLabelProvider()); treeViewer.setContentProvider(new ITreeContentProvider() { @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // } @Override public void dispose() { // } @Override public boolean hasChildren(Object element) { return getChildren(element).length > 0; } @Override public Object getParent(Object element) { if (element instanceof Node) return ((Node) element).getParent(); return null; } @Override public Object[] getElements(Object inputElement) { return getChildren(inputElement); } @Override public Object[] getChildren(Object parentElement) { if (parentElement instanceof Node) try { return getNodeChildren((Node) parentElement).toArray(); } catch (Exception e) { throw new RuntimeException(e); } return new Object[0]; } }); root = new Node() { @Override public List<Node> getChildren() { return getRootChildren(); } @Override public Node getParent() { return null; } @Override public void removeChild(Node o) { root.removeChild(o); } }; treeViewer.setInput(root); addPaginationWidget(); if (collection != null) setCollection(collection); menu = new Menu(parent); treeViewer.getTree().setMenu(menu); autoSizeColumns = columnWidths == null ? true : false; BgcClipboard.addClipboardCopySupport(treeViewer, menu, getLabelProvider(), headings.length); } protected abstract List<Node> getNodeChildren(Node node) throws Exception; protected abstract List<Node> getRootChildren(); public void setHeadings(String[] headings) { setHeadings(headings, null); } public void setHeadings(String[] headings, int[] columnWidths) { int index = 0; if (headings != null) { for (String name : headings) { final TreeViewerColumn col = new TreeViewerColumn(treeViewer, SWT.NONE); col.getColumn().setText(name); if (columnWidths == null || columnWidths[index] == -1) { col.getColumn().pack(); } else { col.getColumn().setWidth(columnWidths[index]); } col.getColumn().setResizable(true); col.getColumn().setMoveable(true); col.getColumn().addListener(SWT.SELECTED, new Listener() { @Override public void handleEvent(Event event) { col.getColumn().pack(); } }); col.setEditingSupport(getEditingSupport(index)); index++; } treeViewer.setColumnProperties(headings); } } @SuppressWarnings("unused") protected EditingSupport getEditingSupport(int index) { return null; } protected abstract boolean isEditMode(); protected abstract BgcLabelProvider getLabelProvider(); public List<T> getCollection() { return collection; } @Override public boolean setFocus() { treeViewer.getControl().setFocus(); return true; } public void addSelectionListener(SelectionListener listener) { treeViewer.getTree().addSelectionListener(listener); } protected TreeViewer getTreeViewer() { return treeViewer; } /** * 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 tree data. * * @throws Exception */ protected abstract void treeLoader(final List<T> collection, final T Selection); public void setCollection(final List<T> collection) { setCollection(collection, null); if (collection != null) { size = collection.size(); } } public void setCollection(final List<T> collection, final T selection) { try { if ((collection == null) || ((backgroundThread != null) && backgroundThread.isAlive())) { return; } else if (this.collection != collection || size != collection.size()) { this.collection = collection; init(collection); setPaginationParams(collection); } if (paginationRequired) { showPaginationWidget(); setPageLabelText(); enablePaginationWidget(false); } else if (paginationWidget != null) paginationWidget.setVisible(false); final Display display = getTreeViewer().getTree().getDisplay(); resizeTree(); backgroundThread = new Thread() { @Override public void run() { treeLoader(collection, selection); if (autoSizeColumns) { display.syncExec(new Runnable() { @Override public void run() { autoSizeColumns(); } }); } } }; backgroundThread.start(); } catch (Exception e) { BgcPlugin.openAsyncError( Messages.AbstractInfoTreeWidget_load_error_title, e); } layout(true, true); } private void autoSizeColumns() { Tree tree = treeViewer.getTree(); if (tree.isDisposed()) { return; } final int[] maxCellContentsWidths = new int[tree.getColumnCount()]; Text textRenderer = new Text(menu.getShell(), SWT.NONE); textRenderer.setVisible(false); GridData gd = new GridData(); gd.exclude = true; textRenderer.setLayoutData(gd); for (int i = 0; i < tree.getColumnCount(); i++) { textRenderer.setText(tree.getColumn(i).getText()); maxCellContentsWidths[i] = textRenderer.computeSize(SWT.DEFAULT, SWT.DEFAULT).x; } for (TreeItem row : tree.getItems()) { for (int i = 0; i < tree.getColumnCount(); i++) { String rowText = row.getText(i); Image rowImage = row.getImage(i); int cellContentsWidth = 0; if (rowText != null) { textRenderer.setText(rowText); cellContentsWidth = textRenderer.computeSize(SWT.DEFAULT, SWT.DEFAULT).x; } else if (rowImage != null) { cellContentsWidth = rowImage.getImageData().width; } maxCellContentsWidths[i] = Math.max(cellContentsWidth, maxCellContentsWidths[i]); } } textRenderer.dispose(); int sumOfMaxTextWidths = 0; for (int width : maxCellContentsWidths) { sumOfMaxTextWidths += width; } int treeWidth = Math.max(500, treeViewer.getTree().getSize().x); int totalWidths = 0; treeViewer.getTree().setVisible(false); for (int i = 0; i < tree.getColumnCount(); i++) { int width = (int) ((double) maxCellContentsWidths[i] / sumOfMaxTextWidths * treeWidth); if (i == tree.getColumnCount() - 1) tree.getColumn(i).setWidth(treeWidth - totalWidths - 5); else tree.getColumn(i).setWidth(width); totalWidths += width; } treeViewer.getTree().setVisible(true); } protected abstract void init(List<T> collection); private void resizeTree() { Tree tree = getTreeViewer().getTree(); GridData gd = (GridData) tree.getLayoutData(); int rows = Math.max(pageInfo.rowsPerPage, 5); gd.heightHint = (rows - 1) * tree.getItemHeight() + tree.getHeaderHeight() + 4; layout(true, true); } protected abstract void setPaginationParams(List<T> collection); @Override public void setEnabled(boolean enabled) { treeViewer.getTree().setEnabled(enabled); } protected void addPaginationWidget() { if (paginationWidget != null) paginationWidget.dispose(); paginationWidget = new Composite(this, SWT.NONE); paginationWidget.setLayout(new GridLayout(5, false)); firstButton = new Button(paginationWidget, SWT.NONE); firstButton.setImage(BgcPlugin.getDefault().getImageRegistry() .get(BgcPlugin.IMG_RESULTSET_FIRST)); firstButton.setToolTipText(Messages.AbstractInfoTreeWidget_first_label); firstButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { firstP(); } }); prevButton = new Button(paginationWidget, SWT.NONE); prevButton.setImage(BgcPlugin.getDefault().getImageRegistry() .get(BgcPlugin.IMG_RESULTSET_PREV)); prevButton .setToolTipText(Messages.AbstractInfoTreeWidget_previous_label); prevButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { prevP(); } }); pageLabel = new Label(paginationWidget, SWT.NONE); nextButton = new Button(paginationWidget, SWT.NONE); nextButton.setImage(BgcPlugin.getDefault().getImageRegistry() .get(BgcPlugin.IMG_RESULTSET_NEXT)); nextButton.setToolTipText(Messages.AbstractInfoTreeWidget_next_label); nextButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { nextP(); } }); lastButton = new Button(paginationWidget, SWT.NONE); lastButton.setImage(BgcPlugin.getDefault().getImageRegistry() .get(BgcPlugin.IMG_RESULTSET_LAST)); lastButton.setToolTipText(Messages.AbstractInfoTreeWidget_last_label); lastButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { lastP(); } }); setDefaultWidgetsEnabled(); setPageLabelText(); // do not display it yet, wait till collection is added paginationWidget.setVisible(false); GridData gd = new GridData(SWT.END, SWT.TOP, true, true); gd.exclude = false; paginationWidget.setLayoutData(gd); layout(true, true); } @Override public Menu getMenu() { return menu; } protected abstract void setDefaultWidgetsEnabled(); private void showPaginationWidget() { paginationWidget.setVisible(true); } protected void enablePaginationWidget(boolean enable) { paginationWidget.setEnabled(enable); enableWidgets(enable); } protected abstract void enableWidgets(boolean enable); private void firstP() { firstPage(); newPage(); } private void nextP() { nextPage(); newPage(); } private void prevP() { prevPage(); newPage(); } private void lastP() { lastPage(); newPage(); } private void newPage() { setCollection(collection); setPageLabelText(); } protected abstract void firstPage(); protected abstract void prevPage(); protected abstract void nextPage(); protected abstract void lastPage(); protected abstract void setPageLabelText(); }