/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy 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 3 of the License, or * (at your option) any later version. * * Icy 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 Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.gui.main; import icy.common.listener.AcceptListener; import icy.common.listener.weak.WeakListener; import icy.gui.frame.IcyFrame; import icy.gui.inspector.InspectorPanel; import icy.gui.inspector.LayersPanel; import icy.gui.inspector.RoisPanel; import icy.gui.main.MainEvent.MainEventSourceType; import icy.gui.main.MainEvent.MainEventType; import icy.gui.menu.ApplicationMenu; import icy.gui.menu.ToolRibbonTask; import icy.gui.viewer.Viewer; import icy.gui.viewer.ViewerAdapter; import icy.gui.viewer.ViewerEvent; import icy.gui.viewer.ViewerListener; import icy.image.IcyBufferedImage; import icy.image.lut.LUT; import icy.imagej.ImageJWrapper; import icy.main.Icy; import icy.painter.Overlay; import icy.painter.OverlayWrapper; import icy.painter.Painter; import icy.plugin.abstract_.Plugin; import icy.preferences.IcyPreferences; import icy.preferences.XMLPreferences; import icy.roi.ROI; import icy.search.SearchEngine; import icy.sequence.Sequence; import icy.sequence.SequenceAdapter; import icy.sequence.SequenceEvent; import icy.sequence.SequenceListener; import icy.swimmingPool.SwimmingPool; import icy.system.thread.ThreadUtil; import icy.undo.IcyUndoManager; import icy.util.StringUtil; import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyVetoException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLayeredPane; import javax.swing.event.EventListenerList; /** * MainInterfaceGui * * @author Fabrice de Chaumont & Stephane */ public class MainInterfaceGui implements MainInterface { private class WeakAcceptListener extends WeakListener<AcceptListener> implements AcceptListener { public WeakAcceptListener(AcceptListener listener) { super(listener); } @Override public void removeListener(Object source) { internalRemoveCanExitListener(this); } @Override public boolean accept(Object source) { final AcceptListener listener = getListener(); if (listener != null) return listener.accept(source); return true; } } // private final UpdateEventHandler updater; private final EventListenerList listeners; // use specific list for faster listeners retrieve private final List<MainListener> mainListeners; private final List<GlobalViewerListener> globalViewerListeners; private final List<GlobalSequenceListener> globalSequenceListeners; private final List<GlobalROIListener> globalROIListeners; private final List<GlobalOverlayListener> globalOverlayListeners; /** * used to generate focused sequence & viewer events */ private final ViewerListener activeViewerListener; private final SequenceListener sequenceListener; private final List<Viewer> viewers; private final List<Sequence> sequences; private final List<WeakReference<Plugin>> activePlugins; private final SwimmingPool swimmingPool; private final TaskFrameManager taskFrameManager; MainFrame mainFrame; Viewer previousActiveViewer; Viewer activeViewer; Sequence activeSequence; /** * Take care that MainInterface constructor do not call the {@link Icy#getMainInterface()} method.<br> * We use a separate {@link #init()} for that purpose. */ public MainInterfaceGui() { listeners = new EventListenerList(); mainListeners = new ArrayList<MainListener>(); globalViewerListeners = new ArrayList<GlobalViewerListener>(); globalSequenceListeners = new ArrayList<GlobalSequenceListener>(); globalROIListeners = new ArrayList<GlobalROIListener>(); globalOverlayListeners = new ArrayList<GlobalOverlayListener>(); viewers = new ArrayList<Viewer>(); sequences = new ArrayList<Sequence>(); activePlugins = new ArrayList<WeakReference<Plugin>>(); swimmingPool = new SwimmingPool(); taskFrameManager = new TaskFrameManager(); // active viewer listener activeViewerListener = new ViewerAdapter() { @Override public void viewerChanged(ViewerEvent event) { activeViewerChanged(event); } }; // global sequence listener sequenceListener = new SequenceAdapter() { @Override public void sequenceChanged(SequenceEvent event) { MainInterfaceGui.this.sequenceChanged(event); } }; mainFrame = null; previousActiveViewer = null; activeViewer = null; activeSequence = null; } @Override public void init() { // build main frame mainFrame = new MainFrame(); mainFrame.init(); mainFrame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { // exit application Icy.exit(false); } }); taskFrameManager.init(); } @Override public boolean isHeadLess() { // we are not head less with this interface return false; } @Override public void addSequence(Sequence sequence) { if (sequence != null) { final Sequence seq = sequence; // thread safe ThreadUtil.invokeLater(new Runnable() { @Override public void run() { new Viewer(seq); } }); } } @Override public ArrayList<JFrame> getExternalFrames() { final ArrayList<JFrame> result = new ArrayList<JFrame>(); final Window[] windows = Window.getWindows(); for (Window w : windows) if (w instanceof JFrame) result.add((JFrame) w); return result; } @Override public ArrayList<JInternalFrame> getInternalFrames() { if (mainFrame == null) return new ArrayList<JInternalFrame>(); return mainFrame.getInternalFrames(); } /** * @return the preferences */ @Override public XMLPreferences getPreferences() { return IcyPreferences.applicationRoot(); } @Override public InspectorPanel getInspector() { if (mainFrame == null) return null; return mainFrame.getInspector(); } @Override public RoisPanel getRoisPanel() { if (mainFrame == null) return null; final InspectorPanel inspector = mainFrame.getInspector(); if (inspector == null) return null; return inspector.getRoisPanel(); } @Override public LayersPanel getLayersPanel() { if (mainFrame == null) return null; final InspectorPanel inspector = mainFrame.getInspector(); if (inspector == null) return null; return inspector.getLayersPanel(); } @Override public ArrayList<Plugin> getActivePlugins() { final ArrayList<Plugin> result = new ArrayList<Plugin>(); synchronized (activePlugins) { for (WeakReference<Plugin> ref : activePlugins) { final Plugin plugin = ref.get(); if (plugin != null) result.add(plugin); } } return result; } @Override public LUT getActiveLUT() { if (activeViewer != null) return activeViewer.getLut(); return null; } @Override public Viewer getActiveViewer() { return activeViewer; } @Override public Sequence getActiveSequence() { return activeSequence; } @Override public IcyBufferedImage getActiveImage() { if (activeViewer != null) return activeViewer.getCurrentImage(); return null; } @Override @Deprecated public Viewer getFocusedViewer() { return getActiveViewer(); } @Override @Deprecated public Sequence getFocusedSequence() { return getActiveSequence(); } @Override @Deprecated public IcyBufferedImage getFocusedImage() { return getActiveImage(); } @Override public IcyUndoManager getUndoManager() { if (activeSequence != null) return activeSequence.getUndoManager(); return null; } @Override public boolean undo() { if (activeSequence != null) return activeSequence.undo(); return false; } @Override public boolean redo() { if (activeSequence != null) return activeSequence.redo(); return false; } @Override public ArrayList<Viewer> getViewers() { synchronized (viewers) { return new ArrayList<Viewer>(viewers); } } @Override public synchronized void setActiveViewer(Viewer viewer) { if (activeViewer == viewer) return; // got a previously active viewer ? if (activeViewer != null) { // remove active viewer listener activeViewer.removeListener(activeViewerListener); // force previous viewer internal frame to release focus try { activeViewer.getInternalFrame().setSelected(false); } catch (PropertyVetoException e) { // ignore } } previousActiveViewer = activeViewer; activeViewer = viewer; // add active viewer listener if (activeViewer != null) activeViewer.addListener(activeViewerListener); // activation changed viewerActivationChanged(previousActiveViewer, activeViewer); } @Override @Deprecated public synchronized void setFocusedViewer(Viewer viewer) { setActiveViewer(viewer); } @Override public synchronized void addToDesktopPane(JInternalFrame internalFrame) { getDesktopPane().add(internalFrame, JLayeredPane.DEFAULT_LAYER); } @Override public IcyDesktopPane getDesktopPane() { if (mainFrame == null) return null; return mainFrame.getDesktopPane(); } @Override public ApplicationMenu getApplicationMenu() { if (mainFrame == null) return null; return mainFrame.getApplicationMenu(); } @Override public TaskFrameManager getTaskWindowManager() { return taskFrameManager; } private WeakReference<Plugin> getPluginReference(Plugin plugin) { synchronized (activePlugins) { for (WeakReference<Plugin> ref : activePlugins) if (ref.get() == plugin) return ref; } return null; } @Deprecated @Override public void registerExternalFrame(JFrame frame) { } @Deprecated @Override public void unRegisterExternalFrame(JFrame frame) { } @Override public synchronized void registerPlugin(Plugin plugin) { synchronized (activePlugins) { activePlugins.add(new WeakReference<Plugin>(plugin)); } // plugin opened pluginStarted(plugin); } @Override public synchronized void unRegisterPlugin(Plugin plugin) { final WeakReference<Plugin> ref = getPluginReference(plugin); synchronized (activePlugins) { // reference found if (ref != null) activePlugins.remove(ref); } // plugin closed pluginEnded(plugin); } @Override public synchronized void registerViewer(Viewer viewer) { if (viewer == null) return; // viewer opened viewerOpened(viewer); } @Override public synchronized void unRegisterViewer(Viewer viewer) { if (viewer == null) return; // viewer closed viewerClosed(viewer); // no more opened viewer ? if (viewers.isEmpty()) // set focus to null setActiveViewer(null); else { final IcyFrame frame = IcyFrame.findIcyFrame(getDesktopPane().getSelectedFrame()); if (frame instanceof Viewer) ((Viewer) frame).requestFocus(); else { // it was the active viewer ? if (activeViewer == viewer) { // restore focus to previous active if (previousActiveViewer != null) { setActiveViewer(previousActiveViewer); // no more previous active now previousActiveViewer = null; } else // or just focus another one setActiveViewer(viewers.get(viewers.size() - 1)); } } } } @Override @Deprecated public MainFrame getFrame() { return getMainFrame(); } @Override public MainFrame getMainFrame() { return mainFrame; } @Override public SearchEngine getSearchEngine() { return mainFrame.getSearchBar().getSearchEngine(); } @Override public void closeSequence(Sequence sequence) { // use copy as this actually modify viewers list for (Viewer v : getViewers()) if (v.getSequence() == sequence) v.close(); } @Deprecated @Override public void closeViewersOfSequence(Sequence sequence) { closeSequence(sequence); } @Override public synchronized void closeAllViewers() { // use copy as this actually modify viewers list for (Viewer viewer : getViewers()) viewer.close(); } @Override public Viewer getFirstViewerContaining(ROI roi) { return getFirstViewer(getFirstSequenceContaining(roi)); } @Deprecated @Override public Viewer getFirstViewerContaining(Painter painter) { return getFirstViewer(getFirstSequenceContaining(painter)); } @Override public Viewer getFirstViewerContaining(Overlay overlay) { return getFirstViewer(getFirstSequenceContaining(overlay)); } @Override public Viewer getFirstViewer(Sequence sequence) { if (sequence != null) { for (Viewer viewer : getViewers()) if (viewer.getSequence() == sequence) return viewer; } return null; } @Override public ArrayList<Viewer> getViewers(Sequence sequence) { final ArrayList<Viewer> result = new ArrayList<Viewer>(); for (Viewer v : getViewers()) if (v.getSequence() == sequence) result.add(v); return result; } @Override public boolean isUniqueViewer(Viewer viewer) { final List<Viewer> viewers = getViewers(viewer.getSequence()); return (viewers.size() == 1) && (viewers.get(0) == viewer); } @Override public ArrayList<Sequence> getSequences() { synchronized (sequences) { return new ArrayList<Sequence>(sequences); } } @Override public ArrayList<Sequence> getSequences(String name) { final ArrayList<Sequence> result = new ArrayList<Sequence>(); synchronized (viewers) { for (Viewer viewer : viewers) { final Sequence sequence = viewer.getSequence(); // matching name and no duplicate if (!result.contains(sequence) && StringUtil.equals(name, sequence.getName())) result.add(sequence); } } return result; } @Override public boolean isOpened(Sequence sequence) { return getSequences().contains(sequence); } @Deprecated @Override public Sequence getFirstSequencesContaining(ROI roi) { return getFirstSequenceContaining(roi); } @Override public Sequence getFirstSequenceContaining(ROI roi) { for (Sequence seq : getSequences()) if (seq.contains(roi)) return seq; return null; } @Deprecated @Override public Sequence getFirstSequencesContaining(Painter painter) { return getFirstSequenceContaining(painter); } @Deprecated @Override public Sequence getFirstSequenceContaining(Painter painter) { for (Sequence seq : getSequences()) if (seq.contains(painter)) return seq; return null; } @Override public Sequence getFirstSequenceContaining(Overlay overlay) { for (Sequence seq : getSequences()) if (seq.contains(overlay)) return seq; return null; } @Override public ArrayList<Sequence> getSequencesContaining(ROI roi) { final ArrayList<Sequence> result = getSequences(); for (int i = result.size() - 1; i >= 0; i--) if (!result.get(i).contains(roi)) result.remove(i); return result; } @Override @Deprecated public ArrayList<Sequence> getSequencesContaining(Painter painter) { final ArrayList<Sequence> result = getSequences(); for (int i = result.size() - 1; i >= 0; i--) if (!result.get(i).contains(painter)) result.remove(i); return result; } @Override public List<Sequence> getSequencesContaining(Overlay overlay) { final ArrayList<Sequence> result = getSequences(); for (int i = result.size() - 1; i >= 0; i--) if (!result.get(i).contains(overlay)) result.remove(i); return result; } @Override public ArrayList<ROI> getROIs() { // HashSet is better suited for add elements final HashSet<ROI> result = new HashSet<ROI>(); for (Sequence seq : getSequences()) for (ROI roi : seq.getROISet()) result.add(roi); // TODO: add ROI from swimming pool ? return new ArrayList<ROI>(result); } @Override @Deprecated public ROI getROI(Painter painter) { if (painter instanceof Overlay) return getROI((Overlay) painter); return null; } @Override public ROI getROI(Overlay overlay) { final List<ROI> rois = getROIs(); for (ROI roi : rois) if (roi.getOverlay() == overlay) return roi; return null; } @Override @Deprecated public ArrayList<Painter> getPainters() { // HashSet better suited for add element final HashSet<Painter> result = new HashSet<Painter>(); for (Sequence seq : getSequences()) result.addAll(seq.getPainterSet()); // TODO: add Painter from swimming pool ? return new ArrayList<Painter>(); } @Override public List<Overlay> getOverlays() { // HashSet better suited for add element final HashSet<Overlay> result = new HashSet<Overlay>(); for (Sequence seq : getSequences()) result.addAll(seq.getOverlaySet()); // TODO: add Overlay from swimming pool ? return new ArrayList<Overlay>(); } @Override public SwimmingPool getSwimmingPool() { return swimmingPool; } @Override public ImageJWrapper getImageJ() { if (mainFrame == null) return null; return mainFrame.getMainRibbon().getImageJ(); } @Override public String getSelectedTool() { if (mainFrame == null) return null; return mainFrame.getMainRibbon().getToolRibbon().getSelected(); } @Override public void setSelectedTool(String command) { if (mainFrame != null) mainFrame.getMainRibbon().getToolRibbon().setSelected(command); } @Override public ToolRibbonTask getToolRibbon() { if (mainFrame == null) return null; return mainFrame.getMainRibbon().getToolRibbon(); } @Override public boolean isAlwaysOnTop() { if (mainFrame == null) return false; return mainFrame.isAlwaysOnTop(); } @Override public void setAlwaysOnTop(boolean value) { if (mainFrame != null) mainFrame.setAlwaysOnTop(value); } @Override public boolean isDetachedMode() { if (mainFrame == null) return false; return mainFrame.isDetachedMode(); } @Override public void setDetachedMode(boolean value) { if (mainFrame != null) mainFrame.setDetachedMode(value); } @Override @Deprecated public synchronized void addListener(MainListener listener) { if (listener != null) mainListeners.add(listener); } @Override @Deprecated public synchronized void removeListener(MainListener listener) { mainListeners.remove(listener); } @Override public synchronized void addGlobalViewerListener(GlobalViewerListener listener) { if (listener != null) globalViewerListeners.add(listener); } @Override public synchronized void removeGlobalViewerListener(GlobalViewerListener listener) { globalViewerListeners.remove(listener); } @Override public synchronized void addGlobalSequenceListener(GlobalSequenceListener listener) { if (listener != null) globalSequenceListeners.add(listener); } @Override public synchronized void removeGlobalSequenceListener(GlobalSequenceListener listener) { globalSequenceListeners.remove(listener); } @Override public synchronized void addGlobalROIListener(GlobalROIListener listener) { if (listener != null) globalROIListeners.add(listener); } @Override public synchronized void removeGlobalROIListener(GlobalROIListener listener) { globalROIListeners.remove(listener); } @Override public synchronized void addGlobalOverlayListener(GlobalOverlayListener listener) { if (listener != null) globalOverlayListeners.add(listener); } @Override public synchronized void removeGlobalOverlayListener(GlobalOverlayListener listener) { globalOverlayListeners.remove(listener); } @Override public synchronized void addGlobalPluginListener(GlobalPluginListener listener) { if (listener != null) listeners.add(GlobalPluginListener.class, listener); } @Override public synchronized void removeGlobalPluginListener(GlobalPluginListener listener) { listeners.remove(GlobalPluginListener.class, listener); } @Override public synchronized void addCanExitListener(AcceptListener listener) { if (listener != null) listeners.add(WeakAcceptListener.class, new WeakAcceptListener(listener)); } @Override public synchronized void removeCanExitListener(AcceptListener listener) { // we use weak reference so we have to find base listener... for (WeakAcceptListener l : listeners.getListeners(WeakAcceptListener.class)) if (listener == l.getListener()) internalRemoveCanExitListener(l); } public synchronized void internalRemoveCanExitListener(WeakAcceptListener listener) { listeners.remove(WeakAcceptListener.class, listener); } @Deprecated @Override public synchronized void addFocusedViewerListener(FocusedViewerListener listener) { listeners.add(FocusedViewerListener.class, listener); } @Deprecated @Override public synchronized void removeFocusedViewerListener(FocusedViewerListener listener) { listeners.remove(FocusedViewerListener.class, listener); } @Deprecated @Override public synchronized void addFocusedSequenceListener(FocusedSequenceListener listener) { listeners.add(FocusedSequenceListener.class, listener); } @Deprecated @Override public synchronized void removeFocusedSequenceListener(FocusedSequenceListener listener) { listeners.remove(FocusedSequenceListener.class, listener); } @Override public synchronized void addActiveViewerListener(ActiveViewerListener listener) { listeners.add(ActiveViewerListener.class, listener); } @Override public synchronized void removeActiveViewerListener(ActiveViewerListener listener) { listeners.remove(ActiveViewerListener.class, listener); } @Override public synchronized void addActiveSequenceListener(ActiveSequenceListener listener) { listeners.add(ActiveSequenceListener.class, listener); } @Override public synchronized void removeActiveSequenceListener(ActiveSequenceListener listener) { listeners.remove(ActiveSequenceListener.class, listener); } /** * fire plugin opened event */ @SuppressWarnings("deprecation") private void firePluginStartedEvent(Plugin plugin) { for (GlobalPluginListener listener : listeners.getListeners(GlobalPluginListener.class)) listener.pluginStarted(plugin); // backward compatibility final MainEvent event = new MainEvent(MainEventSourceType.PLUGIN, MainEventType.OPENED, plugin); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.pluginOpened(event); } /** * fire plugin closed event */ @SuppressWarnings("deprecation") private void firePluginEndedEvent(Plugin plugin) { for (GlobalPluginListener listener : listeners.getListeners(GlobalPluginListener.class)) listener.pluginEnded(plugin); // backward compatibility final MainEvent event = new MainEvent(MainEventSourceType.PLUGIN, MainEventType.CLOSED, plugin); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.pluginClosed(event); } /** * fire viewer opened event */ @SuppressWarnings("deprecation") private void fireViewerOpenedEvent(Viewer viewer) { for (GlobalViewerListener listener : new ArrayList<GlobalViewerListener>(globalViewerListeners)) listener.viewerOpened(viewer); // backward compatibility final MainEvent event = new MainEvent(MainEventSourceType.VIEWER, MainEventType.OPENED, viewer); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.viewerOpened(event); } /** * fire viewer close event */ @SuppressWarnings("deprecation") private void fireViewerClosedEvent(Viewer viewer) { for (GlobalViewerListener listener : new ArrayList<GlobalViewerListener>(globalViewerListeners)) listener.viewerClosed(viewer); // backward compatibility final MainEvent event = new MainEvent(MainEventSourceType.VIEWER, MainEventType.CLOSED, viewer); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.viewerClosed(event); } /** * fire viewer deactive event */ private void fireViewerDeactivatedEvent(Viewer viewer) { for (ActiveViewerListener listener : listeners.getListeners(ActiveViewerListener.class)) listener.viewerDeactivated(viewer); } /** * fire viewer active event */ @SuppressWarnings("deprecation") private void fireViewerActivatedEvent(Viewer viewer) { for (ActiveViewerListener listener : listeners.getListeners(ActiveViewerListener.class)) listener.viewerActivated(viewer); // backward compatibility final MainEvent event = new MainEvent(MainEventSourceType.VIEWER, MainEventType.FOCUSED, viewer); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.viewerFocused(event); for (FocusedViewerListener listener : listeners.getListeners(FocusedViewerListener.class)) listener.focusChanged(viewer); } /** * fire sequence opened event */ @SuppressWarnings("deprecation") private void fireSequenceOpenedEvent(Sequence sequence) { for (GlobalSequenceListener listener : new ArrayList<GlobalSequenceListener>(globalSequenceListeners)) listener.sequenceOpened(sequence); // backward compatibility final MainEvent event = new MainEvent(MainEventSourceType.SEQUENCE, MainEventType.OPENED, sequence); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.sequenceOpened(event); } /** * fire sequence active event */ @SuppressWarnings("deprecation") private void fireSequenceClosedEvent(Sequence sequence) { for (GlobalSequenceListener listener : new ArrayList<GlobalSequenceListener>(globalSequenceListeners)) listener.sequenceClosed(sequence); // backward compatibility final MainEvent event = new MainEvent(MainEventSourceType.SEQUENCE, MainEventType.CLOSED, sequence); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.sequenceClosed(event); } /** * fire sequence deactive event */ private void fireSequenceDeactivatedEvent(Sequence sequence) { for (ActiveSequenceListener listener : listeners.getListeners(ActiveSequenceListener.class)) listener.sequenceDeactivated(sequence); } /** * fire sequence active event */ @SuppressWarnings("deprecation") private void fireSequenceActivatedEvent(Sequence sequence) { for (ActiveSequenceListener listener : listeners.getListeners(ActiveSequenceListener.class)) listener.sequenceActivated(sequence); // backward compatibility final MainEvent event = new MainEvent(MainEventSourceType.SEQUENCE, MainEventType.FOCUSED, sequence); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.sequenceFocused(event); for (FocusedSequenceListener listener : listeners.getListeners(FocusedSequenceListener.class)) listener.focusChanged(sequence); } /** * fire ROI added event */ @SuppressWarnings("deprecation") private void fireRoiAddedEvent(ROI roi) { for (GlobalROIListener listener : new ArrayList<GlobalROIListener>(globalROIListeners)) listener.roiAdded(roi); // backward compatibility final MainEvent event = new MainEvent(MainEventSourceType.ROI, MainEventType.ADDED, roi); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.roiAdded(event); } /** * fire ROI removed event */ @SuppressWarnings("deprecation") private void fireRoiRemovedEvent(ROI roi) { for (GlobalROIListener listener : new ArrayList<GlobalROIListener>(globalROIListeners)) listener.roiRemoved(roi); // backward compatibility final MainEvent event = new MainEvent(MainEventSourceType.ROI, MainEventType.REMOVED, roi); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.roiRemoved(event); } /** * fire painter added event */ @SuppressWarnings("deprecation") private void fireOverlayAddedEvent(Overlay overlay) { for (GlobalOverlayListener listener : new ArrayList<GlobalOverlayListener>(globalOverlayListeners)) listener.overlayAdded(overlay); // backward compatibility final Painter painter; if (overlay instanceof OverlayWrapper) painter = ((OverlayWrapper) overlay).getPainter(); else painter = overlay; final MainEvent event = new MainEvent(MainEventSourceType.PAINTER, MainEventType.ADDED, painter); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.painterAdded(event); } /** * fire painter removed event */ @SuppressWarnings("deprecation") private void fireOverlayRemovedEvent(Overlay overlay) { for (GlobalOverlayListener listener : new ArrayList<GlobalOverlayListener>(globalOverlayListeners)) listener.overlayRemoved(overlay); // backward compatibility final Painter painter; if (overlay instanceof OverlayWrapper) painter = ((OverlayWrapper) overlay).getPainter(); else painter = overlay; final MainEvent event = new MainEvent(MainEventSourceType.PAINTER, MainEventType.REMOVED, painter); for (MainListener listener : new ArrayList<MainListener>(mainListeners)) listener.painterRemoved(event); } /** * fire active viewer changed event */ @SuppressWarnings("deprecation") private void fireActiveViewerChangedEvent(ViewerEvent event) { for (ActiveViewerListener listener : listeners.getListeners(ActiveViewerListener.class)) listener.activeViewerChanged(event); // backward compatibility for (FocusedViewerListener listener : listeners.getListeners(FocusedViewerListener.class)) listener.focusedViewerChanged(event); } /** * fire active sequence changed event */ @SuppressWarnings("deprecation") private void fireActiveSequenceChangedEvent(SequenceEvent event) { for (ActiveSequenceListener listener : listeners.getListeners(ActiveSequenceListener.class)) listener.activeSequenceChanged(event); // backward compatibility for (FocusedSequenceListener listener : listeners.getListeners(FocusedSequenceListener.class)) listener.focusedSequenceChanged(event); } @Override public boolean canExitExternal() { for (AcceptListener listener : listeners.getListeners(WeakAcceptListener.class)) if (!listener.accept(mainFrame)) return false; return true; } @Deprecated @Override public void beginUpdate() { // updater.beginUpdate(); } @Deprecated @Override public void endUpdate() { // updater.endUpdate(); } @Deprecated @Override public boolean isUpdating() { return false; // return updater.isUpdating(); } /** * called when a plugin is opened */ private void pluginStarted(Plugin plugin) { firePluginStartedEvent(plugin); } /** * called when a plugin is closed */ private void pluginEnded(Plugin plugin) { firePluginEndedEvent(plugin); } /** * called when a viewer is opened */ private void viewerOpened(Viewer viewer) { final Sequence sequence = viewer.getSequence(); boolean opened = true; synchronized (viewers) { // check if the sequence has just been opened if (sequence != null) { for (Viewer v : viewers) { if (v.getSequence() == sequence) { opened = false; break; } } } // add viewer to the viewer list viewers.add(viewer); } // single viewer for this sequence ? if ((sequence != null) && opened) // send opened event sequenceOpened(sequence); // fire viewer open event (after sequence open) fireViewerOpenedEvent(viewer); } /** * called when viewer activation changed */ private void viewerActivationChanged(Viewer oldActive, Viewer newActive) { final Sequence sequence; // new active viewer is not null ? if (newActive != null) { // remove focus on ImageJ image final ImageJWrapper ij = Icy.getMainInterface().getImageJ(); if (ij != null) ij.setActiveImage(null); // get active sequence sequence = newActive.getSequence(); } else sequence = null; final Sequence oldActiveSequence = activeSequence; // sequence active changed ? if (oldActiveSequence != sequence) { activeSequence = sequence; sequenceActivationChanged(oldActiveSequence, sequence); } // fire deactivated / activated events fireViewerDeactivatedEvent(oldActive); fireViewerActivatedEvent(newActive); } /** * called when the active viewer changed */ void activeViewerChanged(ViewerEvent event) { // propagate event if it comes from the active viewer // FIXME: why we need to test that ? it should always be the active viewer ? if (event.getSource() == activeViewer) fireActiveViewerChangedEvent(event); } /** * called when a viewer is closed */ private void viewerClosed(Viewer viewer) { // retrieve the viewer LUT before we release it final LUT lut = viewer.getLut(); // remove active viewer listener if (viewer == activeViewer) viewer.removeListener(activeViewerListener); // remove viewer from the viewer list synchronized (viewers) { viewers.remove(viewer); } // fire viewer closed event (before sequence close) fireViewerClosedEvent(viewer); final Sequence sequence = viewer.getSequence(); // check if a sequence has been closed if (sequence != null) { // if no viewer for this sequence if (getViewers(sequence).isEmpty()) // sequence close sequenceClosed(sequence, lut); } } /** * called when a sequence is opened */ private void sequenceOpened(Sequence sequence) { // add to sequence list synchronized (sequences) { sequences.add(sequence); } // listen the sequence sequence.addListener(sequenceListener); // fire sequence opened event (before roi / overlay events) fireSequenceOpenedEvent(sequence); // check about ROI add event for (ROI roi : sequence.getROIs()) checkRoiAdded(roi, false); // check about Overlay add event for (Overlay overlay : sequence.getOverlays()) checkOverlayAdded(overlay, false); } /** * called when sequence activation changed */ private void sequenceActivationChanged(Sequence oldActive, Sequence newActive) { // fire events fireSequenceDeactivatedEvent(oldActive); fireSequenceActivatedEvent(newActive); } /** * called when a sequence changed */ void sequenceChanged(SequenceEvent event) { final Sequence sequence = event.getSequence(); // handle event for active sequence only if (isOpened(sequence)) { switch (event.getSourceType()) { case SEQUENCE_ROI: switch (event.getType()) { case ADDED: checkRoiAdded((ROI) event.getSource(), false); break; case REMOVED: checkRoiRemoved((ROI) event.getSource(), false); break; } break; case SEQUENCE_OVERLAY: switch (event.getType()) { case ADDED: checkOverlayAdded((Overlay) event.getSource(), false); break; case REMOVED: checkOverlayRemoved((Overlay) event.getSource(), false); break; } break; } } // propagate event if it comes from the active sequence if (sequence == activeSequence) fireActiveSequenceChangedEvent(event); } /** * Called when a sequence is closed. * * @param sequence * the sequence which has been closed. * @param userLut * the viewer's LUT used when sequence has been closed. */ private void sequenceClosed(Sequence sequence, LUT userLut) { // check about Overlay remove event for (Overlay overlay : sequence.getOverlays()) checkOverlayRemoved(overlay, true); // check about ROI remove event for (ROI roi : sequence.getROIs()) checkRoiRemoved(roi, true); // remove from sequence listener sequence.removeListener(sequenceListener); // remove from the sequence list synchronized (sequences) { sequences.remove(sequence); } // set the user LUT in the sequence if (userLut != null) sequence.setUserLUT(userLut); // inform sequence is now closed sequence.closed(); // fire sequence closed event (after roi / overlay events) fireSequenceClosedEvent(sequence); } private void checkRoiAdded(ROI roi, boolean checkBeforeAdd) { final List<Sequence> sequencesContainingRoi = getSequencesContaining(roi); // only 1 sequence contains (or will contain) this roi ? if (sequencesContainingRoi.size() == (checkBeforeAdd ? 0 : 1)) // roi added roiAdded(roi); } private void checkRoiRemoved(ROI roi, boolean checkBeforeRemove) { final List<Sequence> sequencesContainingRoi = getSequencesContaining(roi); // no more sequence contains (or will contain) this roi ? if (sequencesContainingRoi.size() == (checkBeforeRemove ? 1 : 0)) // roi removed roiRemoved(roi); } private void checkOverlayAdded(Overlay overlay, boolean checkBeforeAdd) { final List<Sequence> sequencesContainingOverlay = getSequencesContaining(overlay); // only 1 sequence contains (or will contain) this overlay ? if (sequencesContainingOverlay.size() == (checkBeforeAdd ? 0 : 1)) // overlay added overlayAdded(overlay); } private void checkOverlayRemoved(Overlay overlay, boolean checkBeforeRemove) { final List<Sequence> sequencesContainingOverlay = getSequencesContaining(overlay); // no more sequence contains (or will contain) this overlay ? if (sequencesContainingOverlay.size() == (checkBeforeRemove ? 1 : 0)) // overlay removed overlayRemoved(overlay); } /** * called when a roi is added for the first time in a sequence */ private void roiAdded(ROI roi) { fireRoiAddedEvent(roi); } /** * called when a roi is removed from all sequence */ private void roiRemoved(ROI roi) { fireRoiRemovedEvent(roi); } /** * called when an overlay is added for the first time in a sequence */ private void overlayAdded(Overlay overlay) { fireOverlayAddedEvent(overlay); } /** * called when an overlay is removed from all sequence */ private void overlayRemoved(Overlay overlay) { fireOverlayRemovedEvent(overlay); } @Override public void setGlobalViewSyncId(int id) { for (Viewer viewer : getViewers()) viewer.setViewSyncId(id); } }