org.openmicroscopy.shoola.agents.util.finder.AdvancedFinder.java Source code

Java tutorial

Introduction

Here is the source code for org.openmicroscopy.shoola.agents.util.finder.AdvancedFinder.java

Source

/*
 * org.openmicroscopy.shoola.agents.util.finder.AdvancedFinder 
 *
 *------------------------------------------------------------------------------
 *  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.util.finder;

//Java imports
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

//Third-party libraries
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;

//Application-internal dependencies
import org.openmicroscopy.shoola.agents.dataBrowser.DataBrowserAgent;
import org.openmicroscopy.shoola.agents.dataBrowser.view.SearchComponent;
import org.openmicroscopy.shoola.agents.treeviewer.TreeViewerAgent;
import org.openmicroscopy.shoola.agents.util.EditorUtil;
import org.openmicroscopy.shoola.agents.util.SelectionWizard;
import org.openmicroscopy.shoola.agents.util.ViewerSorter;
import org.openmicroscopy.shoola.agents.util.ui.UserManagerDialog;
import org.openmicroscopy.shoola.env.LookupNames;
import org.openmicroscopy.shoola.env.data.util.AdvancedSearchResult;
import org.openmicroscopy.shoola.env.data.util.AdvancedSearchResultCollection;
import org.openmicroscopy.shoola.env.data.util.SearchDataContext;
import org.openmicroscopy.shoola.env.data.util.SearchParameters;
import org.openmicroscopy.shoola.env.data.util.SecurityContext;
import org.openmicroscopy.shoola.env.ui.UserNotifier;
import org.openmicroscopy.shoola.util.ui.IconManager;
import org.openmicroscopy.shoola.util.ui.UIUtilities;
import org.openmicroscopy.shoola.util.ui.search.GroupContext;
import org.openmicroscopy.shoola.util.ui.search.SearchContext;
import org.openmicroscopy.shoola.util.ui.search.SearchHelp;
import org.openmicroscopy.shoola.util.ui.search.SearchUtil;

import pojos.DataObject;
import pojos.DatasetData;
import pojos.ExperimenterData;
import pojos.GroupData;
import pojos.ImageData;
import pojos.PlateData;
import pojos.ProjectData;
import pojos.ScreenData;
import pojos.TagAnnotationData;
import pojos.WellData;

/** 
 * The class actually managing the search.
 *
 * @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
 * <small>
 * (<b>Internal version:</b> $Revision: $Date: $)
 * </small>
 * @since OME3.0
 */
public class AdvancedFinder extends SearchComponent implements Finder, PropertyChangeListener {

    /** URL which links to the search help website */
    private static final String HELP_URL = "http://help.openmicroscopy.org/search.html";

    /** The default title of the notification message. */
    private static final String TITLE = "Search";

    /** Reference to the component handling data. */
    private FinderLoader loader;

    /** One of the constants defined by this class. */
    private int state;

    /** Collection of selected users. */
    private Map<Long, ExperimenterData> users;

    /** The collection of tags. */
    private Collection tags;

    /** Host the result per group.*/
    private AdvancedSearchResultCollection results = new AdvancedSearchResultCollection();

    /** The identifier of the group.*/
    private long groupId;

    /** The components used to sort the nodes.*/
    private ViewerSorter sorter;

    /** The display mode e.g. Experimenter/Group.*/
    private int displayMode;

    /**
     * Returns the name of the group corresponding to the security context.
     * 
     * @param ctx The context to handle.
     * @return See above
     */
    private String getGroupName(SecurityContext ctx) {
        Iterator<GroupData> i = groups.iterator();
        GroupData g;
        while (i.hasNext()) {
            g = i.next();
            if (g.getId() == ctx.getGroupID())
                return g.getName();
        }
        return null;
    }

    /**
     * Determines the scope of the search.
     * 
     * @param value The value to convert.
     * @return See above.
     */
    private Integer convertScope(int value) {
        switch (value) {
        case SearchContext.TEXT_ANNOTATION:
            return SearchParameters.TEXT_ANNOTATION;
        case SearchContext.TAGS:
            return SearchParameters.TAGS;
        case SearchContext.URL_ANNOTATION:
            return SearchParameters.URL_ANNOTATION;
        case SearchContext.FILE_ANNOTATION:
            return SearchParameters.FILE_ANNOTATION;
        case SearchContext.NAME:
            return SearchParameters.NAME;
        case SearchContext.DESCRIPTION:
            return SearchParameters.DESCRIPTION;
        case SearchContext.CUSTOMIZED:
            return SearchParameters.CUSTOMIZED;
        case SearchContext.ANNOTATION:
            return SearchParameters.ANNOTATION;
        default:
            return null;
        }
    }

