uk.ac.diamond.scisoft.analysis.rcp.hdf5.HDF5TableTree.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.diamond.scisoft.analysis.rcp.hdf5.HDF5TableTree.java

Source

/*
 * Copyright (c) 2012 Diamond Light Source Ltd.
 *
 * 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
 */

package uk.ac.diamond.scisoft.analysis.rcp.hdf5;

import java.util.Iterator;

import org.dawb.common.ui.selection.SelectedTreeItemInfo;
import org.dawb.common.ui.selection.SelectionUtils;
import org.eclipse.dawnsci.analysis.api.dataset.IDataset;
import org.eclipse.dawnsci.analysis.api.dataset.ILazyDataset;
import org.eclipse.dawnsci.analysis.api.tree.Attribute;
import org.eclipse.dawnsci.analysis.api.tree.DataNode;
import org.eclipse.dawnsci.analysis.api.tree.GroupNode;
import org.eclipse.dawnsci.analysis.api.tree.Node;
import org.eclipse.dawnsci.analysis.api.tree.NodeLink;
import org.eclipse.dawnsci.analysis.api.tree.SymbolicNode;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ILazyTreeContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
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.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;

import uk.ac.diamond.scisoft.analysis.io.NexusTreeUtils;
import uk.ac.diamond.scisoft.analysis.rcp.adapters.HDF5Adaptable;

/**
 * Class to contain a table-tree view of a HDF5 tree
 */
public class HDF5TableTree extends Composite implements ISelectionProvider {

    private TreeViewer tViewer = null;
    private Listener clistener, slistener, dlistener;
    private TreeFilter treeFilter;
    private Menu headerMenu;
    private Menu treeMenu;
    private String filename;

    private static final String MSG_ENABLED = "Use this item as comparison value";
    private static final String MSG_DISABLED = "Cannot use the item";

    /**
     * @param parent
     * @param slistener for single clicks
     * @param dlistener for double clicks
     * @param clistener for context click
     */
    public HDF5TableTree(Composite parent, Listener slistener, Listener dlistener, Listener clistener) {
        super(parent, SWT.NONE);
        setLayout(new FillLayout());
        this.slistener = slistener;
        this.dlistener = dlistener;
        this.clistener = clistener;

        // set up tree filter to omit following node names
        treeFilter = new TreeFilter(new String[] { "target", NexusTreeUtils.NX_CLASS });

        // set up tree and its columns
        tViewer = new TreeViewer(this, SWT.BORDER | SWT.VIRTUAL);
        tViewer.setUseHashlookup(true);

        final Tree tree = tViewer.getTree();
        tree.setHeaderVisible(true);

        String[] titles = { "Name", "Class", "Dims", "Type", "Data" };
        int[] widths = { 250, 120, 80, 60, 300 };

        TreeViewerColumn tVCol;
        headerMenu = new Menu(parent.getShell(), SWT.POP_UP);

        for (int i = 0; i < titles.length; i++) {
            tVCol = new TreeViewerColumn(tViewer, SWT.NONE);
            final TreeColumn tCol = tVCol.getColumn();
            tCol.setText(titles[i]);
            tCol.setWidth(widths[i]);
            tCol.setMoveable(true);
            final MenuItem item = new MenuItem(headerMenu, SWT.CHECK);
            item.setText(titles[i]);
            item.setSelection(true);
            item.addListener(SWT.Selection, new Listener() {
                @Override
                public void handleEvent(Event event) {
                    if (!item.getSelection()) {
                        int width = tCol.getWidth();
                        tCol.setData("restoredWidth", Integer.valueOf(width));
                        tCol.setWidth(0);
                    } else {
                        int width = (Integer) tCol.getData("restoredWidth");
                        tCol.setWidth(width);
                    }
                }
            });
        }

        treeMenu = new Menu(parent.getShell(), SWT.POP_UP);

        // TODO make context menu dependent on node (use a SWT.Show listener on menu)
        if (clistener != null) {
            treeMenu.addListener(SWT.Show, new Listener() {
                @Override
                public void handleEvent(Event event) {
                    // get selection and decide
                    ITreeSelection sel = (ITreeSelection) tViewer.getSelection();
                    Object obj = sel.getFirstElement();
                    boolean enable = false;
                    if (obj instanceof NodeLink) {
                        NodeLink link = (NodeLink) obj;
                        enable = link.isDestinationData() && !((DataNode) link.getDestination()).isString();
                    } else if (obj instanceof Attribute) {
                        enable = !((Attribute) obj).isString();
                    }

                    for (MenuItem m : treeMenu.getItems()) {
                        m.setEnabled(enable);
                        m.setText(enable ? MSG_ENABLED : MSG_DISABLED);
                    }
                }
            });
            MenuItem item = new MenuItem(treeMenu, SWT.PUSH);
            item.addListener(SWT.Selection, clistener);
        }

        tree.addListener(SWT.MenuDetect, new Listener() {
            @Override
            public void handleEvent(Event event) {
                Point pt = getDisplay().map(null, tree, new Point(event.x, event.y));
                Rectangle clientArea = tree.getClientArea();
                boolean header = clientArea.y <= pt.y && pt.y < (clientArea.y + tree.getHeaderHeight());
                tree.setMenu(header ? headerMenu : treeMenu);
            }
        });

        tViewer.setContentProvider(new HDF5LazyContentProvider(tViewer, treeFilter));
        tViewer.setLabelProvider(new HDF5LabelProvider());
        if (slistener != null)
            tree.addListener(SWT.MouseUp, slistener);
        if (dlistener != null)
            tree.addListener(SWT.MouseDoubleClick, dlistener);
    }

