Java tutorial
/* * 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 * <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()); } } } }