    /**
     * Determines the type of the search.
     * 
     * @param value The value to convert.
     * @return See above.
     */
    private Class<? extends DataObject> convertType(int value) {
        switch (value) {
        case SearchContext.DATASETS:
            return DatasetData.class;
        case SearchContext.PROJECTS:
            return ProjectData.class;
        case SearchContext.IMAGES:
            return ImageData.class;
        case SearchContext.SCREENS:
            return ScreenData.class;
        case SearchContext.PLATES:
            return PlateData.class;
        case SearchContext.WELLS:
            return WellData.class;
        default:
            return null;
        }
    }

    /**
     * Creates and returns the list of users corresponding to the collection
     * of names.
     * 
     * @param names Collection of names to handle.
     * @return See above.
     */
    private List<ExperimenterData> fillUsersList(List<Long> names) {
        List<ExperimenterData> l = new ArrayList<ExperimenterData>();
        if (names == null)
            return l;
        Iterator i = names.iterator();
        Long id;
        ExperimenterData user;
        while (i.hasNext()) {
            id = (Long) i.next();
            user = users.get(id);
            if (user != null && !l.contains(user))
                l.add(user);
        }
        return l;
    }

    /**
     * Fills the passed lists depending on the specified context.
     * 
     * @param usersContext   The context.
     * @param toKeep      The users to consider.
     * @param toExclude      The users to exclude.
     */
    private void fillUsersList(List<Integer> usersContext, List<ExperimenterData> toKeep,
            List<ExperimenterData> toExclude) {
        if (usersContext == null) {
            toKeep.clear();
            toExclude.clear();
            return;
        }
        switch (usersContext.size()) {
        case 2:
            if (toKeep.size() >= 0)
                toKeep.add(getUserDetails());
            else {
                toKeep.clear();
                toExclude.clear();
            }
            break;
        case 1:
            if (usersContext.contains(SearchContext.CURRENT_USER)) {
                toKeep.clear();
                toExclude.clear();
                toKeep.add(getUserDetails());
            } else {
                if (toKeep.size() == 0)
                    toExclude.add(getUserDetails());
            }
        }
    }

    /**
     * Converts the UI context into a context to search for.
     * 
     * @param ctx The value to convert.
     */
    private void handleSearchContext(SearchContext ctx) {
        String query = ctx.getQuery();
        UserNotifier un = FinderFactory.getRegistry().getUserNotifier();
        Timestamp start = ctx.getStartTime();
        Timestamp end = ctx.getEndTime();
        if (start != null && end != null && start.after(end)) {
            un.notifyInfo(TITLE, "The selected time interval is not valid.");
            return;
        }

        if (StringUtils.isEmpty(query) && start == null && end == null) {
            un.notifyInfo(TITLE, "Please enter a term to search for " + "or a valid time interval.");
            return;
        }

        List<Integer> context = ctx.getContext();
        if (context == null || context.size() == 0) {
            context = new ArrayList<Integer>();
            context.add(SearchContext.CUSTOMIZED);
        }
        List<Integer> scope = new ArrayList<Integer>(context.size());
        Iterator i = context.iterator();
        Integer v;
        while (i.hasNext()) {
            v = convertScope((Integer) i.next());
            if (v != null)
                scope.add(v);
        }
        List<Class<? extends DataObject>> types = new ArrayList<Class<? extends DataObject>>();
        i = ctx.getType().iterator();
        Class<? extends DataObject> k;
        while (i.hasNext()) {
            k = convertType((Integer) i.next());
            if (k != null)
                types.add(k);
        }

        SearchParameters searchContext = new SearchParameters(scope, types, query);
        searchContext.setTimeInterval(start, end, ctx.getTimeType());
        searchContext.setUserId(ctx.getSelectedOwner());

        SecurityContext secCtx;

        if (ctx.getSelectedGroup() == GroupContext.ALL_GROUPS_ID) {
            secCtx = new SecurityContext(getUserDetails().getGroupId());
            searchContext.setGroupId(SearchParameters.ALL_GROUPS_ID);
        } else {
            secCtx = new SecurityContext(ctx.getSelectedGroup());
            searchContext.setGroupId(ctx.getSelectedGroup());
        }

        loader = new AdvancedFinderLoader(this, secCtx, searchContext);
        loader.load();
        state = Finder.SEARCH;
        setSearchEnabled(true);
    }

    /**
     * Returns the current user's details.
     * 
     * @return See above.
     */
    private ExperimenterData getUserDetails() {
        return (ExperimenterData) FinderFactory.getRegistry().lookup(LookupNames.CURRENT_USER_DETAILS);
    }