    public Viewer getViewer() {
        return tViewer;
    }

    @Override
    public void dispose() {
        if (slistener != null)
            tViewer.getTree().removeListener(SWT.MouseUp, slistener);
        if (dlistener != null)
            tViewer.getTree().removeListener(SWT.MouseDoubleClick, dlistener);

        if (clistener != null) {
            for (MenuItem m : treeMenu.getItems())
                m.removeListener(SWT.Selection, clistener);
        }

        tViewer.getTree().dispose();

        if (headerMenu != null && !headerMenu.isDisposed())
            headerMenu.dispose();

        if (treeMenu != null && !treeMenu.isDisposed())
            treeMenu.dispose();

        super.dispose();
    }

    public static int countChildren(Object element, TreeFilter filter) {
        int count = 0;
        if (element instanceof Attribute) {
            return 0;
        }

        if (element instanceof NodeLink) {
            Node node = ((NodeLink) element).getDestination();

            Iterator<String> iter = node.getAttributeNameIterator();
            while (iter.hasNext()) {
                if (filter.select(iter.next()))
                    count++;
            }

            if (node instanceof GroupNode) {
                GroupNode group = (GroupNode) node;
                Iterator<String> nIter = group.getNodeNameIterator();
                while (nIter.hasNext()) {
                    if (filter.select(nIter.next()))
                        count++;
                }
            }

            if (node instanceof DataNode) {
                // do nothing?
            }

        }
        return count;
    }

    /**
     * @param tree given by a node link
     */
    public void setInput(NodeLink tree) {
        if (tViewer != null && tViewer.getContentProvider() != null) {
            tViewer.setInput(tree);
            //          TODO decide whether this is needed
            //          tViewer.getTree().setItemCount(countChildren(tree, treeFilter));
        }
    }

    /**
     * Refresh viewer's content
     */
    public void refresh() {
        if (tViewer != null && !isDisposed()) {
            tViewer.refresh();
        }
    }

    /**
     * @return selection
     */
    @Override
    public IStructuredSelection getSelection() {
        IStructuredSelection selection = (IStructuredSelection) tViewer.getSelection();
        if (selection instanceof ITreeSelection) {
            SelectedTreeItemInfo[] results = SelectionUtils.parseAsTreeSelection((ITreeSelection) selection);
            if (results.length > 0 && results[0].getNode() != null) {
                return new HDF5TreeSelection(
                        new HDF5Adaptable(filename, results[0].getNode(), results[0].getItem()));
            }
        }
        return selection;
    }

    @Override
    public void addSelectionChangedListener(ISelectionChangedListener listener) {
    }

    @Override
    public void removeSelectionChangedListener(ISelectionChangedListener listener) {
    }

    @Override
    public void setSelection(ISelection selection) {
        if (selection instanceof IStructuredSelection) {
            tViewer.setSelection(selection);
        }
    }

    public void expandAll() {
        tViewer.expandAll();
    }

    public void expandToLevel(int level) {
        tViewer.expandToLevel(level);
    }

    public void expandToLevel(Object link, int level) {
        tViewer.expandToLevel(link, level);
    }

    public TreePath[] getExpandedTreePaths() {
        return tViewer.getExpandedTreePaths();
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

}

class HDF5LazyContentProvider implements ILazyTreeContentProvider {
    private TreeViewer viewer;
    private TreeFilter filter;

    public HDF5LazyContentProvider(TreeViewer treeViewer, TreeFilter treeFilter) {
        filter = treeFilter;
        viewer = treeViewer;
    }

    @Override
    public Object getParent(Object element) {
        if (element == null || !(element instanceof NodeLink)) {
            return null;
        }

        Node node = ((NodeLink) element).getSource();
        if (node == null)
            return element;
        return node;
    }

    @Override
    public void updateChildCount(Object element, int currentChildCount) {
        // count number of nodes that will not be filtered out
        int count = HDF5TableTree.countChildren(element, filter);
        if (count != currentChildCount)
            viewer.setChildCount(element, count);
    }

