/* *------------------------------------------------------------------------------ * 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.treeviewer.browser; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.swing.Action; import javax.swing.JTree; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.tree.TreePath; import org.apache.commons.collections.CollectionUtils; import org.openmicroscopy.shoola.agents.treeviewer.TreeViewerAgent; import org.openmicroscopy.shoola.agents.treeviewer.actions.BrowserDeleteAction; import org.openmicroscopy.shoola.agents.treeviewer.actions.BrowserImportAction; import org.openmicroscopy.shoola.agents.treeviewer.actions.BrowserManageAction; import org.openmicroscopy.shoola.agents.treeviewer.actions.BrowserPasswordResetAction; import org.openmicroscopy.shoola.agents.treeviewer.actions.BrowserRefreshAction; import org.openmicroscopy.shoola.agents.treeviewer.actions.CloseAction; import org.openmicroscopy.shoola.agents.treeviewer.actions.CollapseAction; import org.openmicroscopy.shoola.agents.treeviewer.actions.ShowNameAction; import org.openmicroscopy.shoola.agents.treeviewer.actions.SortAction; import org.openmicroscopy.shoola.agents.treeviewer.actions.SortByDateAction; import org.openmicroscopy.shoola.agents.treeviewer.view.TreeViewer; import org.openmicroscopy.shoola.agents.util.EditorUtil; import org.openmicroscopy.shoola.agents.util.browser.TreeFileSet; import org.openmicroscopy.shoola.agents.util.browser.TreeImageDisplay; import org.openmicroscopy.shoola.agents.util.browser.TreeImageSet; import org.openmicroscopy.shoola.agents.util.browser.TreeImageTimeSet; import org.openmicroscopy.shoola.env.ui.UserNotifier; import omero.gateway.model.DatasetData; import omero.gateway.model.ExperimenterData; import omero.gateway.model.FileAnnotationData; import omero.gateway.model.FileData; import omero.gateway.model.GroupData; import omero.gateway.model.ImageData; import omero.gateway.model.PlateData; import omero.gateway.model.PlateAcquisitionData; import omero.gateway.model.ProjectData; import omero.gateway.model.ScreenData; import omero.gateway.model.TagAnnotationData; /** * The Browser's Controller. * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @version 2.2 * @since OME2.2 */ class BrowserControl implements ChangeListener { /** Identifies the <code>Collapse</code> action. */ static final Integer COLLAPSE = Integer.valueOf(0); /** Identifies the <code>Close</code> action. */ static final Integer CLOSE = Integer.valueOf(1); /** Identifies the <code>Sort</code> action. */ static final Integer SORT = Integer.valueOf(2); /** Identifies the <code>Sort by Date</code> action. */ static final Integer SORT_DATE = Integer.valueOf(3); /** Identifies the <code>Partial Name</code> action.*/ static final Integer PARTIAL_NAME = Integer.valueOf(4); /** Identifies the <code>Info</code> action. */ static final Integer INFO = Integer.valueOf(5); /** Identifies the <code>Delete</code> action. */ static final Integer DELETE = Integer.valueOf(6); /** Identifies the <code>New container</code> action. */ static final Integer NEW_CONTAINER = Integer.valueOf(7); /** Identifies the <code>New tag</code> action. */ static final Integer NEW_TAG = Integer.valueOf(8); /** Identifies the <code>Import</code> action. */ static final Integer IMPORT = Integer.valueOf(9); /** Identifies the <code>Refresh</code> action. */ static final Integer REFRESH = Integer.valueOf(10); /** Identifies the <code>New Admin</code> action. */ static final Integer NEW_ADMIN = Integer.valueOf(11); /** Identifies the <code>Reset Password</code> action. */ static final Integer RESET_PASSWORD = Integer.valueOf(12); /** Identifies the <code>New container</code> action. */ static final Integer CUT = Integer.valueOf(13); /** Identifies the <code>New container</code> action. */ static final Integer COPY = Integer.valueOf(14); /** Identifies the <code>New container</code> action. */ static final Integer PASTE = Integer.valueOf(15); /** * Reference to the {@link Browser} component, which, in this context, * is regarded as the Model. */ private Browser model; /** Reference to the View. */ private BrowserUI view; /** Maps actions identifiers onto actual <code>Action</code> object. */ private Map<Integer, Action> actionsMap; /** Helper method to create all the UI actions. */ private void createActions() { actionsMap.put(COLLAPSE, new CollapseAction(model)); actionsMap.put(CLOSE, new CloseAction(model)); actionsMap.put(SORT, new SortAction(model)); actionsMap.put(SORT_DATE, new SortByDateAction(model)); actionsMap.put(PARTIAL_NAME, new ShowNameAction(model)); actionsMap.put(DELETE, new BrowserDeleteAction(model)); actionsMap.put(NEW_CONTAINER, new BrowserManageAction(model, BrowserManageAction.NEW_CONTAINERS)); actionsMap.put(NEW_ADMIN, new BrowserManageAction(model, BrowserManageAction.NEW_ADMIN)); actionsMap.put(NEW_TAG, new BrowserManageAction(model, BrowserManageAction.NEW_TAGS)); actionsMap.put(IMPORT, new BrowserImportAction(model)); actionsMap.put(REFRESH, new BrowserRefreshAction(model)); actionsMap.put(RESET_PASSWORD, new BrowserPasswordResetAction(model)); actionsMap.put(CUT, new BrowserManageAction(model, BrowserManageAction.CUT)); actionsMap.put(COPY, new BrowserManageAction(model, BrowserManageAction.COPY)); actionsMap.put(PASTE, new BrowserManageAction(model, BrowserManageAction.PASTE)); } /** * Creates a new instance. * The {@link #initialize(BrowserUI) initialize} method * should be called straight after to link this Controller to the other * MVC components. * * @param model Reference to the {@link Browser} component, which, in * this context, is regarded as the Model. * Mustn't be <code>null</code>. */ BrowserControl(Browser model) { if (model == null) throw new NullPointerException("No model."); this.model = model; actionsMap = new HashMap<Integer, Action>(); createActions(); } /** * Links this Controller to its Model and its View. * * @param view Reference to the View. Mustn't be <code>null</code>. */ void initialize(BrowserUI view) { if (view == null) throw new NullPointerException("No view."); this.view = view; model.addChangeListener(this); } /** * Selects the specified nodes. * * @param nodes The nodes to select. * @param updateView Pass <code>true</code> to update the view, * <code>false</code> otherwise. */ void selectNodes(List nodes, Class ref) { if (CollectionUtils.isEmpty(nodes)) return; //make sure we have node of the same type. Iterator<?> i = nodes.iterator(); TreeImageDisplay n; List<TreeImageDisplay> values = new ArrayList<TreeImageDisplay>(); Object o; while (i.hasNext()) { n = (TreeImageDisplay) i.next(); o = n.getUserObject(); if (o.getClass().equals(ref)) values.add(n); } if (CollectionUtils.isEmpty(values)) return; TreeImageDisplay[] array = values.toArray( new TreeImageDisplay[values.size()]); model.setSelectedDisplays(array, false); view.setFoundNode(array); } /** * Invokes the right-click is selected. */ void onRightClick(TreeImageDisplay node) { TreeImageDisplay d = model.getLastSelectedDisplay(); if (node != d) { model.setSelectedDisplay(node); } } /** * Reacts to tree expansion events. * * @param display The selected node. * @param expanded Pass <code>true</code> if the node is expanded, * <code>false</code> otherwise. */ void onNodeNavigation(TreeImageDisplay display, boolean expanded) { display.setExpanded(expanded); Object ho = display.getUserObject(); if (model.getBrowserType() == Browser.FILE_SYSTEM_EXPLORER) { if (ho instanceof FileData) { FileData f = (FileData) ho; if (f.isDirectory()) model.loadDirectory(display); return; } else if ((ho instanceof ImageData) && display.isChildrenLoaded()) return; } if (!expanded) { model.cancel(); return; } int state = model.getState(); if (state == Browser.LOADING_DATA || state == Browser.LOADING_LEAVES) return; model.setSelectedDisplay(display); int browserType = model.getBrowserType(); if ((browserType == Browser.IMAGES_EXPLORER || browserType == Browser.FILES_EXPLORER) && !display.isChildrenLoaded() && (ho instanceof ExperimenterData || ho instanceof GroupData)) { model.countExperimenterImages(display); return; } if (display.isChildrenLoaded()) { if (view.isFirstChildMessage(display)) { List<?> l = display.getChildrenDisplay(); List<Object> list = new ArrayList<Object>(l.size()); Iterator<?> i = l.iterator(); while (i.hasNext()) { list.add(i.next()); } view.setLeavesViews(list, (TreeImageSet) display); } return; } if (ho instanceof ProjectData || ho instanceof ScreenData || ho instanceof PlateData || ho instanceof GroupData) { if (display.getNumberOfItems() == 0) return; } TreeImageDisplay node; if (display instanceof TreeImageTimeSet || display instanceof TreeFileSet) { view.loadAction(display); switch (model.getDisplayMode()) { case TreeViewer.GROUP_DISPLAY: node = EditorUtil.getDataGroup(display); break; case TreeViewer.EXPERIMENTER_DISPLAY: default: node = BrowserFactory.getDataOwner(display); } model.loadExperimenterData(node, display); return; } if (ho instanceof DatasetData || ho instanceof TagAnnotationData) { view.loadAction(display); //Load the data of the logged in user. switch (model.getDisplayMode()) { case TreeViewer.GROUP_DISPLAY: node = EditorUtil.getDataGroup(display); break; case TreeViewer.EXPERIMENTER_DISPLAY: default: node = BrowserFactory.getDataOwner(display); } model.loadExperimenterData(node, display); } else if (ho instanceof ExperimenterData) { view.loadAction(display); model.loadExperimenterData(display, null); } else if (ho instanceof GroupData) { if (browserType == Browser.ADMIN_EXPLORER) { view.loadAction(display); model.loadExperimenterData(display, display); } else { //Load the data of the logged in user. switch (model.getDisplayMode()) { case TreeViewer.GROUP_DISPLAY: view.loadAction(display); model.loadExperimenterData(display, null); break; case TreeViewer.EXPERIMENTER_DISPLAY: default: List<?> l = display.getChildrenDisplay(); if (l != null & l.size() > 0) { view.expandNode((TreeImageDisplay) l.get(0), true); } } } } } /** * Brings up the pop-up menu. * * @param index The index of the menu. */ void showPopupMenu(int index) { model.showPopupMenu(index); } /** * Reacts to click events in the tree. * * @param added The collection of added paths. */ void onClick(List<TreePath> added) { JTree tree = view.getTreeDisplay(); TreePath[] paths = tree.getSelectionPaths(); if (paths == null) { return; } TreeImageDisplay node; TreePath path; List<TreePath> toRemove = new ArrayList<TreePath>(); TreeImageDisplay[] nodes; if (paths.length == 1) { Object p = paths[0].getLastPathComponent(); if (!(p instanceof TreeImageDisplay)) return; node = (TreeImageDisplay) p; if (node.isSelectable()) { nodes = new TreeImageDisplay[1]; nodes[0] = node; model.setSelectedDisplays(nodes, false); } else { toRemove.add(paths[0]); view.removeTreePaths(toRemove); paths = tree.getSelectionPaths(); nodes = new TreeImageDisplay[paths.length]; for (int j = 0; j < paths.length; j++) { nodes[j] = (TreeImageDisplay) paths[j].getLastPathComponent(); } model.setSelectedDisplays(nodes, false); } return; } //more than one node selected. TreeImageDisplay previous = model.getLastSelectedDisplay(); Class<?> ref = null; Object ho = null; if (previous != null) { ho = previous.getUserObject(); ref = ho.getClass(); } List<TreeImageDisplay> l = new ArrayList<TreeImageDisplay>(); TagAnnotationData tag; String ns = null; if (TagAnnotationData.class.equals(ref)) { ns = ((TagAnnotationData) ho).getNameSpace(); } if (added != null) { Iterator<TreePath> i = added.iterator(); Object nho; String nsNode; Object lastPath; while (i.hasNext()) { path = i.next(); lastPath = path.getLastPathComponent(); if (lastPath instanceof TreeImageDisplay) { node = (TreeImageDisplay) lastPath; nho = node.getUserObject(); if (nho.getClass().equals(ref) && node.isSelectable()) { if (nho.getClass().equals(TagAnnotationData.class)) { nsNode = ((TagAnnotationData) nho).getNameSpace(); if (ns == null && nsNode == null) l.add(node); else if (ns == null && nsNode != null && TagAnnotationData.INSIGHT_TAGSET_NS.equals( nsNode)) toRemove.add(path); else if (ns != null && nsNode == null && TagAnnotationData.INSIGHT_TAGSET_NS.equals( ns)) toRemove.add(path); else if (ns != null && nsNode != null) { if (ns.equals(nsNode)) l.add(node); } } else l.add(node); } else toRemove.add(path); } } } if (toRemove.size() > 0) { String text = null; if (ImageData.class.equals(ref)) text = "Images."; else if (ProjectData.class.equals(ref)) text = "Projects."; else if (DatasetData.class.equals(ref)) text = "Datasets."; else if (ScreenData.class.equals(ref)) text = "Screens."; else if (PlateData.class.equals(ref)) text = "Plates."; else if (PlateAcquisitionData.class.equals(ref)) text = "Acquisitions."; else if (TagAnnotationData.class.equals(ref)) { tag = (TagAnnotationData) ho; if (TagAnnotationData.INSIGHT_TAGSET_NS.equals( tag.getNameSpace())) text = "Tag Sets."; else text = "Tags."; } else if (FileAnnotationData.class.equals(ref)) text = "Files."; else if (FileData.class.equals(ref)) text = "Files."; else if (ExperimenterData.class.equals(ref)) text = "Experimenters"; else if (GroupData.class.equals(ref)) text = "User Groups"; //smart folder selected if (text == null) text = "nodes of the same type."; UserNotifier un = TreeViewerAgent.getRegistry().getUserNotifier(); un.notifyInfo("Tree selection", "You can only select "+text); view.removeTreePaths(toRemove); } paths = tree.getSelectionPaths(); List<TreeImageDisplay> list = new ArrayList<TreeImageDisplay>(); if (paths != null) { for (int j = 0; j < paths.length; j++) { if (paths[j].getLastPathComponent() instanceof TreeImageDisplay) list.add((TreeImageDisplay) paths[j].getLastPathComponent()); } } if (list.size() > 0) { model.setSelectedDisplays(list.toArray( new TreeImageDisplay[list.size()]), false); } } /** * Returns the action corresponding to the specified id. * * @param id One of the flags defined by this class. * @return The specified action. */ Action getAction(Integer id) { return actionsMap.get(id); } /** * Detects when the {@link Browser} is ready and then registers for * property change notification. * @see ChangeListener#stateChanged(ChangeEvent) */ public void stateChanged(ChangeEvent e) { int state = model.getState(); switch (state) { case Browser.BROWSING_DATA: break; default: break; } view.onStateChanged(state == Browser.READY); } }