org.openmicroscopy.shoola.agents.dataBrowser.browser.BrowserModel.java Source code

Java tutorial

Introduction

Here is the source code for org.openmicroscopy.shoola.agents.dataBrowser.browser.BrowserModel.java

Source

/*
 * org.openmicroscopy.shoola.agents.dataBrowser.browser.BrowserModel 
 *
 *------------------------------------------------------------------------------
 *  Copyright (C) 2006-2014 University of Dundee. All rights reserved.
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *------------------------------------------------------------------------------
 */
package org.openmicroscopy.shoola.agents.dataBrowser.browser;

//Java imports
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.swing.JComponent;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;

//Third-party libraries

import org.apache.commons.collections.CollectionUtils;
//Application-internal dependencies
import org.openmicroscopy.shoola.agents.dataBrowser.Colors;
import org.openmicroscopy.shoola.agents.dataBrowser.layout.Layout;
import org.openmicroscopy.shoola.agents.dataBrowser.layout.LayoutFactory;
import org.openmicroscopy.shoola.agents.dataBrowser.visitor.FilesetVisitor;
import org.openmicroscopy.shoola.agents.dataBrowser.visitor.NodesFinder;
import org.openmicroscopy.shoola.agents.dataBrowser.visitor.ResetNodesVisitor;
import org.openmicroscopy.shoola.util.ui.component.AbstractComponent;
import pojos.DataObject;
import pojos.ImageData;
import pojos.WellData;

/** 
 * Implements {@link Browser} to maintain presentation state, thus acting
 * as the Model in MVC.
 *
 * @author  Jean-Marie Burel     
 * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
 * @author Donald MacDonald &nbsp;&nbsp;&nbsp;&nbsp;
 * <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a>
 * @version 3.0
 * @since OME3.0
 */
class BrowserModel extends AbstractComponent implements Browser {

    /**
     * Flag indicating to display the data related to a node
     * when the user mouses over the node.
     */
    private boolean mouseOver;

    /** 
     * Flag to control the zoom action when the user mouses over an 
     * {@link ImageNode}. 
     */
    private boolean rollOver;

    /** 
     * Tells if a thumbnail has been selected in the case the 
     * last selected display is an {@link ImageNode}. 
     */
    private boolean thumbSelected;

    /** Position of the last pop-up trigger within the browser. */
    private Point popupPoint;

    /** Contains all visualization trees, our View. */
    private RootDisplay rootDisplay;

    /** The selected layout. */
    private Layout selectedLayout;

    /**
     * Tells if more than one {@link ImageNode}s are selected.
     * Doesn't really make sense to select other type of data objects.
     */
    private boolean multiSelection;

    /** The selected nodes. */
    private List<ImageDisplay> selectedDisplays;

    /** Indicates if the image's title bar is visible. */
    private boolean titleBarVisible;

    /** The node on which the mouse was located before exited. */
    private RollOverNode rollOverNode;

    /** The collection of original images. */
    private Set<ImageDisplay> originalNodes;

    /**
     * Adds the children of the passed node to its internal desktop.
     * This method should be invoked when user switches between layout.
     * 
     * @param node The node to handle.
     */
    private void addToDesktop(ImageDisplay node) {
        if (node instanceof ImageNode)
            return;
        JComponent desktop = node.getInternalDesktop();
        Collection<ImageDisplay> children = node.getChildrenDisplay();
        if (children == null)
            return;
        //desktop.removeAll();
        Iterator<ImageDisplay> i = children.iterator();
        ImageDisplay child;
        while (i.hasNext()) {
            child = i.next();
            if (!node.containsImages())
                addToDesktop(child);
            else
                desktop.add(child);
        }
    }

