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.imagej;
020
021import icy.gui.main.MainFrame;
022import icy.gui.util.SwingUtil;
023import icy.main.Icy;
024import icy.system.IcyExceptionHandler;
025import icy.system.SystemUtil;
026import icy.system.thread.ThreadUtil;
027import icy.util.ReflectionUtil;
028
029import java.awt.BorderLayout;
030import java.awt.Dimension;
031import java.awt.Image;
032import java.awt.MenuBar;
033import java.awt.Point;
034import java.awt.event.ContainerEvent;
035import java.awt.event.ContainerListener;
036import java.util.ArrayList;
037import java.util.List;
038
039import javax.swing.BorderFactory;
040import javax.swing.BoundedRangeModel;
041import javax.swing.JLabel;
042import javax.swing.JMenuBar;
043import javax.swing.JPanel;
044import javax.swing.JProgressBar;
045
046import ij.ImageJ;
047import ij.gui.ImageWindow;
048
049/**
050 * ImageJ Wrapper class.
051 * 
052 * @author Stephane
053 */
054public class ImageJWrapper extends ImageJ
055{
056    /**
057     * 
058     */
059    private static final long serialVersionUID = -4361946959228494782L;
060
061    public interface ImageJActiveImageListener
062    {
063        public void imageActived(ImageWindow iw);
064
065    }
066
067    public final static String PROPERTY_MENU = "menu";
068
069    /**
070     * swing GUI
071     */
072    final JPanel swingPanel;
073    JMenuBar swingMenuBar;
074    final JPanel swingStatusPanel;
075    final JLabel swingStatusLabel;
076    final JProgressBar swingProgressBar;
077    ToolbarWrapper swingToolBar;
078
079    /**
080     * internal
081     */
082    final List<ImageJActiveImageListener> listeners;
083    MenuBar menuBarSave;
084
085    public ImageJWrapper()
086    {
087        // silent creation
088        super(ImageJ.NO_SHOW);
089
090        swingPanel = new JPanel();
091        swingPanel.setLayout(new BorderLayout());
092
093        // menubar
094        swingMenuBar = null;
095        updateMenu();
096
097        // toolbar
098        swingToolBar = new ToolbarWrapper(this);
099        swingPanel.add(swingToolBar.getSwingComponent(), BorderLayout.CENTER);
100        try
101        {
102            // patch imageJ toolbar to uses our wrapper
103            ReflectionUtil.getField(this.getClass(), "toolbar", true).set(this, swingToolBar);
104        }
105        catch (Exception e)
106        {
107            IcyExceptionHandler.showErrorMessage(e, false);
108            System.err.println("Cannot install ImageJ toolbar wrapper");
109        }
110
111        // status bar
112        swingStatusPanel = new JPanel();
113        swingStatusPanel.setLayout(new BorderLayout());
114
115        swingStatusLabel = new JLabel();
116        swingStatusLabel.setPreferredSize(new Dimension(420, 24));
117        swingStatusLabel.setMaximumSize(new Dimension(420, 24));
118        swingStatusLabel.setFocusable(true);
119        swingStatusLabel.addKeyListener(this);
120        swingStatusLabel.addMouseListener(this);
121        swingStatusPanel.add(swingStatusLabel, BorderLayout.CENTER);
122        swingProgressBar = new JProgressBar(0, 1000);
123        swingProgressBar.setBorder(BorderFactory.createEmptyBorder());
124        swingProgressBar.setFocusable(true);
125        swingProgressBar.setPreferredSize(new Dimension(120, 20));
126        swingProgressBar.setMaximumSize(new Dimension(120, 20));
127        swingProgressBar.setValue(1000);
128        swingProgressBar.addKeyListener(this);
129        swingProgressBar.addMouseListener(this);
130        swingStatusPanel.add(swingProgressBar, BorderLayout.EAST);
131
132        swingPanel.add(swingStatusPanel, BorderLayout.SOUTH);
133        
134        // add original toolbar (but not visible) just to detect removing of it
135        swingToolBar.setVisible(false);
136        swingPanel.add(swingToolBar, BorderLayout.EAST);
137        swingPanel.addContainerListener(new ContainerListener()
138        {
139            @Override
140            public void componentRemoved(ContainerEvent e)
141            {
142                // original toolbar was removed ?
143                if (e.getChild() == swingToolBar)
144                    // remove its swing counterpart
145                    swingPanel.remove(swingToolBar.getSwingComponent());
146            }
147            
148            @Override
149            public void componentAdded(ContainerEvent e)
150            {
151                // original toolbar was (re)added ?
152                if (e.getChild() == swingToolBar)
153                    // add its swing counterpart
154                    swingPanel.add(swingToolBar.getSwingComponent());
155            }
156        });
157
158        swingPanel.validate();
159
160        listeners = new ArrayList<ImageJWrapper.ImageJActiveImageListener>();
161    }
162
163    @Override
164    public void removeNotify()
165    {
166        // TODO: remove this temporary hack when the "window dispose" bug will be fixed
167        // on the OpenJDK / Sun JVM
168        if (SystemUtil.isUnix())
169            swingPanel.remove(swingToolBar);
170
171        super.removeNotify();
172    }
173
174    void updateMenu()
175    {
176        ThreadUtil.invokeLater(new Runnable()
177        {
178            @Override
179            public void run()
180            {
181                if (swingPanel != null)
182                {
183                    if (swingMenuBar != null)
184                        swingPanel.remove(swingMenuBar);
185
186                    // update menu
187                    swingMenuBar = SwingUtil.getJMenuBar(menuBarSave, true);
188
189                    swingPanel.add(swingMenuBar, BorderLayout.NORTH);
190                    swingPanel.validate();
191                }
192            }
193        }, true);
194    }
195
196    public void setActiveImage(ImageWindow iw)
197    {
198        // notify active image changed
199        fireActiveImageChanged(iw);
200    }
201
202    public void showSwingProgress(final int currentIndex, final int finalIndex)
203    {
204        ThreadUtil.invokeLater(new Runnable()
205        {
206            @Override
207            public void run()
208            {
209                final BoundedRangeModel model = swingProgressBar.getModel();
210
211                model.setMaximum(finalIndex);
212                model.setValue(currentIndex);
213            }
214        });
215    }
216
217    public void showSwingStatus(String s)
218    {
219        swingStatusLabel.setText(s);
220    }
221
222    /**
223     * @return the Swing menuBar
224     */
225    public JMenuBar getSwingMenuBar()
226    {
227        return swingMenuBar;
228    }
229
230    /**
231     * @return the swingPanel
232     */
233    public JPanel getSwingPanel()
234    {
235        return swingPanel;
236    }
237
238    /**
239     * @return the Swing statusPanel
240     */
241    public JPanel getSwingStatusPanel()
242    {
243        return swingStatusPanel;
244    }
245
246    /**
247     * @return the Swing statusLabel
248     */
249    public JLabel getSwingStatusLabel()
250    {
251        return swingStatusLabel;
252    }
253
254    /**
255     * @return the Swing progressBar
256     */
257    public JProgressBar getSwingProgressBar()
258    {
259        return swingProgressBar;
260    }
261
262    /**
263     * ICY integration
264     */
265    public void menuChanged()
266    {
267        // rebuild menu
268        updateMenu();
269    }
270
271    /**
272     * ICY integration
273     */
274    @Override
275    public Point getLocationOnScreen()
276    {
277        final MainFrame mainFrame = Icy.getMainInterface().getMainFrame();
278
279        if (mainFrame != null)
280            return mainFrame.getLocationOnScreen();
281
282        return new Point(0, 0);
283    }
284
285    @Override
286    public void setMenuBar(MenuBar mb)
287    {
288        menuBarSave = mb;
289        menuChanged();
290    }
291
292    @Override
293    public Image createImage(int width, int height)
294    {
295        return swingPanel.createImage(width, height);
296    }
297
298    public void addActiveImageListener(ImageJActiveImageListener listener)
299    {
300        listeners.add(listener);
301    }
302
303    public void removeActiveImageListener(ImageJActiveImageListener listener)
304    {
305        listeners.remove(listener);
306    }
307
308    public void fireActiveImageChanged(ImageWindow iw)
309    {
310        for (ImageJActiveImageListener listener : listeners)
311            listener.imageActived(iw);
312    }
313}