/*
*------------------------------------------------------------------------------
* Copyright (C) 2006-2008 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.metadata.browser;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.ToolTipManager;
import javax.swing.border.BevelBorder;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.openmicroscopy.shoola.agents.events.treeviewer.DataObjectSelectionEvent;
import org.openmicroscopy.shoola.agents.metadata.IconManager;
import org.openmicroscopy.shoola.agents.metadata.MetadataViewerAgent;
import org.openmicroscopy.shoola.agents.metadata.util.TreeCellRenderer;
import org.openmicroscopy.shoola.agents.util.ViewerSorter;
import org.openmicroscopy.shoola.env.event.EventBus;
import omero.gateway.model.DataObject;
import omero.gateway.model.DatasetData;
import omero.gateway.model.ProjectData;
/**
* The view.
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author Donald MacDonald
* <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a>
* @version 3.0
* @since OME3.0
*/
class BrowserUI
extends JPanel
implements ActionListener
{
/** The text of the dummy default node. */
static final String LOADING_MSG = "Loading...";
/** The text of the default node when the object has not parents */
//static final String NO_PARENTS_MSG = "Wild and Free. " +
// "As data, and maybe all creatures should be.";
static final String NO_PARENTS_MSG = "Not in a container.";
/** Action Id indicating to browse the item. */
private static final int VIEW = 0;
/**
* The text of the node added to a {@link TreeBrowserSet} node
* containing no element.
*/
private static final String EMPTY_MSG = "";
/** Reference to the controller. */
private BrowserControl controller;
/** Reference to the Model. */
private BrowserModel model;
/** The tree hosting the display. */
private JTree treeDisplay;
/** The tool bar hosting the controls. */
private JToolBar menuBar;
/** Reference to the listener. */
private TreeExpansionListener listener;
/** Reference to the selection listener. */
private TreeSelectionListener selectionListener;
/** Menu used to handle the items. */
private JPopupMenu menu;
/**
* A {@link ViewerSorter sorter} to order nodes in ascending
* alphabetical order.
*/
private ViewerSorter sorter;
/**
* Creates the menu to manage the hierarchy.
*
* @return See above.
*/
private JPopupMenu createManagementMenu()
{
if (menu != null) return menu;
menu = new JPopupMenu();
menu.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
IconManager icons = IconManager.getInstance();
JMenuItem item = new JMenuItem("Browse");
item.setActionCommand(""+VIEW);
item.addActionListener(this);
item.setIcon(icons.getIcon(IconManager.BROWSE));
menu.add(item);
return menu;
}
/**
* Handles the mouse pressed and released.
*
* @param evt The event to handle.
*/
private void handleMouseClick(MouseEvent evt)
{
if (evt.getClickCount() == 2) {
TreeBrowserDisplay node = model.getLastSelectedNode();
if (node == null) return;
Object uo = node.getUserObject();
if (uo instanceof ProjectData || uo instanceof DatasetData) {
long id = ((DataObject) uo).getId();
DataObjectSelectionEvent event =
new DataObjectSelectionEvent(uo.getClass(), id);
event.setSelectTab(true);
EventBus bus = MetadataViewerAgent.getRegistry().getEventBus();
bus.post(event);
}
}
}
/** Helper method to create the menu bar. */
private void createMenuBar()
{
menuBar = new JToolBar();
menuBar.setBorder(null);
menuBar.setRollover(true);
menuBar.setFloatable(false);
}
/**
* Adds a dummy node to the specified node.
*
* @param node The parent node.
*/
private void buildEmptyNode(DefaultMutableTreeNode node)
{
DefaultTreeModel tm = (DefaultTreeModel) treeDisplay.getModel();
tm.insertNodeInto(new DefaultMutableTreeNode(EMPTY_MSG), node,
node.getChildCount());
}
/**
* Adds a tree menu to the passed node.
*
* @param parent The node the menus is attached to.
*/
private void addMenuToNode(TreeBrowserDisplay parent)
{
if (parent instanceof TreeBrowserSet)
buildEmptyNode(parent);
}
/** Creates the tree. */
private void createTree()
{
treeDisplay = new JTree();
treeDisplay.setVisible(true);
treeDisplay.setRootVisible(false);
treeDisplay.setCellRenderer(new TreeCellRenderer());
treeDisplay.setShowsRootHandles(true);
ToolTipManager.sharedInstance().registerComponent(treeDisplay);
TreeBrowserDisplay root = model.getLastSelectedNode();
treeDisplay.setModel(new DefaultTreeModel(root));
//addMenuToNode(root);
treeDisplay.expandPath(new TreePath(root.getPath()));
treeDisplay.addMouseListener(new MouseAdapter() {
/**
* Pops up a menu if the mouse click occurs on the tree
* but not on the a node composing the tree
* @see MouseAdapter#mousePressed(MouseEvent)
*/
public void mousePressed(MouseEvent e) { handleMouseClick(e); }
/**
* Pops up a menu if the mouse click occurs on the tree
* but not on the a node composing the tree
* @see MouseAdapter#mouseReleased(MouseEvent)
*/
public void mouseReleased(MouseEvent e) { handleMouseClick(e); }
});
selectionListener = new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e)
{
controller.onClick();
}
};
treeDisplay.addTreeSelectionListener(selectionListener);
listener = new TreeExpansionListener() {
public void treeCollapsed(TreeExpansionEvent e) {
onNodeNavigation(e, false);
}
public void treeExpanded(TreeExpansionEvent e) {
onNodeNavigation(e, true);
}
};
treeDisplay.addTreeExpansionListener(listener);
}
/**
* Reacts to node expansion event.
*
* @param tee The event to handle.
* @param expanded Pass <code>true</code> is the node is expanded,
* <code>false</code> otherwise.
*/
private void onNodeNavigation(TreeExpansionEvent tee, boolean expanded)
{
TreeBrowserDisplay node = (TreeBrowserDisplay)
tee.getPath().getLastPathComponent();
node.setExpanded(expanded);
controller.onNodeNavigation(node);
}
/** Builds and lays out the UI. */
private void buildGUI()
{
setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.anchor = GridBagConstraints.NORTHWEST;
constraints.insets = new Insets(0, 2, 2, 0);
constraints.gridy = 0;
constraints.gridwidth = GridBagConstraints.RELATIVE; //next-to-last
constraints.weightx = 1.0;
JScrollPane pane = new JScrollPane(treeDisplay);
Dimension d = pane.getPreferredSize();
pane.getViewport().setPreferredSize(new Dimension(d.width, 100));
pane.setBorder(null);
add(pane, constraints);
}
/** Creates a new instance. */
BrowserUI() {}
/**
* Links this View to its Controller and its Model.
*
* @param model Reference to the Model.
* Mustn't be <code>null</code>.
* @param controller Reference to the Controller.
* Mustn't be <code>null</code>.
*/
void initialize(BrowserModel model, BrowserControl controller)
{
if (controller == null)
throw new IllegalArgumentException("Controller cannot be null");
if (model == null)
throw new IllegalArgumentException("Model cannot be null");
this.controller = controller;
this.model = model;
sorter = new ViewerSorter();
createMenuBar();
createTree();
buildGUI();
}
/**
* Returns the selected tree.
*
* @return See above.
*/
JTree getTreeDisplay() { return treeDisplay; }
/** Sets the root of the tree. */
void setRootNode()
{
treeDisplay.removeAll();
DefaultTreeModel tm = (DefaultTreeModel) treeDisplay.getModel();
TreeBrowserDisplay root = model.getLastSelectedNode();
treeDisplay.setModel(new DefaultTreeModel(root));
tm.reload(root);
/*
treeDisplay.removeAll();
DefaultTreeModel tm = (DefaultTreeModel) treeDisplay.getModel();
TreeBrowserSet oldRoot = (TreeBrowserSet) tm.getRoot();
Set children = oldRoot.getChildrenDisplay();
TreeBrowserDisplay root = model.getLastSelectedNode();
treeDisplay.setModel(new DefaultTreeModel(root));
//addMenuToNode(root);
tm = (DefaultTreeModel) treeDisplay.getModel();
if (children == null || children.size() == 0) {
treeDisplay.expandPath(new TreePath(root.getPath()));
} else {
Iterator i = root.getChildrenDisplay().iterator();
TreeBrowserDisplay node, newNode;
Map<String, TreeBrowserDisplay>
map = new HashMap<String, TreeBrowserDisplay>();
while (i.hasNext()) {
node = (TreeBrowserDisplay) i.next();
map.put(node.toString(), node);
}
i = children.iterator();
while (i.hasNext()) {
node = (TreeBrowserDisplay) i.next();
if (node.isExpanded()) {
newNode = map.get(node.toString());
if (newNode != null) {
treeDisplay.expandPath(new TreePath(newNode.getPath()));
}
}
}
}
tm.reload(root);
*/
}
/**
* Creates a dummy loading node whose parent is the specified node.
*
* @param message The value of the default node.
*/
void addDefaultNode(String message)
{
addDefaultNode(model.getRoot(), message);
}
/**
* Creates a dummy loading node to the specified node.
*
* @param node The parent of the default node.
* @param message The value of the default node.
*/
void addDefaultNode(TreeBrowserDisplay node, String message)
{
DefaultTreeModel tm = (DefaultTreeModel) treeDisplay.getModel();
node.removeAllChildren();
node.removeAllChildrenDisplay();
if (message != null)
tm.insertNodeInto(new TreeBrowserNode(message), node,
node.getChildCount());
tm.reload(node);
}
/**
* Adds the nodes to the specified parent node.
*
* @param parent The parent node.
* @param nodes The nodes to add.
*/
void setNodes(TreeBrowserDisplay parent, Collection nodes)
{
List sortedNodes = sorter.sort(nodes);
DefaultTreeModel tm = (DefaultTreeModel) treeDisplay.getModel();
parent.removeAllChildren();
parent.removeAllChildrenDisplay();
Iterator i = sortedNodes.iterator();
TreeBrowserDisplay child;
//addMenuToNode(parent);
while (i.hasNext()) {
child = (TreeBrowserDisplay) i.next();
if (!(child instanceof TreeBrowserNode))
addMenuToNode(child);
parent.addChildDisplay(child);
tm.insertNodeInto(child, parent, parent.getChildCount());
}
tm.reload(parent);
}
/**
* Reacts to selection in the management menu.
* @see ActionListener#actionPerformed(ActionEvent)
*/
public void actionPerformed(ActionEvent e)
{
int index = Integer.parseInt(e.getActionCommand());
switch (index) {
case VIEW:
controller.browser(model.getSelectedNodes());
break;
}
}
}