    /**
     * Sets the color of the selected and deselected nodes.
     * 
     * @param toSelect      The collection of selected nodes.
     * @param toDeselect   The collection of deselected nodes.
     */
    private void setNodesColor(Collection<ImageDisplay> toSelect, Collection<ImageDisplay> toDeselect) {
        //paint the nodes
        Colors colors = Colors.getInstance();
        Iterator<ImageDisplay> i;
        ImageDisplay node;
        ImageDisplay primary = null;
        if (selectedDisplays.size() > 0)
            primary = selectedDisplays.get(0);

        List<ImageData> selectedImages = new ArrayList<ImageData>();
        List<ImageData> deselectedImages = new ArrayList<ImageData>();
        Object ho;
        if (toDeselect != null && toDeselect.size() > 0) {
            i = toDeselect.iterator();
            while (i.hasNext()) {
                node = i.next();
                if (node != null) {
                    ho = node.getHierarchyObject();
                    if (ho instanceof ImageData) {
                        deselectedImages.add((ImageData) ho);
                    }
                    if (toSelect != null) {
                        if (!toSelect.contains(node))
                            node.setHighlight(colors.getDeselectedHighLight(node));
                    } else
                        node.setHighlight(colors.getDeselectedHighLight(node));
                }
            }
        }
        if (toSelect != null && toSelect.size() > 0) {
            i = toSelect.iterator();
            while (i.hasNext()) {
                node = i.next();
                ho = node.getHierarchyObject();
                if (ho instanceof ImageData) {
                    selectedImages.add((ImageData) ho);
                }
                node.setHighlight(colors.getSelectedHighLight(node, isSameNode(node, primary)));
            }
        }
        FilesetVisitor visitor = new FilesetVisitor(selectedImages, deselectedImages);
        accept(visitor);
    }

    /**
     * Returns <code>true</code> if the passed nodes are the same, 
     * <code>false</code> otherwise.
     * 
     * @param n1 One of the nodes to handle.
     * @param n2 One of the nodes to handle.
     * @return See above.
     */
    private boolean isSameNode(ImageDisplay n1, ImageDisplay n2) {
        if (n1 != null && n2 != null) {
            Object o1 = n1.getHierarchyObject();
            Object o2 = n2.getHierarchyObject();
            if (o1 == null || o2 == null)
                return false;
            if (!o1.getClass().equals(o2.getClass()))
                return false;
            if ((o1 instanceof DataObject) && (o2 instanceof DataObject)) {
                long id1 = ((DataObject) o1).getId();
                long id2 = ((DataObject) o2).getId();
                return id1 == id2;
            } else if ((o1 instanceof File) && (o2 instanceof File)) {
                String s1 = ((File) o1).getAbsolutePath();
                String s2 = ((File) o2).getAbsolutePath();
                return s1.equals(s2);
            }
        }
        return false;
    }

    /**
     * Creates a new instance.
     * 
     * @param view The root display of the visualization trees. Each child node
     *              is the top node of a visualization tree.
     *              Mustn't be <code>null</code>.
     */
    BrowserModel(RootDisplay view) {
        super();
        if (view == null)
            throw new NullPointerException("No view.");
        rootDisplay = view;
        selectedDisplays = new ArrayList<ImageDisplay>();
        originalNodes = new HashSet<ImageDisplay>(rootDisplay.getChildrenDisplay());
        titleBarVisible = true;
    }

    /**
     * Sets the title and the color of the selected node.
     * 
     * @param newNode The selected node.
     * @param nodes   The previously selected nodes.
     */
    void onNodeSelected(ImageDisplay newNode, Set<ImageDisplay> nodes) {
        if (newNode == null)
            return;
        rootDisplay.setTitle(currentPathString(newNode));
        //paint the nodes
        List<ImageDisplay> selected = new ArrayList<ImageDisplay>();
        selected.add(newNode);
        if (isMultiSelection() || nodes == null)
            setNodesColor(selected, null);
        else
            setNodesColor(selected, nodes);
    }

    /**
     * Sets the selected cells.
     * 
     * @param cell The selected cell.
     */
    void setSelectedCell(CellDisplay cell) {
        firePropertyChange(CELL_SELECTION_PROPERTY, null, cell);
    }