    /** Displays the widget allowing the select users. */
    private void showUserSelection() {
        IconManager icons = IconManager.getInstance();
        UserManagerDialog dialog = new UserManagerDialog(FinderFactory.getRefFrame(), getUserDetails(),
                getUserDetails().getDefaultGroup(), null, icons.getIcon(IconManager.OWNER),
                icons.getIcon(IconManager.OWNER_48));
        dialog.addPropertyChangeListener(this);
        dialog.setDefaultSize();
        UIUtilities.centerAndShow(dialog);
    }

    /**
     * Creates a list of controls to add to the searching component.
     * 
     * @return See above.
     */
    private List<JButton> createControls() {
        List<JButton> list = new ArrayList<JButton>();
        IconManager icons = IconManager.getInstance();
        JButton button = new JButton(icons.getIcon(IconManager.TAG));
        UIUtilities.unifiedButtonLookAndFeel(button);
        button.setToolTipText("Load existing Tags to search by.");
        button.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                loadTags();
            }
        });
        list.add(button);
        return list;
    }

    /** Loads the tags. */
    private void loadTags() {
        if (tags == null) {
            List<SecurityContext> l = new ArrayList<SecurityContext>();
            Iterator<GroupData> i = groups.iterator();
            while (i.hasNext()) {
                l.add(new SecurityContext(i.next().getId()));
            }
            TagsLoader loader = new TagsLoader(this, l);
            loader.load();
        } else
            setExistingTags(tags);
    }

    /**
     * Handles the selection.
     * 
     * @param selected The selected tags.
     */
    private void handleTagsSelection(Collection selected) {
        List<String> toAdd = new ArrayList<String>();
        if (selected == null || selected.size() == 0) {
            setTerms(toAdd);
            return;
        }
        Iterator i = selected.iterator();
        TagAnnotationData tag;
        String value;
        while (i.hasNext()) {
            tag = (TagAnnotationData) i.next();
            value = tag.getTagValue();
            if (value.contains(SearchUtil.SPACE_SEPARATOR)) {
                toAdd.add(SearchUtil.QUOTE_SEPARATOR + value + SearchUtil.QUOTE_SEPARATOR);
            } else
                toAdd.add(value);
        }
        setTerms(toAdd);
    }

    /** 
     * Creates a new instance.
     * 
     * @param groups The available groups.
     */
    AdvancedFinder(Collection<GroupData> groups) {
        //sort
        displayMode = LookupNames.EXPERIMENTER_DISPLAY;
        sorter = new ViewerSorter();
        List<GroupData> l = sorter.sort(groups);
        initialize(l);
        addPropertyChangeListener(SEARCH_PROPERTY, this);
        addPropertyChangeListener(CANCEL_SEARCH_PROPERTY, this);
        addPropertyChangeListener(OWNER_PROPERTY, this);
        users = new HashMap<Long, ExperimenterData>();
    }

    /**
     * Brings up the <code>Help</code> dialog.
     * @see #help()
     */
    protected void help() {
        SearchHelp help = new SearchHelp(FinderFactory.getRefFrame(), HELP_URL);
        UIUtilities.centerAndShow(help);

        if (help.hasError()) {
            showWebbrowserError(HELP_URL);
        }
    }

    /**
     * Pops up an UserNotifier indicating that the webbrowser
     * for the help website couldn't be opened
     * @param url
     */
    public void showWebbrowserError(String url) {
        TreeViewerAgent.getRegistry().getUserNotifier().notifyError("Could not open web browser",
                "Please open your web browser and go to page: " + url);
    }

    /** 
     * Implemented as specified by {@link Finder} I/F
     * @see Finder#cancel()
     */
    public void cancel() {
        if (loader != null)
            loader.cancel();
        results.clear();
        state = DISCARDED;
    }

    /** 
     * Implemented as specified by {@link Finder} I/F
     * @see Finder#getState()
     */
    public int getState() {
        return state;
    }

    /** 
     * Implemented as specified by {@link Finder} I/F
     * @see Finder#dispose()
     */
    public void dispose() {
        setSearchEnabled(false);
        setVisible(false);
        cancel();
    }

    /** 
     * Implemented as specified by {@link Finder} I/F
     * @see Finder#setStatus(String, boolean)
     */
    public void setStatus(String text, boolean status) {
        if (text == null)
            text = "";
        setSearchEnabled(text, status);
    }

    /** 
     * Implemented as specified by {@link Finder} I/F
     * @see Finder#setResult(SecurityContext, Object)
     */
    public void setResult(AdvancedSearchResultCollection result) {
        if (result.isError()) {
            String msg = "";
            switch (result.getError()) {
            case AdvancedSearchResultCollection.GENERAL_ERROR:
                msg = "Invalid search expression";
                break;
            case AdvancedSearchResultCollection.TOO_MANY_RESULTS_ERROR:
                msg = "Too many results, please refine your search criteria.";
                break;
            case AdvancedSearchResultCollection.TOO_MANY_CLAUSES:
                msg = "Please try to narrow down your query. The wildcard matched too many terms.";
                break;
            }
            UserNotifier un = FinderFactory.getRegistry().getUserNotifier();
            un.notifyError("Search error", msg);
            setSearchEnabled(false);
            return;
        }

        results = result;
        setSearchEnabled(false);
        firePropertyChange(RESULTS_FOUND_PROPERTY, null, results);
    }

    /** 
     * Implemented as specified by {@link Finder} I/F
     * @see Finder#setExistingTags(Collection)
     */
    public void setExistingTags(Collection tags) {
        this.tags = tags;
        if (tags == null || tags.size() == 0) {
            UserNotifier un = FinderFactory.getRegistry().getUserNotifier();
            un.notifyInfo("Existing Tags", "No existing tags to search by.");
            return;
        }
        IconManager icons = IconManager.getInstance();
        String title = "Filter By Tags";
        String text = "Select the Tags to filter by.";
        Collection selected = new ArrayList<TagAnnotationData>();
        Iterator i = tags.iterator();
        TagAnnotationData tag;
        List<String> l = getTerms();
        Collection available = new ArrayList<TagAnnotationData>();

        while (i.hasNext()) {
            tag = (TagAnnotationData) i.next();
            if (l.contains(tag.getTagValue()))
                selected.add(tag);
            else
                available.add(tag);
        }
        SelectionWizard wizard = new SelectionWizard(DataBrowserAgent.getRegistry().getTaskBar().getFrame(),
                available, selected, TagAnnotationData.class, false, DataBrowserAgent.getUserDetails());
        wizard.setGroups(groups);
        wizard.setTitle(title, text, icons.getIcon(IconManager.TAG_48));
        wizard.addPropertyChangeListener(this);
        UIUtilities.centerAndShow(wizard);
    }

    /** 
     * Sets the current tags.
     * 
     * @param groupId The identifier of the group.
     */
    public void setCurrentGroup(long groupId) {
        if (this.groupId == groupId)
            return;
        this.groupId = groupId;
        tags = null;
    }

    /** 
     * Resets the component after switching users.
     * 
     * @param groups The collection of groups to handle.
     */
    public void reset(Collection<GroupData> groups) {
        sorter = new ViewerSorter();
        this.groups = sorter.sort(groups);
        users.clear();
        results.clear();
        if (tags != null)
            tags.clear();
        tags = null;
        groupsContext.clear();
        addResult(null, true);
        uiDelegate.reset();
    }

    /**
     * Sets the display mode e.g. Group Display
     * 
     * @param displayMode The value to set.
     */
    public void setDisplayMode(int displayMode) {
        this.displayMode = displayMode;
    }

    /**
     * Reacts to the property fired by the <code>SearchComponent</code>
     * @see PropertyChangeListener#propertyChange(PropertyChangeEvent)
     */
    public void propertyChange(PropertyChangeEvent evt) {
        String name = evt.getPropertyName();
        if (SEARCH_PROPERTY.equals(name)) {
            SearchContext ctx = (SearchContext) evt.getNewValue();
            if (ctx == null)
                return;
            handleSearchContext(ctx);
        } else if (CANCEL_SEARCH_PROPERTY.equals(name)) {
            cancel();
        } else if (OWNER_PROPERTY.equals(name)) {
            showUserSelection();
        } else if (UserManagerDialog.USER_SWITCH_PROPERTY.equals(name)) {
            Map m = (Map) evt.getNewValue();
            if (m == null)
                return;
            Iterator i = m.keySet().iterator();
            List<ExperimenterData> l;
            ExperimenterData exp;
            Iterator<ExperimenterData> j;
            while (i.hasNext()) {
                l = (List<ExperimenterData>) m.get(i.next());
                j = l.iterator();
                while (j.hasNext()) {
                    exp = j.next();
                    users.put(exp.getId(), exp);
                }
                //uiValue += value;
            }
            //setUserString(uiValue);
        } else if (SelectionWizard.SELECTED_ITEMS_PROPERTY.equals(name)) {
            Map m = (Map) evt.getNewValue();
            if (m == null || m.size() != 1)
                return;
            Set set = m.entrySet();
            Entry entry;
            Iterator i = set.iterator();
            Class type;
            while (i.hasNext()) {
                entry = (Entry) i.next();
                type = (Class) entry.getKey();
                handleTagsSelection((Collection) entry.getValue());
            }
        }
    }

}