001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.main; 020 021import java.awt.Window; 022import java.awt.event.WindowAdapter; 023import java.awt.event.WindowEvent; 024import java.beans.PropertyVetoException; 025import java.lang.ref.WeakReference; 026import java.util.ArrayList; 027import java.util.HashSet; 028import java.util.List; 029 030import javax.swing.JFrame; 031import javax.swing.JInternalFrame; 032import javax.swing.JLayeredPane; 033import javax.swing.event.EventListenerList; 034 035import icy.common.listener.AcceptListener; 036import icy.common.listener.weak.WeakListener; 037import icy.gui.frame.IcyFrame; 038import icy.gui.inspector.InspectorPanel; 039import icy.gui.inspector.LayersPanel; 040import icy.gui.inspector.RoisPanel; 041import icy.gui.main.MainEvent.MainEventSourceType; 042import icy.gui.main.MainEvent.MainEventType; 043import icy.gui.menu.ApplicationMenu; 044import icy.gui.menu.ROITask; 045import icy.gui.menu.ToolRibbonTask; 046import icy.gui.viewer.Viewer; 047import icy.gui.viewer.ViewerAdapter; 048import icy.gui.viewer.ViewerEvent; 049import icy.gui.viewer.ViewerListener; 050import icy.image.IcyBufferedImage; 051import icy.image.lut.LUT; 052import icy.imagej.ImageJWrapper; 053import icy.main.Icy; 054import icy.painter.Overlay; 055import icy.painter.OverlayWrapper; 056import icy.painter.Painter; 057import icy.plugin.abstract_.Plugin; 058import icy.preferences.GeneralPreferences; 059import icy.preferences.IcyPreferences; 060import icy.preferences.XMLPreferences; 061import icy.roi.ROI; 062import icy.search.SearchEngine; 063import icy.sequence.Sequence; 064import icy.sequence.SequenceAdapter; 065import icy.sequence.SequenceEvent; 066import icy.sequence.SequenceListener; 067import icy.swimmingPool.SwimmingPool; 068import icy.system.thread.ThreadUtil; 069import icy.undo.IcyUndoManager; 070import icy.util.StringUtil; 071 072/** 073 * MainInterfaceGui 074 * 075 * @author Fabrice de Chaumont & Stephane 076 */ 077public class MainInterfaceGui implements MainInterface 078{ 079 private class WeakAcceptListener extends WeakListener<AcceptListener> implements AcceptListener 080 { 081 public WeakAcceptListener(AcceptListener listener) 082 { 083 super(listener); 084 } 085 086 @Override 087 public void removeListener(Object source) 088 { 089 internalRemoveCanExitListener(this); 090 } 091 092 @Override 093 public boolean accept(Object source) 094 { 095 final AcceptListener listener = getListener(); 096 097 if (listener != null) 098 return listener.accept(source); 099 100 return true; 101 } 102 } 103 104 // private final UpdateEventHandler updater; 105 106 private final EventListenerList listeners; 107 108 // use specific list for faster listeners retrieve 109 private final List<MainListener> mainListeners; 110 private final List<GlobalViewerListener> globalViewerListeners; 111 private final List<GlobalSequenceListener> globalSequenceListeners; 112 private final List<GlobalROIListener> globalROIListeners; 113 private final List<GlobalOverlayListener> globalOverlayListeners; 114 115 /** 116 * used to generate focused sequence & viewer events 117 */ 118 private final ViewerListener activeViewerListener; 119 private final SequenceListener sequenceListener; 120 121 private final List<Viewer> viewers; 122 private final List<Sequence> sequences; 123 private final List<WeakReference<Plugin>> activePlugins; 124 125 private final SwimmingPool swimmingPool; 126 private final TaskFrameManager taskFrameManager; 127 128 MainFrame mainFrame; 129 130 Viewer previousActiveViewer; 131 Viewer activeViewer; 132 Sequence activeSequence; 133 134 /** 135 * Take care that MainInterface constructor do not call the {@link Icy#getMainInterface()} method.<br> 136 * We use a separate {@link #init()} for that purpose. 137 */ 138 public MainInterfaceGui() 139 { 140 listeners = new EventListenerList(); 141 mainListeners = new ArrayList<MainListener>(); 142 globalViewerListeners = new ArrayList<GlobalViewerListener>(); 143 globalSequenceListeners = new ArrayList<GlobalSequenceListener>(); 144 globalROIListeners = new ArrayList<GlobalROIListener>(); 145 globalOverlayListeners = new ArrayList<GlobalOverlayListener>(); 146 147 viewers = new ArrayList<Viewer>(); 148 sequences = new ArrayList<Sequence>(); 149 activePlugins = new ArrayList<WeakReference<Plugin>>(); 150 swimmingPool = new SwimmingPool(); 151 taskFrameManager = new TaskFrameManager(); 152 153 // active viewer listener 154 activeViewerListener = new ViewerAdapter() 155 { 156 @Override 157 public void viewerChanged(ViewerEvent event) 158 { 159 activeViewerChanged(event); 160 } 161 }; 162 163 // global sequence listener 164 sequenceListener = new SequenceAdapter() 165 { 166 @Override 167 public void sequenceChanged(SequenceEvent event) 168 { 169 MainInterfaceGui.this.sequenceChanged(event); 170 } 171 }; 172 173 mainFrame = null; 174 175 previousActiveViewer = null; 176 activeViewer = null; 177 activeSequence = null; 178 } 179 180 @Override 181 public void init() 182 { 183 // build main frame 184 mainFrame = new MainFrame(); 185 mainFrame.init(); 186 mainFrame.addWindowListener(new WindowAdapter() 187 { 188 @Override 189 public void windowClosing(WindowEvent e) 190 { 191 // exit application 192 Icy.exit(false); 193 } 194 }); 195 196 taskFrameManager.init(); 197 } 198 199 @Override 200 public boolean isHeadLess() 201 { 202 // we are not head less with this interface 203 return false; 204 } 205 206 @Override 207 public void addSequence(Sequence sequence) 208 { 209 if (sequence != null) 210 { 211 final Sequence seq = sequence; 212 213 // thread safe 214 ThreadUtil.invokeLater(new Runnable() 215 { 216 @Override 217 public void run() 218 { 219 new Viewer(seq); 220 } 221 }); 222 } 223 } 224 225 @Override 226 public ArrayList<JFrame> getExternalFrames() 227 { 228 final ArrayList<JFrame> result = new ArrayList<JFrame>(); 229 final Window[] windows = Window.getWindows(); 230 231 for (Window w : windows) 232 if (w instanceof JFrame) 233 result.add((JFrame) w); 234 235 return result; 236 } 237 238 @Override 239 public ArrayList<JInternalFrame> getInternalFrames() 240 { 241 if (mainFrame == null) 242 return new ArrayList<JInternalFrame>(); 243 244 return mainFrame.getInternalFrames(); 245 246 } 247 248 /** 249 * @return the preferences 250 */ 251 @Override 252 public XMLPreferences getPreferences() 253 { 254 return IcyPreferences.applicationRoot(); 255 } 256 257 @Override 258 public InspectorPanel getInspector() 259 { 260 if (mainFrame == null) 261 return null; 262 263 return mainFrame.getInspector(); 264 } 265 266 @Override 267 public RoisPanel getRoisPanel() 268 { 269 if (mainFrame == null) 270 return null; 271 272 final InspectorPanel inspector = mainFrame.getInspector(); 273 if (inspector == null) 274 return null; 275 276 return inspector.getRoisPanel(); 277 } 278 279 @Override 280 public LayersPanel getLayersPanel() 281 { 282 if (mainFrame == null) 283 return null; 284 285 final InspectorPanel inspector = mainFrame.getInspector(); 286 if (inspector == null) 287 return null; 288 289 return inspector.getLayersPanel(); 290 } 291 292 @Override 293 public ArrayList<Plugin> getActivePlugins() 294 { 295 final ArrayList<Plugin> result = new ArrayList<Plugin>(); 296 297 synchronized (activePlugins) 298 { 299 for (WeakReference<Plugin> ref : activePlugins) 300 { 301 final Plugin plugin = ref.get(); 302 303 if (plugin != null) 304 result.add(plugin); 305 } 306 } 307 308 return result; 309 } 310 311 @Override 312 public LUT getActiveLUT() 313 { 314 if (activeViewer != null) 315 return activeViewer.getLut(); 316 317 return null; 318 } 319 320 @Override 321 public Viewer getActiveViewer() 322 { 323 return activeViewer; 324 } 325 326 @Override 327 public Sequence getActiveSequence() 328 { 329 return activeSequence; 330 } 331 332 @Override 333 public IcyBufferedImage getActiveImage() 334 { 335 if (activeViewer != null) 336 return activeViewer.getCurrentImage(); 337 338 return null; 339 } 340 341 @Override 342 @Deprecated 343 public Viewer getFocusedViewer() 344 { 345 return getActiveViewer(); 346 } 347 348 @Override 349 @Deprecated 350 public Sequence getFocusedSequence() 351 { 352 return getActiveSequence(); 353 } 354 355 @Override 356 @Deprecated 357 public IcyBufferedImage getFocusedImage() 358 { 359 return getActiveImage(); 360 } 361 362 @Override 363 public IcyUndoManager getUndoManager() 364 { 365 if (activeSequence != null) 366 return activeSequence.getUndoManager(); 367 368 return null; 369 } 370 371 @Override 372 public boolean undo() 373 { 374 if (activeSequence != null) 375 return activeSequence.undo(); 376 377 return false; 378 } 379 380 @Override 381 public boolean redo() 382 { 383 if (activeSequence != null) 384 return activeSequence.redo(); 385 386 return false; 387 } 388 389 @Override 390 public ArrayList<Viewer> getViewers() 391 { 392 synchronized (viewers) 393 { 394 return new ArrayList<Viewer>(viewers); 395 } 396 } 397 398 @Override 399 public synchronized void setActiveViewer(Viewer viewer) 400 { 401 if (activeViewer == viewer) 402 return; 403 404 // got a previously active viewer ? 405 if (activeViewer != null) 406 { 407 // remove active viewer listener 408 activeViewer.removeListener(activeViewerListener); 409 410 // force previous viewer internal frame to release focus 411 try 412 { 413 activeViewer.getInternalFrame().setSelected(false); 414 } 415 catch (PropertyVetoException e) 416 { 417 // ignore 418 } 419 } 420 421 previousActiveViewer = activeViewer; 422 activeViewer = viewer; 423 424 // add active viewer listener 425 if (activeViewer != null) 426 activeViewer.addListener(activeViewerListener); 427 428 // activation changed 429 viewerActivationChanged(previousActiveViewer, activeViewer); 430 } 431 432 @Override 433 @Deprecated 434 public synchronized void setFocusedViewer(Viewer viewer) 435 { 436 setActiveViewer(viewer); 437 } 438 439 @Override 440 public synchronized void addToDesktopPane(JInternalFrame internalFrame) 441 { 442 getDesktopPane().add(internalFrame, JLayeredPane.DEFAULT_LAYER); 443 } 444 445 @Override 446 public IcyDesktopPane getDesktopPane() 447 { 448 if (mainFrame == null) 449 return null; 450 451 return mainFrame.getDesktopPane(); 452 } 453 454 @Override 455 public ApplicationMenu getApplicationMenu() 456 { 457 if (mainFrame == null) 458 return null; 459 460 return mainFrame.getApplicationMenu(); 461 } 462 463 @Override 464 public TaskFrameManager getTaskWindowManager() 465 { 466 return taskFrameManager; 467 } 468 469 private WeakReference<Plugin> getPluginReference(Plugin plugin) 470 { 471 synchronized (activePlugins) 472 { 473 for (WeakReference<Plugin> ref : activePlugins) 474 if (ref.get() == plugin) 475 return ref; 476 } 477 478 return null; 479 } 480 481 @Deprecated 482 @Override 483 public void registerExternalFrame(JFrame frame) 484 { 485 486 } 487 488 @Deprecated 489 @Override 490 public void unRegisterExternalFrame(JFrame frame) 491 { 492 493 } 494 495 @Override 496 public synchronized void registerPlugin(Plugin plugin) 497 { 498 synchronized (activePlugins) 499 { 500 activePlugins.add(new WeakReference<Plugin>(plugin)); 501 } 502 503 // plugin opened 504 pluginStarted(plugin); 505 } 506 507 @Override 508 public synchronized void unRegisterPlugin(Plugin plugin) 509 { 510 final WeakReference<Plugin> ref = getPluginReference(plugin); 511 512 synchronized (activePlugins) 513 { 514 // reference found 515 if (ref != null) 516 activePlugins.remove(ref); 517 } 518 519 // plugin closed 520 pluginEnded(plugin); 521 } 522 523 @Override 524 public synchronized void registerViewer(Viewer viewer) 525 { 526 if (viewer == null) 527 return; 528 529 // viewer opened 530 viewerOpened(viewer); 531 } 532 533 @Override 534 public synchronized void unRegisterViewer(Viewer viewer) 535 { 536 if (viewer == null) 537 return; 538 539 // viewer closed 540 viewerClosed(viewer); 541 542 // no more opened viewer ? 543 if (viewers.isEmpty()) 544 // set focus to null 545 setActiveViewer(null); 546 else 547 { 548 final IcyFrame frame = IcyFrame.findIcyFrame(getDesktopPane().getSelectedFrame()); 549 550 if (frame instanceof Viewer) 551 ((Viewer) frame).requestFocus(); 552 else 553 { 554 // it was the active viewer ? 555 if (activeViewer == viewer) 556 { 557 // restore focus to previous active 558 if (previousActiveViewer != null) 559 { 560 setActiveViewer(previousActiveViewer); 561 // no more previous active now 562 previousActiveViewer = null; 563 } 564 else 565 // or just focus another one 566 setActiveViewer(viewers.get(viewers.size() - 1)); 567 } 568 } 569 } 570 } 571 572 @Override 573 @Deprecated 574 public MainFrame getFrame() 575 { 576 return getMainFrame(); 577 } 578 579 @Override 580 public MainFrame getMainFrame() 581 { 582 return mainFrame; 583 } 584 585 @Override 586 public SearchEngine getSearchEngine() 587 { 588 return mainFrame.getSearchBar().getSearchEngine(); 589 } 590 591 @Override 592 public void closeSequence(Sequence sequence) 593 { 594 // use copy as this actually modify viewers list 595 for (Viewer v : getViewers()) 596 if (v.getSequence() == sequence) 597 v.close(); 598 } 599 600 @Deprecated 601 @Override 602 public void closeViewersOfSequence(Sequence sequence) 603 { 604 closeSequence(sequence); 605 } 606 607 @Override 608 public synchronized void closeAllViewers() 609 { 610 // use copy as this actually modify viewers list 611 for (Viewer viewer : getViewers()) 612 viewer.close(); 613 } 614 615 @Override 616 public Viewer getFirstViewerContaining(ROI roi) 617 { 618 return getFirstViewer(getFirstSequenceContaining(roi)); 619 } 620 621 @Deprecated 622 @Override 623 public Viewer getFirstViewerContaining(Painter painter) 624 { 625 return getFirstViewer(getFirstSequenceContaining(painter)); 626 } 627 628 @Override 629 public Viewer getFirstViewerContaining(Overlay overlay) 630 { 631 return getFirstViewer(getFirstSequenceContaining(overlay)); 632 } 633 634 @Override 635 public Viewer getFirstViewer(Sequence sequence) 636 { 637 if (sequence != null) 638 { 639 for (Viewer viewer : getViewers()) 640 if (viewer.getSequence() == sequence) 641 return viewer; 642 } 643 644 return null; 645 } 646 647 @Override 648 public ArrayList<Viewer> getViewers(Sequence sequence) 649 { 650 final ArrayList<Viewer> result = new ArrayList<Viewer>(); 651 652 for (Viewer v : getViewers()) 653 if (v.getSequence() == sequence) 654 result.add(v); 655 656 return result; 657 } 658 659 @Override 660 public boolean isUniqueViewer(Viewer viewer) 661 { 662 final List<Viewer> viewers = getViewers(viewer.getSequence()); 663 664 return (viewers.size() == 1) && (viewers.get(0) == viewer); 665 } 666 667 @Override 668 public ArrayList<Sequence> getSequences() 669 { 670 synchronized (sequences) 671 { 672 return new ArrayList<Sequence>(sequences); 673 } 674 } 675 676 @Override 677 public ArrayList<Sequence> getSequences(String name) 678 { 679 final ArrayList<Sequence> result = new ArrayList<Sequence>(); 680 681 synchronized (viewers) 682 { 683 for (Viewer viewer : viewers) 684 { 685 final Sequence sequence = viewer.getSequence(); 686 687 // matching name and no duplicate 688 if (!result.contains(sequence) && StringUtil.equals(name, sequence.getName())) 689 result.add(sequence); 690 } 691 } 692 693 return result; 694 } 695 696 @Override 697 public boolean isOpened(Sequence sequence) 698 { 699 return getSequences().contains(sequence); 700 } 701 702 @Deprecated 703 @Override 704 public Sequence getFirstSequencesContaining(ROI roi) 705 { 706 return getFirstSequenceContaining(roi); 707 } 708 709 @Override 710 public Sequence getFirstSequenceContaining(ROI roi) 711 { 712 for (Sequence seq : getSequences()) 713 if (seq.contains(roi)) 714 return seq; 715 716 return null; 717 } 718 719 @Deprecated 720 @Override 721 public Sequence getFirstSequencesContaining(Painter painter) 722 { 723 return getFirstSequenceContaining(painter); 724 } 725 726 @Deprecated 727 @Override 728 public Sequence getFirstSequenceContaining(Painter painter) 729 { 730 for (Sequence seq : getSequences()) 731 if (seq.contains(painter)) 732 return seq; 733 734 return null; 735 } 736 737 @Override 738 public Sequence getFirstSequenceContaining(Overlay overlay) 739 { 740 for (Sequence seq : getSequences()) 741 if (seq.contains(overlay)) 742 return seq; 743 744 return null; 745 } 746 747 @Override 748 public ArrayList<Sequence> getSequencesContaining(ROI roi) 749 { 750 final ArrayList<Sequence> result = getSequences(); 751 752 for (int i = result.size() - 1; i >= 0; i--) 753 if (!result.get(i).contains(roi)) 754 result.remove(i); 755 756 return result; 757 } 758 759 @Override 760 @Deprecated 761 public ArrayList<Sequence> getSequencesContaining(Painter painter) 762 { 763 final ArrayList<Sequence> result = getSequences(); 764 765 for (int i = result.size() - 1; i >= 0; i--) 766 if (!result.get(i).contains(painter)) 767 result.remove(i); 768 769 return result; 770 } 771 772 @Override 773 public List<Sequence> getSequencesContaining(Overlay overlay) 774 { 775 final ArrayList<Sequence> result = getSequences(); 776 777 for (int i = result.size() - 1; i >= 0; i--) 778 if (!result.get(i).contains(overlay)) 779 result.remove(i); 780 781 return result; 782 } 783 784 @Override 785 public ArrayList<ROI> getROIs() 786 { 787 // HashSet is better suited for add elements 788 final HashSet<ROI> result = new HashSet<ROI>(); 789 790 for (Sequence seq : getSequences()) 791 for (ROI roi : seq.getROISet()) 792 result.add(roi); 793 794 // TODO: add ROI from swimming pool ? 795 796 return new ArrayList<ROI>(result); 797 } 798 799 @Override 800 @Deprecated 801 public ROI getROI(Painter painter) 802 { 803 if (painter instanceof Overlay) 804 return getROI((Overlay) painter); 805 806 return null; 807 } 808 809 @Override 810 public ROI getROI(Overlay overlay) 811 { 812 final List<ROI> rois = getROIs(); 813 814 for (ROI roi : rois) 815 if (roi.getOverlay() == overlay) 816 return roi; 817 818 return null; 819 } 820 821 @Override 822 @Deprecated 823 public ArrayList<Painter> getPainters() 824 { 825 // HashSet better suited for add element 826 final HashSet<Painter> result = new HashSet<Painter>(); 827 828 for (Sequence seq : getSequences()) 829 result.addAll(seq.getPainterSet()); 830 831 // TODO: add Painter from swimming pool ? 832 833 return new ArrayList<Painter>(); 834 } 835 836 @Override 837 public List<Overlay> getOverlays() 838 { 839 // HashSet better suited for add element 840 final HashSet<Overlay> result = new HashSet<Overlay>(); 841 842 for (Sequence seq : getSequences()) 843 result.addAll(seq.getOverlaySet()); 844 845 // TODO: add Overlay from swimming pool ? 846 847 return new ArrayList<Overlay>(); 848 } 849 850 @Override 851 public SwimmingPool getSwimmingPool() 852 { 853 return swimmingPool; 854 } 855 856 @Override 857 public ImageJWrapper getImageJ() 858 { 859 if (mainFrame == null) 860 return null; 861 862 return mainFrame.getMainRibbon().getImageJ(); 863 } 864 865 @Override 866 public String getSelectedTool() 867 { 868 if (mainFrame == null) 869 return null; 870 871 return getROIRibbonTask().getSelected(); 872 } 873 874 @Override 875 public void setSelectedTool(String command) 876 { 877 if (mainFrame != null) 878 getROIRibbonTask().setSelected(command); 879 } 880 881 @Override 882 public ROITask getROIRibbonTask() 883 { 884 if (mainFrame == null) 885 return null; 886 887 return mainFrame.getMainRibbon().getROIRibbonTask(); 888 } 889 890 @Deprecated 891 @Override 892 public ToolRibbonTask getToolRibbon() 893 { 894 if (mainFrame == null) 895 return null; 896 897 return mainFrame.getMainRibbon().getToolRibbon(); 898 } 899 900 @Override 901 public boolean isAlwaysOnTop() 902 { 903 if (mainFrame == null) 904 return false; 905 906 return mainFrame.isAlwaysOnTop(); 907 } 908 909 @Override 910 public void setAlwaysOnTop(boolean value) 911 { 912 if (mainFrame != null) 913 mainFrame.setAlwaysOnTop(value); 914 } 915 916 @Override 917 public boolean isDetachedMode() 918 { 919 if (mainFrame == null) 920 return false; 921 922 return mainFrame.isDetachedMode(); 923 } 924 925 @Override 926 public void setDetachedMode(boolean value) 927 { 928 if (mainFrame != null) 929 mainFrame.setDetachedMode(value); 930 } 931 932 @Override 933 @Deprecated 934 public synchronized void addListener(MainListener listener) 935 { 936 if (listener != null) 937 mainListeners.add(listener); 938 } 939 940 @Override 941 @Deprecated 942 public synchronized void removeListener(MainListener listener) 943 { 944 mainListeners.remove(listener); 945 } 946 947 @Override 948 public synchronized void addGlobalViewerListener(GlobalViewerListener listener) 949 { 950 if (listener != null) 951 globalViewerListeners.add(listener); 952 } 953 954 @Override 955 public synchronized void removeGlobalViewerListener(GlobalViewerListener listener) 956 { 957 globalViewerListeners.remove(listener); 958 } 959 960 @Override 961 public synchronized void addGlobalSequenceListener(GlobalSequenceListener listener) 962 { 963 if (listener != null) 964 globalSequenceListeners.add(listener); 965 } 966 967 @Override 968 public synchronized void removeGlobalSequenceListener(GlobalSequenceListener listener) 969 { 970 globalSequenceListeners.remove(listener); 971 } 972 973 @Override 974 public synchronized void addGlobalROIListener(GlobalROIListener listener) 975 { 976 if (listener != null) 977 globalROIListeners.add(listener); 978 } 979 980 @Override 981 public synchronized void removeGlobalROIListener(GlobalROIListener listener) 982 { 983 globalROIListeners.remove(listener); 984 } 985 986 @Override 987 public synchronized void addGlobalOverlayListener(GlobalOverlayListener listener) 988 { 989 if (listener != null) 990 globalOverlayListeners.add(listener); 991 } 992 993 @Override 994 public synchronized void removeGlobalOverlayListener(GlobalOverlayListener listener) 995 { 996 globalOverlayListeners.remove(listener); 997 } 998 999 @Override 1000 public synchronized void addGlobalPluginListener(GlobalPluginListener listener) 1001 { 1002 if (listener != null) 1003 listeners.add(GlobalPluginListener.class, listener); 1004 } 1005 1006 @Override 1007 public synchronized void removeGlobalPluginListener(GlobalPluginListener listener) 1008 { 1009 listeners.remove(GlobalPluginListener.class, listener); 1010 } 1011 1012 @Override 1013 public synchronized void addCanExitListener(AcceptListener listener) 1014 { 1015 if (listener != null) 1016 listeners.add(WeakAcceptListener.class, new WeakAcceptListener(listener)); 1017 } 1018 1019 @Override 1020 public synchronized void removeCanExitListener(AcceptListener listener) 1021 { 1022 // we use weak reference so we have to find base listener... 1023 for (WeakAcceptListener l : listeners.getListeners(WeakAcceptListener.class)) 1024 if (listener == l.getListener()) 1025 internalRemoveCanExitListener(l); 1026 } 1027 1028 public synchronized void internalRemoveCanExitListener(WeakAcceptListener listener) 1029 { 1030 listeners.remove(WeakAcceptListener.class, listener); 1031 } 1032 1033 @Deprecated 1034 @Override 1035 public synchronized void addFocusedViewerListener(FocusedViewerListener listener) 1036 { 1037 listeners.add(FocusedViewerListener.class, listener); 1038 } 1039 1040 @Deprecated 1041 @Override 1042 public synchronized void removeFocusedViewerListener(FocusedViewerListener listener) 1043 { 1044 listeners.remove(FocusedViewerListener.class, listener); 1045 } 1046 1047 @Deprecated 1048 @Override 1049 public synchronized void addFocusedSequenceListener(FocusedSequenceListener listener) 1050 { 1051 listeners.add(FocusedSequenceListener.class, listener); 1052 } 1053 1054 @Deprecated 1055 @Override 1056 public synchronized void removeFocusedSequenceListener(FocusedSequenceListener listener) 1057 { 1058 listeners.remove(FocusedSequenceListener.class, listener); 1059 } 1060 1061 @Override 1062 public synchronized void addActiveViewerListener(ActiveViewerListener listener) 1063 { 1064 listeners.add(ActiveViewerListener.class, listener); 1065 } 1066 1067 @Override 1068 public synchronized void removeActiveViewerListener(ActiveViewerListener listener) 1069 { 1070 listeners.remove(ActiveViewerListener.class, listener); 1071 } 1072 1073 @Override 1074 public synchronized void addActiveSequenceListener(ActiveSequenceListener listener) 1075 { 1076 listeners.add(ActiveSequenceListener.class, listener); 1077 } 1078 1079 @Override 1080 public synchronized void removeActiveSequenceListener(ActiveSequenceListener listener) 1081 { 1082 listeners.remove(ActiveSequenceListener.class, listener); 1083 } 1084 1085 /** 1086 * fire plugin opened event 1087 */ 1088 @SuppressWarnings("deprecation") 1089 private void firePluginStartedEvent(Plugin plugin) 1090 { 1091 for (GlobalPluginListener listener : listeners.getListeners(GlobalPluginListener.class)) 1092 listener.pluginStarted(plugin); 1093 1094 // backward compatibility 1095 final MainEvent event = new MainEvent(MainEventSourceType.PLUGIN, MainEventType.OPENED, plugin); 1096 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1097 listener.pluginOpened(event); 1098 } 1099 1100 /** 1101 * fire plugin closed event 1102 */ 1103 @SuppressWarnings("deprecation") 1104 private void firePluginEndedEvent(Plugin plugin) 1105 { 1106 for (GlobalPluginListener listener : listeners.getListeners(GlobalPluginListener.class)) 1107 listener.pluginEnded(plugin); 1108 1109 // backward compatibility 1110 final MainEvent event = new MainEvent(MainEventSourceType.PLUGIN, MainEventType.CLOSED, plugin); 1111 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1112 listener.pluginClosed(event); 1113 } 1114 1115 /** 1116 * fire viewer opened event 1117 */ 1118 @SuppressWarnings("deprecation") 1119 private void fireViewerOpenedEvent(Viewer viewer) 1120 { 1121 for (GlobalViewerListener listener : new ArrayList<GlobalViewerListener>(globalViewerListeners)) 1122 listener.viewerOpened(viewer); 1123 1124 // backward compatibility 1125 final MainEvent event = new MainEvent(MainEventSourceType.VIEWER, MainEventType.OPENED, viewer); 1126 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1127 listener.viewerOpened(event); 1128 } 1129 1130 /** 1131 * fire viewer close event 1132 */ 1133 @SuppressWarnings("deprecation") 1134 private void fireViewerClosedEvent(Viewer viewer) 1135 { 1136 for (GlobalViewerListener listener : new ArrayList<GlobalViewerListener>(globalViewerListeners)) 1137 listener.viewerClosed(viewer); 1138 1139 // backward compatibility 1140 final MainEvent event = new MainEvent(MainEventSourceType.VIEWER, MainEventType.CLOSED, viewer); 1141 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1142 listener.viewerClosed(event); 1143 } 1144 1145 /** 1146 * fire viewer deactive event 1147 */ 1148 private void fireViewerDeactivatedEvent(Viewer viewer) 1149 { 1150 for (ActiveViewerListener listener : listeners.getListeners(ActiveViewerListener.class)) 1151 listener.viewerDeactivated(viewer); 1152 } 1153 1154 /** 1155 * fire viewer active event 1156 */ 1157 @SuppressWarnings("deprecation") 1158 private void fireViewerActivatedEvent(Viewer viewer) 1159 { 1160 for (ActiveViewerListener listener : listeners.getListeners(ActiveViewerListener.class)) 1161 listener.viewerActivated(viewer); 1162 1163 // backward compatibility 1164 final MainEvent event = new MainEvent(MainEventSourceType.VIEWER, MainEventType.FOCUSED, viewer); 1165 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1166 listener.viewerFocused(event); 1167 for (FocusedViewerListener listener : listeners.getListeners(FocusedViewerListener.class)) 1168 listener.focusChanged(viewer); 1169 } 1170 1171 /** 1172 * fire sequence opened event 1173 */ 1174 @SuppressWarnings("deprecation") 1175 private void fireSequenceOpenedEvent(Sequence sequence) 1176 { 1177 for (GlobalSequenceListener listener : new ArrayList<GlobalSequenceListener>(globalSequenceListeners)) 1178 listener.sequenceOpened(sequence); 1179 1180 // backward compatibility 1181 final MainEvent event = new MainEvent(MainEventSourceType.SEQUENCE, MainEventType.OPENED, sequence); 1182 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1183 listener.sequenceOpened(event); 1184 } 1185 1186 /** 1187 * fire sequence active event 1188 */ 1189 @SuppressWarnings("deprecation") 1190 private void fireSequenceClosedEvent(Sequence sequence) 1191 { 1192 for (GlobalSequenceListener listener : new ArrayList<GlobalSequenceListener>(globalSequenceListeners)) 1193 listener.sequenceClosed(sequence); 1194 1195 // backward compatibility 1196 final MainEvent event = new MainEvent(MainEventSourceType.SEQUENCE, MainEventType.CLOSED, sequence); 1197 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1198 listener.sequenceClosed(event); 1199 } 1200 1201 /** 1202 * fire sequence deactive event 1203 */ 1204 private void fireSequenceDeactivatedEvent(Sequence sequence) 1205 { 1206 for (ActiveSequenceListener listener : listeners.getListeners(ActiveSequenceListener.class)) 1207 listener.sequenceDeactivated(sequence); 1208 } 1209 1210 /** 1211 * fire sequence active event 1212 */ 1213 @SuppressWarnings("deprecation") 1214 private void fireSequenceActivatedEvent(Sequence sequence) 1215 { 1216 for (ActiveSequenceListener listener : listeners.getListeners(ActiveSequenceListener.class)) 1217 listener.sequenceActivated(sequence); 1218 1219 // backward compatibility 1220 final MainEvent event = new MainEvent(MainEventSourceType.SEQUENCE, MainEventType.FOCUSED, sequence); 1221 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1222 listener.sequenceFocused(event); 1223 for (FocusedSequenceListener listener : listeners.getListeners(FocusedSequenceListener.class)) 1224 listener.focusChanged(sequence); 1225 } 1226 1227 /** 1228 * fire ROI added event 1229 */ 1230 @SuppressWarnings("deprecation") 1231 private void fireRoiAddedEvent(ROI roi) 1232 { 1233 for (GlobalROIListener listener : new ArrayList<GlobalROIListener>(globalROIListeners)) 1234 listener.roiAdded(roi); 1235 1236 // backward compatibility 1237 final MainEvent event = new MainEvent(MainEventSourceType.ROI, MainEventType.ADDED, roi); 1238 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1239 listener.roiAdded(event); 1240 } 1241 1242 /** 1243 * fire ROI removed event 1244 */ 1245 @SuppressWarnings("deprecation") 1246 private void fireRoiRemovedEvent(ROI roi) 1247 { 1248 for (GlobalROIListener listener : new ArrayList<GlobalROIListener>(globalROIListeners)) 1249 listener.roiRemoved(roi); 1250 1251 // backward compatibility 1252 final MainEvent event = new MainEvent(MainEventSourceType.ROI, MainEventType.REMOVED, roi); 1253 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1254 listener.roiRemoved(event); 1255 } 1256 1257 /** 1258 * fire painter added event 1259 */ 1260 @SuppressWarnings("deprecation") 1261 private void fireOverlayAddedEvent(Overlay overlay) 1262 { 1263 for (GlobalOverlayListener listener : new ArrayList<GlobalOverlayListener>(globalOverlayListeners)) 1264 listener.overlayAdded(overlay); 1265 1266 // backward compatibility 1267 final Painter painter; 1268 1269 if (overlay instanceof OverlayWrapper) 1270 painter = ((OverlayWrapper) overlay).getPainter(); 1271 else 1272 painter = overlay; 1273 1274 final MainEvent event = new MainEvent(MainEventSourceType.PAINTER, MainEventType.ADDED, painter); 1275 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1276 listener.painterAdded(event); 1277 } 1278 1279 /** 1280 * fire painter removed event 1281 */ 1282 @SuppressWarnings("deprecation") 1283 private void fireOverlayRemovedEvent(Overlay overlay) 1284 { 1285 for (GlobalOverlayListener listener : new ArrayList<GlobalOverlayListener>(globalOverlayListeners)) 1286 listener.overlayRemoved(overlay); 1287 1288 // backward compatibility 1289 final Painter painter; 1290 1291 if (overlay instanceof OverlayWrapper) 1292 painter = ((OverlayWrapper) overlay).getPainter(); 1293 else 1294 painter = overlay; 1295 1296 final MainEvent event = new MainEvent(MainEventSourceType.PAINTER, MainEventType.REMOVED, painter); 1297 for (MainListener listener : new ArrayList<MainListener>(mainListeners)) 1298 listener.painterRemoved(event); 1299 } 1300 1301 /** 1302 * fire active viewer changed event 1303 */ 1304 @SuppressWarnings("deprecation") 1305 private void fireActiveViewerChangedEvent(ViewerEvent event) 1306 { 1307 for (ActiveViewerListener listener : listeners.getListeners(ActiveViewerListener.class)) 1308 listener.activeViewerChanged(event); 1309 1310 // backward compatibility 1311 for (FocusedViewerListener listener : listeners.getListeners(FocusedViewerListener.class)) 1312 listener.focusedViewerChanged(event); 1313 } 1314 1315 /** 1316 * fire active sequence changed event 1317 */ 1318 @SuppressWarnings("deprecation") 1319 private void fireActiveSequenceChangedEvent(SequenceEvent event) 1320 { 1321 for (ActiveSequenceListener listener : listeners.getListeners(ActiveSequenceListener.class)) 1322 listener.activeSequenceChanged(event); 1323 1324 // backward compatibility 1325 for (FocusedSequenceListener listener : listeners.getListeners(FocusedSequenceListener.class)) 1326 listener.focusedSequenceChanged(event); 1327 } 1328 1329 @Override 1330 public boolean canExitExternal() 1331 { 1332 for (AcceptListener listener : listeners.getListeners(WeakAcceptListener.class)) 1333 if (!listener.accept(mainFrame)) 1334 return false; 1335 1336 return true; 1337 } 1338 1339 @Deprecated 1340 @Override 1341 public void beginUpdate() 1342 { 1343 // updater.beginUpdate(); 1344 } 1345 1346 @Deprecated 1347 @Override 1348 public void endUpdate() 1349 { 1350 // updater.endUpdate(); 1351 } 1352 1353 @Deprecated 1354 @Override 1355 public boolean isUpdating() 1356 { 1357 return false; 1358 // return updater.isUpdating(); 1359 } 1360 1361 /** 1362 * called when a plugin is opened 1363 */ 1364 private void pluginStarted(Plugin plugin) 1365 { 1366 firePluginStartedEvent(plugin); 1367 } 1368 1369 /** 1370 * called when a plugin is closed 1371 */ 1372 private void pluginEnded(Plugin plugin) 1373 { 1374 firePluginEndedEvent(plugin); 1375 } 1376 1377 /** 1378 * called when a viewer is opened 1379 */ 1380 private void viewerOpened(Viewer viewer) 1381 { 1382 final Sequence sequence = viewer.getSequence(); 1383 boolean opened = true; 1384 1385 synchronized (viewers) 1386 { 1387 // check if the sequence has just been opened 1388 if (sequence != null) 1389 { 1390 for (Viewer v : viewers) 1391 { 1392 if (v.getSequence() == sequence) 1393 { 1394 opened = false; 1395 break; 1396 } 1397 } 1398 } 1399 1400 // add viewer to the viewer list 1401 viewers.add(viewer); 1402 } 1403 1404 // single viewer for this sequence ? 1405 if ((sequence != null) && opened) 1406 // send opened event 1407 sequenceOpened(sequence); 1408 1409 // fire viewer open event (after sequence open) 1410 fireViewerOpenedEvent(viewer); 1411 } 1412 1413 /** 1414 * called when viewer activation changed 1415 */ 1416 private void viewerActivationChanged(Viewer oldActive, Viewer newActive) 1417 { 1418 final Sequence sequence; 1419 1420 // new active viewer is not null ? 1421 if (newActive != null) 1422 { 1423 // remove focus on ImageJ image 1424 final ImageJWrapper ij = Icy.getMainInterface().getImageJ(); 1425 if (ij != null) 1426 ij.setActiveImage(null); 1427 1428 // get active sequence 1429 sequence = newActive.getSequence(); 1430 } 1431 else 1432 sequence = null; 1433 1434 final Sequence oldActiveSequence = activeSequence; 1435 1436 // sequence active changed ? 1437 if (oldActiveSequence != sequence) 1438 { 1439 activeSequence = sequence; 1440 sequenceActivationChanged(oldActiveSequence, sequence); 1441 } 1442 1443 // fire deactivated / activated events 1444 fireViewerDeactivatedEvent(oldActive); 1445 fireViewerActivatedEvent(newActive); 1446 } 1447 1448 /** 1449 * called when the active viewer changed 1450 */ 1451 void activeViewerChanged(ViewerEvent event) 1452 { 1453 // propagate event if it comes from the active viewer 1454 // FIXME: why we need to test that ? it should always be the active viewer ? 1455 if (event.getSource() == activeViewer) 1456 fireActiveViewerChangedEvent(event); 1457 } 1458 1459 /** 1460 * called when a viewer is closed 1461 */ 1462 private void viewerClosed(Viewer viewer) 1463 { 1464 // retrieve the viewer LUT before we release it 1465 final LUT lut = viewer.getLut(); 1466 1467 // remove active viewer listener 1468 if (viewer == activeViewer) 1469 viewer.removeListener(activeViewerListener); 1470 // remove viewer from the viewer list 1471 synchronized (viewers) 1472 { 1473 viewers.remove(viewer); 1474 } 1475 // fire viewer closed event (before sequence close) 1476 fireViewerClosedEvent(viewer); 1477 1478 final Sequence sequence = viewer.getSequence(); 1479 1480 // check if a sequence has been closed 1481 if (sequence != null) 1482 { 1483 // if no viewer for this sequence 1484 if (getViewers(sequence).isEmpty()) 1485 // sequence close 1486 sequenceClosed(sequence, lut); 1487 } 1488 } 1489 1490 /** 1491 * called when a sequence is opened 1492 */ 1493 private void sequenceOpened(Sequence sequence) 1494 { 1495 // add to sequence list 1496 synchronized (sequences) 1497 { 1498 sequences.add(sequence); 1499 } 1500 // listen the sequence 1501 sequence.addListener(sequenceListener); 1502 // fire sequence opened event (before roi / overlay events) 1503 fireSequenceOpenedEvent(sequence); 1504 1505 // check about ROI add event 1506 for (ROI roi : sequence.getROIs()) 1507 checkRoiAdded(roi, false); 1508 // check about Overlay add event 1509 for (Overlay overlay : sequence.getOverlays()) 1510 checkOverlayAdded(overlay, false); 1511 } 1512 1513 /** 1514 * called when sequence activation changed 1515 */ 1516 private void sequenceActivationChanged(Sequence oldActive, Sequence newActive) 1517 { 1518 // fire events 1519 fireSequenceDeactivatedEvent(oldActive); 1520 fireSequenceActivatedEvent(newActive); 1521 } 1522 1523 /** 1524 * called when a sequence changed 1525 */ 1526 void sequenceChanged(SequenceEvent event) 1527 { 1528 final Sequence sequence = event.getSequence(); 1529 1530 // handle event for active sequence only 1531 if (isOpened(sequence)) 1532 { 1533 switch (event.getSourceType()) 1534 { 1535 case SEQUENCE_ROI: 1536 switch (event.getType()) 1537 { 1538 case ADDED: 1539 checkRoiAdded((ROI) event.getSource(), false); 1540 break; 1541 1542 case REMOVED: 1543 checkRoiRemoved((ROI) event.getSource(), false); 1544 break; 1545 } 1546 break; 1547 1548 case SEQUENCE_OVERLAY: 1549 switch (event.getType()) 1550 { 1551 case ADDED: 1552 checkOverlayAdded((Overlay) event.getSource(), false); 1553 break; 1554 1555 case REMOVED: 1556 checkOverlayRemoved((Overlay) event.getSource(), false); 1557 break; 1558 } 1559 break; 1560 } 1561 } 1562 1563 // propagate event if it comes from the active sequence 1564 if (sequence == activeSequence) 1565 fireActiveSequenceChangedEvent(event); 1566 } 1567 1568 /** 1569 * Called when a sequence is closed. 1570 * 1571 * @param sequence 1572 * the sequence which has been closed. 1573 * @param userLut 1574 * the viewer's LUT used when sequence has been closed. 1575 */ 1576 private void sequenceClosed(Sequence sequence, LUT userLut) 1577 { 1578 // check about Overlay remove event 1579 for (Overlay overlay : sequence.getOverlays()) 1580 checkOverlayRemoved(overlay, true); 1581 // check about ROI remove event 1582 for (ROI roi : sequence.getROIs()) 1583 checkRoiRemoved(roi, true); 1584 1585 // remove from sequence listener 1586 sequence.removeListener(sequenceListener); 1587 // remove from the sequence list 1588 synchronized (sequences) 1589 { 1590 sequences.remove(sequence); 1591 } 1592 1593 // set the user LUT in the sequence 1594 if (userLut != null) 1595 sequence.setUserLUT(userLut); 1596 // inform sequence is now closed 1597 sequence.closed(); 1598 1599 // fire sequence closed event (after roi / overlay events) 1600 fireSequenceClosedEvent(sequence); 1601 } 1602 1603 private void checkRoiAdded(ROI roi, boolean checkBeforeAdd) 1604 { 1605 final List<Sequence> sequencesContainingRoi = getSequencesContaining(roi); 1606 1607 // only 1 sequence contains (or will contain) this roi ? 1608 if (sequencesContainingRoi.size() == (checkBeforeAdd ? 0 : 1)) 1609 // roi added 1610 roiAdded(roi); 1611 } 1612 1613 private void checkRoiRemoved(ROI roi, boolean checkBeforeRemove) 1614 { 1615 final List<Sequence> sequencesContainingRoi = getSequencesContaining(roi); 1616 1617 // no more sequence contains (or will contain) this roi ? 1618 if (sequencesContainingRoi.size() == (checkBeforeRemove ? 1 : 0)) 1619 // roi removed 1620 roiRemoved(roi); 1621 } 1622 1623 private void checkOverlayAdded(Overlay overlay, boolean checkBeforeAdd) 1624 { 1625 final List<Sequence> sequencesContainingOverlay = getSequencesContaining(overlay); 1626 1627 // only 1 sequence contains (or will contain) this overlay ? 1628 if (sequencesContainingOverlay.size() == (checkBeforeAdd ? 0 : 1)) 1629 // overlay added 1630 overlayAdded(overlay); 1631 } 1632 1633 private void checkOverlayRemoved(Overlay overlay, boolean checkBeforeRemove) 1634 { 1635 final List<Sequence> sequencesContainingOverlay = getSequencesContaining(overlay); 1636 1637 // no more sequence contains (or will contain) this overlay ? 1638 if (sequencesContainingOverlay.size() == (checkBeforeRemove ? 1 : 0)) 1639 // overlay removed 1640 overlayRemoved(overlay); 1641 } 1642 1643 /** 1644 * called when a roi is added for the first time in a sequence 1645 */ 1646 private void roiAdded(ROI roi) 1647 { 1648 fireRoiAddedEvent(roi); 1649 } 1650 1651 /** 1652 * called when a roi is removed from all sequence 1653 */ 1654 private void roiRemoved(ROI roi) 1655 { 1656 fireRoiRemovedEvent(roi); 1657 } 1658 1659 /** 1660 * called when an overlay is added for the first time in a sequence 1661 */ 1662 private void overlayAdded(Overlay overlay) 1663 { 1664 fireOverlayAddedEvent(overlay); 1665 } 1666 1667 /** 1668 * called when an overlay is removed from all sequence 1669 */ 1670 private void overlayRemoved(Overlay overlay) 1671 { 1672 fireOverlayRemovedEvent(overlay); 1673 } 1674 1675 @Override 1676 public void setGlobalViewSyncId(int id) 1677 { 1678 for (Viewer viewer : getViewers()) 1679 viewer.setViewSyncId(id); 1680 } 1681 1682 @Override 1683 public boolean isVirtualMode() 1684 { 1685 return GeneralPreferences.getVirtualMode(); 1686 } 1687 1688 @Override 1689 public void setVirtualMode(boolean value) 1690 { 1691 final InspectorPanel inspector = getInspector(); 1692 if (inspector != null) 1693 inspector.setVirtualMode(value); 1694 } 1695}