    /**
     * String-ifies the path from the specified node to the
     * {@link #rootDisplay}.
     * 
     * @param parent The node to start from.
     * @return The above described string.
     */
    String currentPathString(ImageDisplay parent) {
        StringBuffer buf = new StringBuffer();
        List<String> titleBuf = new ArrayList<String>();
        while (parent != null && !(parent instanceof RootDisplay)) {
            if (parent instanceof CellDisplay) {
                int type = ((CellDisplay) parent).getType();
                if (type == CellDisplay.TYPE_HORIZONTAL)
                    titleBuf.add("column: " + parent.getTitle());
                else
                    titleBuf.add("row: " + parent.getTitle());
            } else if (parent instanceof WellImageSet) {
                WellImageSet wiNode = (WellImageSet) parent;
                titleBuf.add(wiNode.getTitle());
            } else if (parent instanceof WellSampleNode) {
                Object o = ((WellSampleNode) parent).getParentObject();
                if (o instanceof WellData) {
                    titleBuf.add(((WellData) o).getPlate().getName());
                    //if (titleBuf.s() != 0)
                    //   titleBuf.append(" > ");
                    titleBuf.add(parent.getTitle());
                    if (titleBuf.size() == 0)
                        titleBuf.add("[..]");
                    //if (titleBuf.length() == 0) titleBuf.append("[..]");
                }
            } else {
                //titleBuf.append(parent.getTitle());
                titleBuf.add(parent.getTitle());
                //if (titleBuf.length() == 0) titleBuf.append("[..]");
                //if (parent instanceof ImageSet) buf.insert(0, " > ");
            }
            //buf.insert(0, titleBuf.toString());
            parent = parent.getParentDisplay();
        }
        int n = titleBuf.size();
        for (int i = 0; i < n; i++) {
            buf.append(titleBuf.get(n - 1 - i));
            if (i != (n - 1))
                buf.append(">");
        }
        return buf.toString();
    }

