/*
*------------------------------------------------------------------------------
* Copyright (C) 2006-2016 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.imviewer;
import java.awt.Rectangle;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.swing.JComponent;
import ome.model.units.BigResult;
import org.apache.commons.collections.CollectionUtils;
import org.openmicroscopy.shoola.agents.events.FocusGainedEvent;
import org.openmicroscopy.shoola.agents.events.iviewer.CopyRndSettings;
import org.openmicroscopy.shoola.agents.events.iviewer.ImageViewport;
import org.openmicroscopy.shoola.agents.events.iviewer.MeasurementTool;
import org.openmicroscopy.shoola.agents.events.iviewer.RendererUnloadedEvent;
import org.openmicroscopy.shoola.agents.events.iviewer.RndSettingsChanged;
import org.openmicroscopy.shoola.agents.events.iviewer.RndSettingsCopied;
import org.openmicroscopy.shoola.agents.events.iviewer.RndSettingsSaved;
import org.openmicroscopy.shoola.agents.events.iviewer.SaveRelatedData;
import org.openmicroscopy.shoola.agents.events.iviewer.ViewImage;
import org.openmicroscopy.shoola.agents.events.iviewer.ViewImageObject;
import org.openmicroscopy.shoola.agents.events.iviewer.ViewerState;
import org.openmicroscopy.shoola.agents.events.measurement.MeasurementToolLoaded;
import org.openmicroscopy.shoola.agents.events.measurement.ROIEvent;
import org.openmicroscopy.shoola.agents.events.measurement.SelectChannel;
import org.openmicroscopy.shoola.agents.events.measurement.SelectPlane;
import org.openmicroscopy.shoola.agents.events.metadata.ChannelSavedEvent;
import org.openmicroscopy.shoola.agents.events.treeviewer.DeleteObjectEvent;
import org.openmicroscopy.shoola.agents.events.treeviewer.DisplayModeEvent;
import org.openmicroscopy.shoola.agents.imviewer.view.ImViewer;
import org.openmicroscopy.shoola.agents.imviewer.view.ImViewerFactory;
import org.openmicroscopy.shoola.env.Agent;
import org.openmicroscopy.shoola.env.Environment;
import org.openmicroscopy.shoola.env.LookupNames;
import org.openmicroscopy.shoola.env.config.Registry;
import org.openmicroscopy.shoola.env.data.events.ReconnectedEvent;
import org.openmicroscopy.shoola.env.data.events.ReloadRenderingEngine;
import org.openmicroscopy.shoola.env.data.events.UserGroupSwitched;
import org.openmicroscopy.shoola.env.data.events.ViewInPluginEvent;
import org.openmicroscopy.shoola.env.data.util.AgentSaveInfo;
import omero.gateway.SecurityContext;
import org.openmicroscopy.shoola.env.event.AgentEvent;
import org.openmicroscopy.shoola.env.event.AgentEventListener;
import org.openmicroscopy.shoola.env.event.EventBus;
import org.openmicroscopy.shoola.env.ui.UserNotifier;
import org.openmicroscopy.shoola.env.ui.ViewObjectEvent;
import omero.gateway.model.ChannelData;
import omero.gateway.model.DataObject;
import omero.gateway.model.ExperimenterData;
import omero.gateway.model.ImageData;
import omero.gateway.model.PixelsData;
import omero.gateway.model.WellSampleData;
/**
* The ImViewer agent. This agent displays an <code>Image</code> and the
* controls to modify the rendering settings.
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author Andrea Falconi
* <a href="mailto:a.falconi@dundee.ac.uk">a.falconi@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 OME2.2
*/
public class ImViewerAgent
implements Agent, AgentEventListener
{
/** The default error message. */
public static final String ERROR = " An error occurred while modifying " +
"the rendering settings.";
/** Reference to the registry. */
private static Registry registry;
/** The display mode.*/
private int displayMode = -1;
/**
* Helper method.
*
* @return A reference to the <code>Registry</code>.
*/
public static Registry getRegistry() { return registry; }
/**
* Helper method returning the current user's details.
*
* @return See above.
*/
public static ExperimenterData getUserDetails()
{
return (ExperimenterData) registry.lookup(
LookupNames.CURRENT_USER_DETAILS);
}
/**
* Helper method returning <code>true</code> if the connection is fast,
* <code>false</code> otherwise.
*
* @return See above.
*/
public static boolean isFastConnection()
{
int value = (Integer) registry.lookup(LookupNames.IMAGE_QUALITY_LEVEL);
return value == ImViewer.UNCOMPRESSED;
}
/**
* Returns <code>true</code> if the application is used as a plugin,
* <code>false</code> otherwise.
*
* @return See above.
*/
public static boolean isRunAsPlugin()
{
Environment env = (Environment) registry.lookup(LookupNames.ENV);
if (env == null) return false;
return env.runAsPlugin() > 0;
}
/**
* Handles the {@link ViewImage} event.
*
* @param evt The event to handle.
*/
private void handleViewImage(ViewImage evt)
{
if (evt == null) return;
Boolean available = (Boolean)
registry.lookup(LookupNames.BINARY_AVAILABLE);
if (available != null && !available.booleanValue()) return;
List<ViewImageObject> images = evt.getImages();
ViewImageObject object = images.get(0);
DataObject image = object.getImage();
Rectangle r = evt.getRequesterBounds();
ImViewer view = null;
boolean b = evt.isSeparateWindow();
if (image != null) {
if (evt.getPlugin() > 0) {
ViewInPluginEvent event = new ViewInPluginEvent(
evt.getSecurityContext(), image, evt.getPlugin());
EventBus bus = registry.getEventBus();
bus.post(event);
return;
}
PixelsData pixels = null;
if (image instanceof ImageData) {
pixels = ((ImageData) image).getDefaultPixels();
} else if (image instanceof WellSampleData) {
pixels = ((WellSampleData) image).getImage().getDefaultPixels();
}
if (pixels != null)
view = ImViewerFactory.getImageViewer(evt.getSecurityContext(),
image, r, b);
} else {
if (evt.getPlugin() > 0) {
ViewInPluginEvent event = new ViewInPluginEvent(
evt.getSecurityContext(),object.getImageID(),
evt.getPlugin());
EventBus bus = registry.getEventBus();
bus.post(event);
} else {
view = ImViewerFactory.getImageViewer(evt.getSecurityContext(),
object.getImageID(), r, b);
}
}
if (view != null) {
view.activate(object.getSettings(), object.getSelectedUserID(),
displayMode, object.getSelectedRndDef());
view.setContext(object.getParent(), object.getGrandParent());
}
}
/**
* Convenience method for logging BigResult exceptions
*
* @param src
* The origin of the exception
* @param exception
* The exception
* @param property
* The property which conversion triggered the exception
*/
public static void logBigResultExeption(Object src, Object exception,
String property) {
if (exception instanceof BigResult) {
ImViewerAgent
.getRegistry()
.getLogger()
.warn(src,
"Arithmetic overflow; "
+ property
+ " is "
+ ((BigResult) exception).result
.doubleValue());
}
}
/**
* Handles the {@link SaveRelatedData} event.
*
* @param evt The event to handle.
*/
private void handleSaveRelatedData(SaveRelatedData evt)
{
if (evt == null) return;
ImViewerFactory.storeEvent(evt);
}
/**
* Handles the {@link MeasurementToolLoaded} event.
*
* @param evt The event to handle.
*/
private void handleMeasurementToolLoaded(MeasurementToolLoaded evt)
{
if (evt == null) return;
MeasurementTool request = (MeasurementTool) evt.getACT();
PixelsData pixels = request.getPixels();
if (pixels == null) return;
long pixelsID = pixels.getId();
//TODO: review
ImViewer view = ImViewerFactory.getImageViewer(evt.getSecurityContext(),
pixelsID);
if (view != null) {
switch (evt.getIndex()) {
case MeasurementToolLoaded.ADD:
view.addToView(evt.getView());
break;
case MeasurementToolLoaded.REMOVE:
view.removeFromView(evt.getView());
}
}
}
/**
* Handles the {@link SelectPlane} event.
*
* @param evt The event to handle.
*/
private void handleSelectPlane(SelectPlane evt)
{
if (evt == null) return;
long pixelsID = evt.getPixelsID();
ImViewer view = ImViewerFactory.getImageViewer(null, pixelsID);
if (view != null && !view.isPlayingMovie()) {
Rectangle r = evt.getBounds();
if (r != null) {
view.setSelectedRegion(evt.getDefaultZ(), evt.getDefaultT(),
evt.getBounds());
} else
view.setSelectedXYPlane(evt.getDefaultZ(), evt.getDefaultT());
}
}
/**
* Handles the {@link SelectChannel} event.
*
* @param evt The event to handle.
*/
private void handleSelectChannel(SelectChannel evt)
{
if (evt == null) return;
long pixelsID = evt.getPixelsID();
ImViewer view = ImViewerFactory.getImageViewer(null, pixelsID);
if (view != null && !view.isPlayingMovie()) {
List<Integer> l = view.getActiveChannels();
List<Integer> channels = evt.getChannels();
Iterator<Integer> i = channels.iterator();
Integer c;
while (i.hasNext()) {
c = i.next();
if (!l.contains(c)) {
view.setChannelSelection(c, true);
}
}
}
}
/**
* Handles the {@link CopyRndSettings} event.
*
* @param evt The event to handle.
*/
public void handleCopyRndSettingsEvent(CopyRndSettings evt)
{
if (evt == null) return;
ImViewerFactory.copyRndSettings(evt.getImage(), evt.getRndDef());
}
/**
* Handles the {@link RndSettingsCopied} event.
*
* @param evt The event to handle.
*/
private void handleRndSettingsCopied(RndSettingsCopied evt)
{
Collection<Long> ids = evt.getImagesIDs();
if (CollectionUtils.isEmpty(ids)) return;
Iterator<Long> i = ids.iterator();
ImViewer view;
long id = evt.getRefPixelsID();
while (i.hasNext()) {
view = ImViewerFactory.getImageViewerFromImage(null, i.next());
if (view != null ) {
if (view.getPixelsID() != id) {
view.pasteRenderingSettings();
view.saveRndSettings(true);
}
view.reloadRenderingThumbs();
}
}
}
/**
* Handles the {@link RndSettingsSaved} event.
*
* @param evt The event to handle.
*/
public void handleRndSettingsSavedEvent(RndSettingsSaved evt)
{
if (evt == null) return;
ImViewerFactory.rndSettingsSaved(evt.getRefPixelsID(),
evt.getSettings());
}
/**
* Handles the {@link RndSettingsChanged} event.
*
* @param evt The event to handle.
*/
public void handleRndSettingsChangedEvent(RndSettingsChanged evt)
{
if (evt == null) return;
ImViewerFactory.rndSettingsChanged(evt.getImageID());
}
/**
* Indicates to bring up the window if a related window gained focus
*
* @param evt The event to handle.
*/
private void handleFocusGainedEvent(FocusGainedEvent evt)
{
/*
ImViewer viewer = ImViewerFactory.getImageViewer(
evt.getPixelsID());
if (viewer == null) return;
if (viewer.getState() != ImViewer.DISCARDED ||
evt.getIndex() != FocusGainedEvent.VIEWER_FOCUS) {
//viewer.toFront();
}
*/
}
/**
* Displays the passed rectangle if possible.
*
* @param evt The event to handle.
*/
private void handleImageViewportEvent(ImageViewport evt)
{
if (evt == null) return;
ImViewer viewer = ImViewerFactory.getImageViewer(null,
evt.getPixelsID());
if (viewer == null) return;
viewer.scrollToViewport(evt.getBounds());
}
/**
* Removes all the references to the existing viewers.
*
* @param evt The event to handle.
*/
private void handleUserGroupSwitched(UserGroupSwitched evt)
{
if (evt == null) return;
ImViewerFactory.onGroupSwitched(evt.isSuccessful());
}
/**
* Indicates that it was possible to reconnect.
*
* @param evt The event to handle.
*/
private void handleReconnectedEvent(ReconnectedEvent evt)
{
ImViewerFactory.onGroupSwitched(true);
}
/**
* Views the passed object if the object is an image.
*
* @param evt The event to handle.
*/
private void handleViewObjectEvent(ViewObjectEvent evt)
{
if (evt == null) return;
Object o = evt.getObject();
if (evt.browseObject()) return;
if (o instanceof ImageData) {
if (evt.getPlugin() > 0) {
JComponent src = evt.getSource();
if (src != null) src.setEnabled(true);
ViewInPluginEvent event = new ViewInPluginEvent(
evt.getSecurityContext(), ((ImageData) o).getId(),
evt.getPlugin());
EventBus bus = registry.getEventBus();
bus.post(event);
} else {
ImViewer view = ImViewerFactory.getImageViewer(
evt.getSecurityContext(), ((ImageData) o).getId(),
null, true);
if (view != null) {
view.activate(null, getUserDetails().getId(),
displayMode, -1);
JComponent src = evt.getSource();
if (src != null) src.setEnabled(true);
}
}
}
}
/**
* Indicates that the rendered could not be loaded.
*
* @param evt The event to handle.
*/
private void handleRendererUnloadedEvent(RendererUnloadedEvent evt)
{
if (evt == null) return;
ImViewer viewer = ImViewerFactory.getImageViewer(null,
evt.getPixelsID());
if (viewer == null) return;
viewer.discard();
}
/**
* Checks the files to delete and see if a viewer is opened.
*
* @param evt The event to handle.
*/
private void handleDeleteObjectEvent(DeleteObjectEvent evt)
{
if (evt == null) return;
List<DataObject> objects = evt.getObjects();
if (objects == null) return;
Iterator<DataObject> i = objects.iterator();
DataObject object;
ImViewer viewer;
EventBus bus = registry.getEventBus();
while (i.hasNext()) {
object = i.next();
if (object instanceof ImageData) {
checkImageForDelete((ImageData) object);
} else {
viewer = ImViewerFactory.getImageViewerFromParent(object);
if (viewer != null) {
//Post an event to discard Measurement tool
ViewerState event = new ViewerState(viewer.getPixelsID(),
ViewerState.CLOSE);
bus.post(event);
viewer.discard();
}
}
}
}
/**
* Closes the viewer b/c the rendering engine could not be loaded.
*
* @param evt The event to handle.
*/
private void handleReloadRenderingEngineEvent(ReloadRenderingEngine evt)
{
if (evt == null) return;
List<Long> pixels = evt.getPixelsID();
if (CollectionUtils.isEmpty(pixels)) return;
Iterator<Long> i = pixels.iterator();
Long id;
ImViewer viewer;
UserNotifier un = registry.getUserNotifier();
while (i.hasNext()) {
id = i.next();
viewer = ImViewerFactory.getImageViewer(null, id);
if (viewer != null) {
un.notifyInfo("Reload", "The rendering engine could not be " +
"reloaded for " + viewer.getUI().getTitle()+
".\nThe viewer will now close.");
viewer.discard();
}
}
}
/**
* Updates the view when the channels have been updated.
*
* @param evt The event to handle.
*/
private void handleChannelSavedEvent(ChannelSavedEvent evt)
{
List<ChannelData> channels = evt.getChannels();
Iterator<Long> i = evt.getImageIds().iterator();
SecurityContext ctx = evt.getSecurityContext();
ImViewer viewer;
while (i.hasNext()) {
viewer = ImViewerFactory.getImageViewerFromImage(ctx, i.next());
if (viewer != null) {
viewer.onUpdatedChannels(channels);
}
}
}
/**
* Updates the view when the mode is changed.
*
* @param evt The event to handle.
*/
private void handleDisplayModeEvent(DisplayModeEvent evt)
{
displayMode = evt.getDisplayMode();
ImViewerFactory.setDisplayMode(displayMode);
}
/**
* Checks if the passed image is actually opened in the viewer.
*
* @param image The image to handle.
*/
private void checkImageForDelete(ImageData image)
{
if (image.getId() < 0) return;
PixelsData pixels = image.getDefaultPixels();
if (pixels == null) return;
EventBus bus = registry.getEventBus();
ImViewer viewer = ImViewerFactory.getImageViewer(null, pixels.getId());
if (viewer != null) {
//Post an event to discard Measurement tool
ViewerState event = new ViewerState(viewer.getPixelsID(),
ViewerState.CLOSE);
bus.post(event);
viewer.discard();
}
}
/** Creates a new instance. */
public ImViewerAgent() {}
/**
* Implemented as specified by {@link Agent}.
* @see Agent#activate(boolean)
*/
public void activate(boolean master) {}
/**
* Implemented as specified by {@link Agent}.
* @see Agent#terminate()
*/
public void terminate()
{
Environment env = (Environment) registry.lookup(LookupNames.ENV);
if (env.isRunAsPlugin())
ImViewerFactory.onGroupSwitched(true);
}
/**
* Implemented as specified by {@link Agent}.
* @see Agent#setContext(Registry)
*/
public void setContext(Registry ctx)
{
registry = ctx;
EventBus bus = registry.getEventBus();
bus.register(this, ViewImage.class);
bus.register(this, MeasurementToolLoaded.class);
bus.register(this, SelectPlane.class);
bus.register(this, CopyRndSettings.class);
bus.register(this, SaveRelatedData.class);
bus.register(this, FocusGainedEvent.class);
bus.register(this, ImageViewport.class);
bus.register(this, UserGroupSwitched.class);
bus.register(this, ViewObjectEvent.class);
bus.register(this, RendererUnloadedEvent.class);
bus.register(this, DeleteObjectEvent.class);
bus.register(this, RndSettingsSaved.class);
bus.register(this, ReloadRenderingEngine.class);
bus.register(this, ReconnectedEvent.class);
bus.register(this, SelectChannel.class);
bus.register(this, ChannelSavedEvent.class);
bus.register(this, DisplayModeEvent.class);
bus.register(this, RndSettingsCopied.class);
bus.register(this, RndSettingsChanged.class);
bus.register(this, ROIEvent.class);
}
/**
* Implemented as specified by {@link Agent}.
* @see Agent#canTerminate()
*/
public boolean canTerminate() { return true; }
/**
* Implemented as specified by {@link Agent}.
* @see Agent#getDataToSave()
*/
public AgentSaveInfo getDataToSave()
{
List<Object> list = ImViewerFactory.getInstancesToSave();
if (CollectionUtils.isEmpty(list)) return null;
return new AgentSaveInfo("Image Viewer", list);
}
/**
* Implemented as specified by {@link Agent}.
* @see Agent#save(List)
*/
public void save(List<Object> instances)
{
ImViewerFactory.saveInstances(instances);
}
/**
* Responds to events fired trigger on the bus.
* @see AgentEventListener#eventFired(AgentEvent)
*/
public void eventFired(AgentEvent e)
{
if (e instanceof ViewImage)
handleViewImage((ViewImage) e);
else if (e instanceof MeasurementToolLoaded)
handleMeasurementToolLoaded((MeasurementToolLoaded) e);
else if (e instanceof SelectPlane)
handleSelectPlane((SelectPlane) e);
else if (e instanceof CopyRndSettings)
handleCopyRndSettingsEvent((CopyRndSettings) e);
else if (e instanceof SaveRelatedData)
handleSaveRelatedData((SaveRelatedData) e);
else if (e instanceof FocusGainedEvent)
handleFocusGainedEvent((FocusGainedEvent) e);
else if (e instanceof ImageViewport)
handleImageViewportEvent((ImageViewport) e);
else if (e instanceof UserGroupSwitched)
handleUserGroupSwitched((UserGroupSwitched) e);
else if (e instanceof ViewObjectEvent)
handleViewObjectEvent((ViewObjectEvent) e);
else if (e instanceof RendererUnloadedEvent)
handleRendererUnloadedEvent((RendererUnloadedEvent) e);
else if (e instanceof DeleteObjectEvent)
handleDeleteObjectEvent((DeleteObjectEvent) e);
else if (e instanceof RndSettingsSaved)
handleRndSettingsSavedEvent((RndSettingsSaved) e);
else if (e instanceof ReloadRenderingEngine)
handleReloadRenderingEngineEvent((ReloadRenderingEngine) e);
else if (e instanceof ReconnectedEvent)
handleReconnectedEvent((ReconnectedEvent) e);
else if (e instanceof SelectChannel)
handleSelectChannel((SelectChannel) e);
else if (e instanceof ChannelSavedEvent)
handleChannelSavedEvent((ChannelSavedEvent) e);
else if (e instanceof DisplayModeEvent)
handleDisplayModeEvent((DisplayModeEvent) e);
else if (e instanceof RndSettingsCopied)
handleRndSettingsCopied((RndSettingsCopied) e);
else if (e instanceof RndSettingsChanged)
handleRndSettingsChangedEvent((RndSettingsChanged) e);
else if (e instanceof ROIEvent)
handleROIEvent((ROIEvent) e);
}
private void handleROIEvent(ROIEvent e) {
ImViewer viewer = ImViewerFactory.getImageViewerFromImage(null, e.getImageId());
if (viewer != null) {
viewer.reloadROICount();
}
}
}