/*
*------------------------------------------------------------------------------
* 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.view;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.swing.Action;
import org.apache.commons.collections.CollectionUtils;
import org.openmicroscopy.shoola.agents.dataBrowser.DataBrowserAgent;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.ActivatedUserAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.DownloadAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.FieldsViewAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.ManageObjectAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.ManageRndSettingsAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.MoveToAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.PasswordResetAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.RefreshAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.SaveAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.SendFeedbackAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.TaggingAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.ViewAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.ViewInPluginAction;
import org.openmicroscopy.shoola.agents.dataBrowser.actions.ViewOtherAction;
import org.openmicroscopy.shoola.agents.dataBrowser.browser.Browser;
import org.openmicroscopy.shoola.agents.dataBrowser.browser.CellDisplay;
import org.openmicroscopy.shoola.agents.dataBrowser.browser.ImageDisplay;
import org.openmicroscopy.shoola.agents.dataBrowser.browser.ImageNode;
import org.openmicroscopy.shoola.agents.dataBrowser.browser.RollOverNode;
import org.openmicroscopy.shoola.agents.dataBrowser.browser.Thumbnail;
import org.openmicroscopy.shoola.agents.dataBrowser.util.FilteringDialog;
import org.openmicroscopy.shoola.agents.dataBrowser.util.QuickFiltering;
import org.openmicroscopy.shoola.agents.util.SelectionWizard;
import org.openmicroscopy.shoola.agents.util.ViewerSorter;
import org.openmicroscopy.shoola.agents.util.ui.EditorDialog;
import org.openmicroscopy.shoola.agents.util.ui.RollOverThumbnailManager;
import org.openmicroscopy.shoola.env.LookupNames;
import org.openmicroscopy.shoola.env.data.model.ApplicationData;
import org.openmicroscopy.shoola.env.data.util.FilterContext;
import omero.gateway.SecurityContext;
import org.openmicroscopy.shoola.util.ui.PlateGrid;
import org.openmicroscopy.shoola.util.ui.PlateGridObject;
import org.openmicroscopy.shoola.util.ui.search.SearchObject;
import omero.gateway.model.DataObject;
import omero.gateway.model.DatasetData;
import omero.gateway.model.ExperimenterData;
import omero.gateway.model.GroupData;
import omero.gateway.model.ImageData;
import omero.gateway.model.PlateAcquisitionData;
import omero.gateway.model.WellSampleData;
/**
* The DataBrowser's Controller.
*
* @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 DataBrowserControl
implements PropertyChangeListener
{
/** Identifies the <code>View action</code>. */
static final Integer VIEW = Integer.valueOf(0);
/** Identifies the <code>Copy object action</code>. */
static final Integer COPY_OBJECT = Integer.valueOf(1);
/** Identifies the <code>Paste object action</code>. */
static final Integer PASTE_OBJECT = Integer.valueOf(2);
/** Identifies the <code>Remove object action</code>. */
static final Integer REMOVE_OBJECT = Integer.valueOf(3);
/** Identifies the <code>Cut object action</code>. */
static final Integer CUT_OBJECT = Integer.valueOf(4);
/** Identifies the <code>Paste rendering settings action</code>. */
static final Integer PASTE_RND_SETTINGS = Integer.valueOf(5);
/** Identifies the <code>Copy rendering settings action</code>. */
static final Integer COPY_RND_SETTINGS = Integer.valueOf(6);
/** Identifies the <code>Reset rendering settings action</code>. */
static final Integer RESET_RND_SETTINGS = Integer.valueOf(7);
/**
* Identifies the <code>Set the min/max for each channel</code>.
*/
static final Integer SET_MIN_MAX_SETTINGS = Integer.valueOf(8);
/** Identifies the <code>Refresh</code> action. */
static final Integer REFRESH = Integer.valueOf(9);
/** Identifies the <code>Save As</code> action. */
static final Integer SAVE_AS = Integer.valueOf(10);
/** Identifies the <code>Tag</code> action. */
static final Integer TAG = Integer.valueOf(11);
/** Identifies the <code>Fields View</code> action. */
static final Integer FIELDS_VIEW = Integer.valueOf(13);
/** Identifies the <code>Fields View</code> action. */
static final Integer OPEN_WITH = Integer.valueOf(14);
/**
* Identifies the <code>Set the original rendering settings action</code>.
*/
static final Integer SET_OWNER_RND_SETTINGS = Integer.valueOf(15);
/** Identifies the <code>Send Feedback action</code>. */
static final Integer SEND_FEEDBACK = Integer.valueOf(16);
/** Identifies the <code>View in ImageJ action</code>.*/
static final Integer VIEW_IN_IJ = Integer.valueOf(17);
/** Identifies the <code>View in KNIME action</code>.*/
static final Integer VIEW_IN_KNIME = Integer.valueOf(18);
/** Identifies the <code>RESET PASSWORD action</code>.*/
static final Integer RESET_PASSWORD = Integer.valueOf(19);
/** Identifies the <code>USER ACTIVATED action</code>.*/
static final Integer USER_ACTIVATED = Integer.valueOf(20);
/** Identifies the <code>Download action</code>.*/
static final Integer DOWNLOAD = Integer.valueOf(21);
/**
* Reference to the {@link DataBrowser} component, which, in this context,
* is regarded as the Model.
*/
private DataBrowser model;
/** Reference to the view. */
private DataBrowserUI view;
/** Maps actions ids onto actual <code>Action</code> object. */
private Map<Integer, Action> actionsMap;
/** One per group.*/
private List<MoveToAction> moveActions;
/** Helper method to create all the UI actions. */
private void createActions()
{
actionsMap.put(VIEW_IN_KNIME, new ViewInPluginAction(model,
LookupNames.KNIME));
actionsMap.put(VIEW_IN_IJ, new ViewInPluginAction(model,
LookupNames.IMAGE_J));
actionsMap.put(VIEW, new ViewAction(model));
actionsMap.put(COPY_OBJECT, new ManageObjectAction(model,
ManageObjectAction.COPY));
actionsMap.put(PASTE_OBJECT, new ManageObjectAction(model,
ManageObjectAction.PASTE));
actionsMap.put(REMOVE_OBJECT, new ManageObjectAction(model,
ManageObjectAction.REMOVE));
actionsMap.put(CUT_OBJECT, new ManageObjectAction(model,
ManageObjectAction.CUT));
actionsMap.put(PASTE_RND_SETTINGS, new ManageRndSettingsAction(model,
ManageRndSettingsAction.PASTE));
actionsMap.put(COPY_RND_SETTINGS, new ManageRndSettingsAction(model,
ManageRndSettingsAction.COPY));
actionsMap.put(RESET_RND_SETTINGS, new ManageRndSettingsAction(model,
ManageRndSettingsAction.RESET));
actionsMap.put(REFRESH, new RefreshAction(model));
actionsMap.put(SET_MIN_MAX_SETTINGS,
new ManageRndSettingsAction(model,
ManageRndSettingsAction.SET_MIN_MAX));
actionsMap.put(SET_OWNER_RND_SETTINGS,
new ManageRndSettingsAction(model,
ManageRndSettingsAction.SET_OWNER));
actionsMap.put(SAVE_AS, new SaveAction(model));
actionsMap.put(TAG, new TaggingAction(model));
actionsMap.put(FIELDS_VIEW, new FieldsViewAction(model));
actionsMap.put(OPEN_WITH, new ViewOtherAction(model, null));
actionsMap.put(SEND_FEEDBACK, new SendFeedbackAction(model));
actionsMap.put(USER_ACTIVATED, new ActivatedUserAction(model));
actionsMap.put(RESET_PASSWORD, new PasswordResetAction(model));
actionsMap.put(DOWNLOAD, new DownloadAction(model));
}
/**
* Filters the nodes.
*
* @param filter The selected filter.
*/
private void filterNodes(SearchObject filter)
{
if (filter == null) return;
List<String> values = filter.getResult();
switch (filter.getIndex()) {
case QuickSearch.FULL_TEXT:
view.setFilterLabel(SearchComponent.NAME_TEXT);
if (!CollectionUtils.isEmpty(values))
model.filterByFullText(values);
else {
view.setFilterLabel("");
model.showAll();
}
break;
case QuickSearch.TAGS:
view.setFilterLabel(SearchComponent.NAME_TAGS);
if (!CollectionUtils.isEmpty(values))
model.filterByTags(values);
else {
showAll();
}
break;
case QuickSearch.COMMENTS:
view.setFilterLabel(SearchComponent.NAME_COMMENTS);
if (!CollectionUtils.isEmpty(values))
model.filterByComments(values);
else {
view.setFilterLabel("");
model.showAll();
}
break;
case QuickSearch.RATED_ONE_OR_BETTER:
view.setFilterLabel(SearchComponent.NAME_RATE);
model.filterByRate(DataBrowser.RATE_ONE);
break;
case QuickSearch.RATED_TWO_OR_BETTER:
view.setFilterLabel(SearchComponent.NAME_RATE);
model.filterByRate(DataBrowser.RATE_TWO);
break;
case QuickSearch.RATED_THREE_OR_BETTER:
view.setFilterLabel(SearchComponent.NAME_RATE);
model.filterByRate(DataBrowser.RATE_THREE);
break;
case QuickSearch.RATED_FOUR_OR_BETTER:
view.setFilterLabel(SearchComponent.NAME_RATE);
model.filterByRate(DataBrowser.RATE_FOUR);
break;
case QuickSearch.RATED_FIVE:
view.setFilterLabel(SearchComponent.NAME_RATE);
model.filterByRate(DataBrowser.RATE_FIVE);
break;
case QuickSearch.UNRATED:
view.setFilterLabel(SearchComponent.UNRATED);
model.filterByRate(DataBrowser.UNRATED);
break;
case QuickSearch.SHOW_ALL:
view.setFilterLabel("");
model.showAll();
break;
case QuickSearch.TAGGED:
view.setFilterLabel(SearchComponent.TAGGED_TEXT);
model.filterByTagged(true);
break;
case QuickSearch.UNTAGGED:
view.setFilterLabel(SearchComponent.UNTAGGED_TEXT);
model.filterByTagged(false);
break;
case QuickSearch.COMMENTED:
view.setFilterLabel(SearchComponent.COMMENTED_TEXT);
model.filterByCommented(true);
break;
case QuickSearch.UNCOMMENTED:
view.setFilterLabel(SearchComponent.UNCOMMENTED_TEXT);
model.filterByCommented(false);
break;
case QuickSearch.HAS_ROIS:
view.setFilterLabel(SearchComponent.HAS_ROIS_TEXT);
model.filterByROIs(true);
break;
case QuickSearch.NO_ROIS:
view.setFilterLabel(SearchComponent.NO_ROIS_TEXT);
model.filterByROIs(false);
break;
}
}
/** Shows all the nodes. */
private void showAll()
{
view.setFilterLabel("");
model.showAll();
}
/** Creates a new instance. */
DataBrowserControl() {}
/**
* Links the components composing the MVC triad.
*
* @param model Reference to the model. Mustn't be <code>null</code>.
* @param view Reference to the view. Mustn't be <code>null</code>.
*/
void initialize(DataBrowser model, DataBrowserUI view)
{
if (view == null)
throw new IllegalArgumentException("No control.");
if (model == null)
throw new IllegalArgumentException("No model.");
this.model = model;
this.view = view;
actionsMap = new HashMap<Integer, Action>();
createActions();
}
/**
* 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); }
/**
* Returns the actions used to move data between groups.
*
* @return See above.
*/
List<MoveToAction> getMoveAction()
{
Browser browser = model.getBrowser();
Collection<DataObject> selection = null;
Iterator<DataObject> j;
List<Long> owners = new ArrayList<Long>();
if (browser != null) {
selection = browser.getSelectedDataObjects();
if (selection == null) return null;
int count = 0;
j = selection.iterator();
Object o;
DataObject data;
while (j.hasNext()) {
o = j.next();
if (o instanceof DataObject) {
if (!(o instanceof GroupData ||
o instanceof ExperimenterData ||
o instanceof PlateAcquisitionData ||
o instanceof WellSampleData)) {
if (model.canChgrp(o)) {
data = (DataObject) o;
if (!owners.contains(data.getOwner().getId()))
owners.add(data.getOwner().getId());
count++;
}
}
}
}
if (count != selection.size()) return null;
if (owners.size() > 1) return null;
}
long userID = DataBrowserAgent.getUserDetails().getId();
long ownerID = -1;
if (owners.size() > 0) ownerID = owners.get(0);
Collection l = null;
if (ownerID == userID) {
l = DataBrowserAgent.getAvailableUserGroups();
} else {
if (DataBrowserAgent.isAdministrator()) {
//load the group the user is member of
SecurityContext ctx = DataBrowserAgent.getAdminContext();
try {
l = DataBrowserAgent.getRegistry().
getAdminService().loadGroupsForExperimenter(ctx,
ownerID);
} catch (Exception e) {
DataBrowserAgent.getRegistry().getLogger().error(this,
"cannot retrieve user's groups");
}
}
}
if (l == null) return null;
ViewerSorter sorter = new ViewerSorter();
List values = sorter.sort(l);
if (moveActions == null)
moveActions = new ArrayList<MoveToAction>(l.size());
moveActions.clear();
List<Long> ids = new ArrayList<Long>();
if (browser != null && selection != null) {
j = selection.iterator();
DataObject data;
while (j.hasNext()) {
data = (DataObject) j.next();
if (!ids.contains(data.getGroupId()))
ids.add(data.getGroupId());
}
}
GroupData group;
Iterator i = values.iterator();
while (i.hasNext()) {
group = (GroupData) i.next();
if (!ids.contains(group.getGroupId()))
moveActions.add(new MoveToAction(model, group));
}
return moveActions;
}
/**
* Views the selected well sample field while browsing a plate.
*
* @param field The index of the field.
*/
void viewField(int field) { model.viewField(field); }
/**
* Forwards to the model to create a report.
*
* @param name The name of the file.
*/
void createReport(String name) { model.createReport(name); }
/** Loads the existing datasets. */
void loadExistingDatasets() { model.loadExistingDatasets(); }
/**
* Returns the external application previously used to open
* the selected document.
*
* @return See above.
*/
List<ViewOtherAction> getApplicationActions()
{
List<ApplicationData> applications = view.getApplications();
if (CollectionUtils.isEmpty(applications)) return null;
Iterator<ApplicationData> i = applications.iterator();
List<ViewOtherAction> actions = new ArrayList<ViewOtherAction>();
while (i.hasNext()) {
actions.add(new ViewOtherAction(model, i.next()));
}
return actions;
}
/**
* Views the passed node if supported.
*
* @param node The node to handle.
*/
void viewDisplay(ImageDisplay node) { model.viewDisplay(node, false); }
/**
* Activates the selected user.
*/
void activateUser()
{
Browser browser = model.getBrowser();
if (browser == null) return;
Collection<DataObject> nodes = browser.getSelectedDataObjects();
if (nodes == null || nodes.size() > 1) return;
DataObject n = nodes.iterator().next();
if (n instanceof ExperimenterData)
model.activateUser((ExperimenterData) n);
}
/**
* Loads data, filters nodes or sets the selected node.
* @see PropertyChangeListener#propertyChange(PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent evt)
{
String name = evt.getPropertyName();
if (Browser.SELECTED_DATA_BROWSER_NODE_DISPLAY_PROPERTY.equals(name)) {
ImageDisplay node = (ImageDisplay) evt.getNewValue();
if (node == null) return;
model.setSelectedDisplay(node);
} else if (Browser.SELECTED_DATA_BROWSER_NODES_DISPLAY_PROPERTY.equals(
name)) {
List<ImageDisplay> nodes = (List<ImageDisplay>) evt.getNewValue();
model.setSelectedDisplays(nodes);
} else if (Browser.UNSELECTED_DATA_BROWSER_NODE_DISPLAY_PROPERTY.equals(
name)) {
ImageDisplay node = (ImageDisplay) evt.getNewValue();
if (node == null) return;
model.setUnselectedDisplay(node);
} else if (QuickFiltering.FILTER_DATA_PROPERTY.equals(name)) {
filterNodes((SearchObject) evt.getNewValue());
} else if (QuickFiltering.DISPLAY_ALL_NODES_PROPERTY.equals(name)) {
showAll();
} else if (FilteringDialog.FILTER_PROPERTY.equals(name) ||
QuickFiltering.FILTER_TAGS_PROPERTY.equals(name)) {
FilterContext filter = (FilterContext) evt.getNewValue();
model.filterByContext(filter);
} else if (FilteringDialog.LOAD_TAG_PROPERTY.equals(name) ||
QuickFiltering.TAG_LOADING_PROPERTY.equals(name)) {
model.loadExistingTags();
} else if (Browser.ROLL_OVER_PROPERTY.equals(name)) {
if (view.isRollOver()) {
RollOverNode n = (RollOverNode) evt.getNewValue();
if (n != null && n.getNode() != null) {
ImageNode node = n.getNode();
Thumbnail prv = node.getThumbnail();
BufferedImage full = prv.getFullScaleThumb();
if (prv.getScalingFactor() == Thumbnail.MAX_SCALING_FACTOR)
full = prv.getZoomedFullScaleThumb();
RollOverThumbnailManager.rollOverDisplay(full,
node.getBounds(), n.getLocationOnScreen(),
node.toString());
} else RollOverThumbnailManager.stopOverDisplay();
}
} else if (SlideShowView.CLOSE_SLIDE_VIEW_PROPERTY.equals(name)) {
view.slideShowView(false);
} else if (EditorDialog.CREATE_NO_PARENT_PROPERTY.equals(name) ||
EditorDialog.CREATE_PROPERTY.equals(name)) {
DataObject object = (DataObject) evt.getNewValue();
model.createDataObject(object);
} else if (ImageTableView.TABLE_NODES_SELECTION_PROPERTY.equals(name) || SearchResultView.SELECTION_PROPERTY.equals(name)) {
List<ImageDisplay> selected = (List) evt.getNewValue();
model.setTableNodesSelected(selected);
} else if (ImageTableView.TABLE_SELECTION_MENU_PROPERTY.equals(name) || SearchResultView.CONTEXT_MENU_PROPERTY.equals(name)) {
Point location = (Point) evt.getNewValue();
if (location != null) view.showPopup(location);
} else if (Browser.POPUP_POINT_PROPERTY.equals(name)) {
Point p = (Point) evt.getNewValue();
if (p != null) view.showPopup(p);
} else if (ImageTableView.TABLE_SELECTION_VIEW_PROPERTY.equals(name)) {
Boolean b = (Boolean) evt.getNewValue();
if (b) view.viewSelectedNode();
} else if (ImageTableView.TABLE_SELECTION_ROLL_OVER_PROPERTY.equals(
name)) {
RollOverNode node = (RollOverNode) evt.getNewValue();
model.getBrowser().setRollOverNode(node);
} else if (Browser.CELL_SELECTION_PROPERTY.equals(name)) {
CellDisplay cell = (CellDisplay) evt.getNewValue();
model.setSelectedCell(cell);
} 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();
if (DatasetData.class.equals(type)) {
model.addToDatasets((Collection) entry.getValue());
}
}
} else if (PlateGrid.WELL_FIELDS_PROPERTY.equals(name)) {
PlateGridObject p = (PlateGridObject) evt.getNewValue();
if (p == null) return;
model.viewFieldsFor(p.getRow(), p.getColumn(),
p.isMultipleSelection());
} else if (Browser.VIEW_DISPLAY_PROPERTY.equals(name)) {
viewDisplay((ImageDisplay) evt.getNewValue());
} else if (Browser.MAIN_VIEW_DISPLAY_PROPERTY.equals(name)) {
ImageDisplay node = (ImageDisplay) evt.getNewValue();
Object ho = node.getHierarchyObject();
if (ho instanceof ImageData) model.viewDisplay(node, true);
}
}
}