    /** 
     * Fires a property whose new value if the passed object.
     * 
     * @param propName  The name of the property.
     * @param node      The new value.
     */
    void setNodeForProperty(String propName, Object node) {
        firePropertyChange(propName, null, node);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setRollOverNode(RollOverNode)
     */
    public void setRollOverNode(RollOverNode node) {
        RollOverNode previousNode = rollOverNode;
        rollOverNode = node;
        firePropertyChange(ROLL_OVER_PROPERTY, previousNode, node);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getRootNodes()
     */
    public Collection<ImageDisplay> getRootNodes() {
        return rootDisplay.getChildrenDisplay();
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getSelectedDisplays()
     */
    public Collection<ImageDisplay> getSelectedDisplays() {
        return selectedDisplays;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getSelectedDataObjects()
     */
    public Collection<DataObject> getSelectedDataObjects() {
        if (selectedDisplays == null)
            return null;
        Iterator<ImageDisplay> i = selectedDisplays.iterator();
        List<DataObject> nodes = new ArrayList<DataObject>();
        ImageDisplay o;
        Object ho;
        while (i.hasNext()) {
            o = i.next();
            ho = o.getHierarchyObject();
            if (ho instanceof DataObject)
                nodes.add((DataObject) ho);
        }
        return nodes;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getLastSelectedDisplay()
     */
    public ImageDisplay getLastSelectedDisplay() {
        final int size = selectedDisplays.size();
        return size < 1 ? null : selectedDisplays.get(size - 1);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setThumbSelected(boolean, ImageNode)
     */
    public void setThumbSelected(boolean selected, ImageNode node) {
        if (node == null)
            throw new IllegalArgumentException("No node");
        if (!selected)
            return;
        popupPoint = null;
        thumbSelected = selected;
        firePropertyChange(THUMB_SELECTED_PROPERTY, null, node);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#isThumbSelected()
     */
    public boolean isThumbSelected() {
        return thumbSelected;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setPopupPoint(Point, boolean)
     */
    public void setPopupPoint(Point p, boolean fireProperty) {
        thumbSelected = false;
        Object oldValue = null;//popupPoint;
        popupPoint = p;
        if (fireProperty)
            firePropertyChange(POPUP_POINT_PROPERTY, oldValue, p);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getPopupPoint()
     */
    public Point getPopupPoint() {
        return popupPoint;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getImages()
     */
    public Set<DataObject> getImages() {
        //Note: avoid caching b/c we don't know yet what we are going
        //to do with updates
        ImageFinder finder = new ImageFinder();
        accept(finder, ImageDisplayVisitor.IMAGE_NODE_ONLY);
        return finder.getImages();
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getImageNodes()
     */
    public Set<ImageDisplay> getImageNodes() {
        //Note: avoid caching b/c we don't know yet what we are going
        //to do with updates
        ImageFinder finder = new ImageFinder();
        accept(finder, ImageDisplayVisitor.IMAGE_NODE_ONLY);
        return finder.getImageNodes();
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#accept(ImageDisplayVisitor)
     */
    public void accept(ImageDisplayVisitor visitor) {
        rootDisplay.accept(visitor, ImageDisplayVisitor.ALL_NODES);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#accept(ImageDisplayVisitor, int)
     */
    public void accept(ImageDisplayVisitor visitor, int algoType) {
        rootDisplay.accept(visitor, algoType);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getUI()
     */
    public JComponent getUI() {
        return rootDisplay;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setSelectedLayout(Layout)
     */
    public void setSelectedLayout(Layout layout) {
        if (layout == null)
            return;
        Layout oldLayout = selectedLayout;
        switch (layout.getIndex()) {
        case LayoutFactory.SQUARY_LAYOUT:
        case LayoutFactory.FLAT_LAYOUT:
        case LayoutFactory.PLATE_LAYOUT:
            selectedLayout = layout;
            break;
        }
        firePropertyChange(LAYOUT_PROPERTY, oldLayout, selectedLayout);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getSelectedLayout()
     */
    public Layout getSelectedLayout() {
        return selectedLayout;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#isMultiSelection()
     */
    public boolean isMultiSelection() {
        return multiSelection;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#isTitleBarVisible()
     */
    public boolean isTitleBarVisible() {
        return titleBarVisible;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setTitleBarVisible(boolean)
     */
    public void setTitleBarVisible(boolean b) {
        titleBarVisible = b;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setRollOver(boolean)
     */
    public void setRollOver(boolean rollOver) {
        setRollOverNode(null);
        this.rollOver = rollOver;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#isRollOver()
     */
    public boolean isRollOver() {
        return rollOver;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#isMouseOver()
     */
    public boolean isMouseOver() {
        return mouseOver;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setMouseOver(boolean)
     */
    public void setMouseOver(boolean b) {
        mouseOver = b;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#resetChildDisplay()
     */
    public void resetChildDisplay() {
        rootDisplay.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        Collection<ImageDisplay> rootChildren = rootDisplay.getChildrenDisplay();
        JComponent desktop = rootDisplay.getInternalDesktop();
        desktop.removeAll();
        Iterator<ImageDisplay> i;
        switch (selectedLayout.getIndex()) {
        case LayoutFactory.SQUARY_LAYOUT:
            i = rootChildren.iterator();
            ImageDisplay child;
            while (i.hasNext()) {
                child = i.next();
                desktop.add(child);
                addToDesktop(child);
            }
            break;

        case LayoutFactory.FLAT_LAYOUT:
            i = getImageNodes().iterator();
            while (i.hasNext())
                desktop.add(i.next());
        }
        rootDisplay.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setSelectedNodes(List)
     */
    public void setSelectedNodes(List<DataObject> nodes) {
        Set<ImageDisplay> oldValue = null;
        if (selectedDisplays != null)
            oldValue = new HashSet<ImageDisplay>(selectedDisplays);
        if (nodes == null || nodes.isEmpty()) {
            if (selectedDisplays != null)
                selectedDisplays.clear();
            setNodesColor(null, oldValue);
            return;
        }
        NodesFinder finder = new NodesFinder(nodes);
        accept(finder);
        List<ImageDisplay> found = finder.getFoundNodes();
        if (CollectionUtils.isEmpty(found)) {
            Collection<ImageDisplay> selected = getSelectedDisplays();
            if (CollectionUtils.isEmpty(selected)) {
                setNodesColor(null, getRootNodes());
            }
            setSelectedDisplay(null, false, false);
            return;
        }

        thumbSelected = false;
        this.multiSelection = found.size() > 1;
        setSelectedDisplays(found);
        setNodesColor(found, oldValue);
        List<ImageData> images = new ArrayList<ImageData>();
        Iterator<ImageDisplay> i = found.iterator();
        ImageDisplay d;
        while (i.hasNext()) {
            d = i.next();
            if (d.getHierarchyObject() instanceof ImageData)
                images.add((ImageData) d.getHierarchyObject());
        }
        FilesetVisitor visitor = new FilesetVisitor(images, null);
        accept(visitor);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setFilterNodes(Collection)
     */
    public void setFilterNodes(Collection<ImageDisplay> nodes) {
        ResetNodesVisitor visitor = new ResetNodesVisitor(nodes, true);
        rootDisplay.accept(visitor, ImageDisplayVisitor.IMAGE_SET_ONLY);
        final Set<DataObject> visibleDataObjects = getVisibleImages();
        final Collection<DataObject> selectedDataObjects = getSelectedDataObjects();
        final Set<ImageDisplay> nodesWithVisibleSelectedDataObjects = new HashSet<ImageDisplay>();
        for (final ImageDisplay filterNode : nodes) {
            final Object hierarchyObject = filterNode.getHierarchyObject();
            if (visibleDataObjects.contains(hierarchyObject) && selectedDataObjects.contains(hierarchyObject))
                nodesWithVisibleSelectedDataObjects.add(filterNode);
        }
        setNodesSelection(nodesWithVisibleSelectedDataObjects);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#showAll()
     */
    public void showAll() {
        setFilterNodes(getImageNodes());
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getOriginal()
     */
    public Set<DataObject> getOriginal() {
        Set<DataObject> nodes = new HashSet<DataObject>();
        Iterator<ImageDisplay> i = originalNodes.iterator();
        Object ho;
        while (i.hasNext()) {
            ho = i.next().getHierarchyObject();
            if (ho instanceof DataObject)
                nodes.add((DataObject) ho);
        }
        return nodes;
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getVisibleImages()
     */
    public Set<DataObject> getVisibleImages() {
        //Note: avoid caching b/c we don't know yet what we are going
        //to do with updates
        ImageFinder finder = new ImageFinder();
        accept(finder, ImageDisplayVisitor.IMAGE_SET_ONLY);
        return finder.getVisibleImages();
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#getVisibleImageNodes()
     */
    public List<ImageNode> getVisibleImageNodes() {
        //Note: avoid caching b/c we don't know yet what we are going
        //to do with updates
        ImageFinder finder = new ImageFinder();
        accept(finder, ImageDisplayVisitor.IMAGE_SET_ONLY);
        return finder.getVisibleImageNodes();
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setNodesSelection(Collection)
     */
    public void setNodesSelection(Collection<ImageDisplay> nodes) {
        if (nodes == null)
            return;
        setNodesColor(nodes, getSelectedDisplays());
        final HashSet<ImageDisplay> previouslySelectedDisplays = new HashSet<ImageDisplay>(this.selectedDisplays);
        previouslySelectedDisplays.removeAll(nodes);
        Colors colors = Colors.getInstance();
        for (final ImageDisplay node : previouslySelectedDisplays) {
            node.setHighlight(colors.getDeselectedHighLight(node));
            selectedDisplays.remove(node);
        }
        boolean multiSelection = false;
        Set<ImageDisplay> oldValue = new HashSet<ImageDisplay>(selectedDisplays);
        for (final ImageDisplay node : nodes) {
            setSelectedDisplay(node, multiSelection, false);
            multiSelection = true;
        }
        firePropertyChange(SELECTED_DATA_BROWSER_NODES_DISPLAY_PROPERTY, oldValue, selectedDisplays);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#removeSelectedDisplay(ImageDisplay)
     */
    public void removeSelectedDisplay(ImageDisplay node) {
        if (node == null)
            return;
        Colors colors = Colors.getInstance();
        node.setHighlight(colors.getDeselectedHighLight(node));
        selectedDisplays.remove(node);
        firePropertyChange(UNSELECTED_DATA_BROWSER_NODE_DISPLAY_PROPERTY, null, node);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#viewDisplay(ImageDisplay, boolean)
     */
    public void viewDisplay(ImageDisplay node, boolean internal) {
        if (node == null)
            return;
        if (internal)
            firePropertyChange(MAIN_VIEW_DISPLAY_PROPERTY, null, node);
        else
            firePropertyChange(VIEW_DISPLAY_PROPERTY, null, node);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setComponentTitle(String)
     */
    public void setComponentTitle(String title) {
        rootDisplay.setTitle(title);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#refresh(Collection, List)
     */
    public void refresh(Collection<ImageDisplay> nodes, List<ImageDisplay> selected) {
        rootDisplay.removeAllChildrenDisplay();
        if (nodes == null)
            return;
        Iterator<ImageDisplay> i = nodes.iterator();
        while (i.hasNext())
            rootDisplay.addChildDisplay(i.next());
        if (selected == null)
            return;
        boolean b = selected.size() > 1;
        i = selected.iterator();
        while (i.hasNext())
            setSelectedDisplay(i.next(), b, true);
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#markUnmodifiedNodes(Class, Collection)
     */
    public void markUnmodifiedNodes(Class type, Collection<Long> ids) {
        Iterator<ImageDisplay> i = selectedDisplays.iterator();
        ImageDisplay node;
        Object ho;
        long id;
        Colors colors = Colors.getInstance();
        while (i.hasNext()) {
            node = i.next();
            ho = node.getHierarchyObject();
            if (ho.getClass().equals(type) && ho instanceof DataObject) {
                id = ((DataObject) ho).getId();
                if (ids.contains(id)) {
                    node.setHighlight(colors.getUnmodifiedHighLight(node));
                }
            }
        }
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setSelectedDisplay(ImageDisplay, boolean, boolean)
     */
    public void setSelectedDisplay(ImageDisplay node, boolean multiSelection, boolean fireProperty) {
        if (node instanceof CellDisplay)
            return;
        thumbSelected = false;
        //popupPoint = null; //TEST mouse click
        this.multiSelection = multiSelection;
        final Set<ImageDisplay> oldValue = new HashSet<ImageDisplay>(this.selectedDisplays);

        if (!multiSelection)
            selectedDisplays.clear();
        int n = selectedDisplays.size();
        boolean removed = false;
        if (node != null) {
            if (selectedDisplays.contains(node)) {
                selectedDisplays.remove(node);
                n = selectedDisplays.size();
                removed = true;
            } else
                selectedDisplays.add(node);
        }
        if (fireProperty) {
            onNodeSelected(node, oldValue);
            firePropertyChange(SELECTED_DATA_BROWSER_NODE_DISPLAY_PROPERTY, oldValue, node);
        } else {
            if (multiSelection) {
                Colors colors = Colors.getInstance();
                if (removed)
                    node.setHighlight(colors.getDeselectedHighLight(node));
                else
                    node.setHighlight(colors.getSelectedHighLight(node, n == 0));
            } else
                onNodeSelected(node, oldValue);
        }
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#setSelectedDisplays(List)
     */
    public void setSelectedDisplays(List<ImageDisplay> nodes) {
        if (nodes == null || nodes.size() == 0)
            return;
        if (nodes.size() == 1) {
            setSelectedDisplay(nodes.get(0), false, true);
        } else {
            List<ImageData> selected = new ArrayList<ImageData>(nodes.size());
            Iterator<ImageDisplay> i = nodes.iterator();
            ImageDisplay img;
            while (i.hasNext()) {
                img = i.next();
                if (img.getHierarchyObject() instanceof ImageData) {
                    selected.add((ImageData) img.getHierarchyObject());
                }
            }
            FilesetVisitor visitor = new FilesetVisitor(selected, null);
            accept(visitor);
            thumbSelected = false;
            this.multiSelection = true;
            Set<ImageDisplay> oldValue = new HashSet<ImageDisplay>(selectedDisplays);
            selectedDisplays = nodes;
            firePropertyChange(SELECTED_DATA_BROWSER_NODES_DISPLAY_PROPERTY, oldValue, nodes);
        }
    }

    /**
     * Implemented as specified by the {@link Browser} interface.
     * @see Browser#scrollToNode(ImageDisplay)
     */
    public void scrollToNode(ImageDisplay node) {
        if (node == null)
            return;
        JScrollPane pane = rootDisplay.getDeskDecorator();
        Rectangle bounds = node.getBounds();
        Rectangle viewRect = pane.getViewport().getViewRect();
        if (viewRect.contains(bounds))
            return;
        JScrollBar hBar = pane.getHorizontalScrollBar();
        if (hBar.isVisible()) {
            int x = bounds.x;
            int max = hBar.getMaximum();
            if (x > max)
                x = max;
            hBar.setValue(x);
        }
        JScrollBar vBar = pane.getVerticalScrollBar();
        if (vBar.isVisible()) {
            int y = bounds.y;
            int max = vBar.getMaximum();
            if (y > max)
                y = max;
            vBar.setValue(y);
        }
    }

}