    @Override
    public void updateElement(Object parent, final int index) {
        if (parent instanceof Attribute) {
            return;
        }

        assert parent instanceof NodeLink : "Not an attribute or a link";

        Node pNode = ((NodeLink) parent).getDestination();

        int count = 0;
        Iterator<String> iter = pNode.getAttributeNameIterator();
        while (iter.hasNext()) {
            String name = iter.next();
            if (filter.select(name)) {
                if (index == count) {
                    Attribute a = pNode.getAttribute(name);
                    viewer.replace(parent, index, a);
                    updateChildCount(a, -1);
                    return;
                }
                count++;
            }
        }

        if (pNode instanceof GroupNode) {
            for (NodeLink link : (GroupNode) pNode) {
                if (link.isDestinationSymbolic()) {
                    SymbolicNode slink = (SymbolicNode) link.getDestination();
                    link = slink.getNodeLink();
                }
                if (link.isDestinationGroup()) {
                    String name = link.getName();
                    if (filter.select(name)) {
                        if (index == count) {
                            viewer.replace(parent, index, link);
                            updateChildCount(link, -1);
                            return;
                        }
                    }
                    count++;
                }
            }

            for (NodeLink link : (GroupNode) pNode) {
                if (link.isDestinationSymbolic()) {
                    SymbolicNode slink = (SymbolicNode) link.getDestination();
                    link = slink.getNodeLink();
                }
                if (link.isDestinationData()) {
                    String name = link.getName();
                    if (filter.select(name)) {
                        if (index == count) {
                            viewer.replace(parent, index, link);
                            updateChildCount(link, -1);
                            return;
                        }
                    }
                    count++;
                }
            }

        } else if (pNode instanceof DataNode) {
            // do nothing
        }
    }

    @Override
    public void dispose() {
    }

    @Override
    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
    }
}

class HDF5LabelProvider implements ITableLabelProvider {
    //   private static final Logger logger = LoggerFactory.getLogger(HDF5LabelProvider.class);

    @Override
    public Image getColumnImage(Object element, int columnIndex) {
        return null;
    }

    @Override
    public String getColumnText(Object element, int columnIndex) {
        String msg = "";

        if (element instanceof Attribute) {
            Attribute attr = (Attribute) element;
            switch (columnIndex) {
            case 0: // name
                msg = attr.getName();
                break;
            case 1: // class
                msg = "Attr";
                break;
            case 2: // dimensions
                if (attr.getSize() > 1) {
                    for (int i : attr.getShape()) {
                        msg += i + ", ";
                    }
                    if (msg.length() > 2)
                        msg = msg.substring(0, msg.length() - 2);
                }
                break;
            case 3: // type
                msg = attr.getTypeName();
                break;
            case 4: // data
                msg = attr.getSize() == 1 ? attr.getFirstElement() : attr.toString();
                break;
            }

            return msg;
        }

        assert element instanceof NodeLink : "Not an attribute or a link";

        NodeLink link = (NodeLink) element;
        Node node = link.getDestination();

        switch (columnIndex) {
        case 0: // name
            msg = link.getName();
            break;
        case 1: // class
            Attribute attr = node.getAttribute(NexusTreeUtils.NX_CLASS);
            msg = attr != null ? attr.getFirstElement() : "Group";
            break;
        }

        if (node instanceof DataNode) {
            DataNode dataset = (DataNode) node;

            if (columnIndex == 1) { // class
                return "SDS";
            }

            if (dataset.isString()) {
                switch (columnIndex) {
                case 3:
                    msg = dataset.getTypeName();
                    break;
                case 4:
                    msg = dataset.getString();
                    if (msg.length() > 100) // restrict to 100 characters
                        msg = msg.substring(0, 100) + "...";
                    break;
                }
                return msg;
            }

            if (!dataset.isSupported()) {
                return columnIndex == 4 ? "Not supported" : msg;
            }

            ILazyDataset data = dataset.getDataset();
            switch (columnIndex) {
            case 2: // dimensions
                if (data == null) {
                    int rank = dataset.getMaxShape().length;
                    for (int i = 0; i < rank; i++) {
                        msg += "0, ";
                    }
                } else {
                    int[] shape = data.getShape();
                    for (int i : shape) {
                        msg += i + ", ";
                    }
                }
                if (msg.length() > 2)
                    msg = msg.substring(0, msg.length() - 2);
                break;
            case 3: // type
                msg = dataset.getTypeName();
                break;
            case 4: // data
                if (data instanceof IDataset) {
                    // show a single value
                    msg = data.getRank() == 0 ? ((IDataset) data).getString() : ((IDataset) data).getString(0);
                    Attribute units = dataset.getAttribute("units");
                    if (units != null && units.isString()) {
                        msg += " " + units.getFirstElement();
                    }
                } else if (data == null || data.getSize() == 0) {
                    msg = "none available as dataset is zero-sized";
                } else if (data.getSize() == 1) {
                    msg = data.getSlice().getString(0);
                    Attribute units = dataset.getAttribute("units");
                    if (units != null && units.isString()) {
                        msg += " " + units.getFirstElement();
                    }
                } else {
                    msg = "double-click to view";
                }
                break;
            }
        }
        return msg;
    }

    @Override
    public void addListener(ILabelProviderListener listener) {
    }

    @Override
    public void dispose() {
    }

    @Override
    public boolean isLabelProperty(Object element, String property) {
        return false;
    }

    @Override
    public void removeListener(ILabelProviderListener listener) {
    }

}