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.util.LookAndFeelUtil;
022import icy.gui.util.LookAndFeelUtil.WeakSkinChangeListener;
023import icy.system.IcyExceptionHandler;
024import icy.system.SystemUtil;
025import icy.util.ColorUtil;
026import icy.util.ReflectionUtil;
027
028import java.awt.Color;
029import java.awt.Container;
030import java.awt.Graphics;
031import java.awt.MenuComponent;
032import java.awt.PopupMenu;
033import java.lang.reflect.Field;
034import java.util.Vector;
035
036import javax.swing.BorderFactory;
037import javax.swing.JToolBar;
038import javax.swing.SwingConstants;
039
040import org.pushingpixels.substance.api.skin.SkinChangeListener;
041
042import ij.IJ;
043import ij.gui.Toolbar;
044import ij.plugin.MacroInstaller;
045
046/**
047 * ImageJ ToolBar Wrapper class.
048 * 
049 * @author Stephane
050 */
051public class ToolbarWrapper extends Toolbar
052{
053    private class CustomToolBar extends JToolBar
054    {
055        /**
056         * 
057         */
058        private static final long serialVersionUID = -3278693015639517146L;
059
060        /**
061         * @param orientation
062         */
063        public CustomToolBar(int orientation)
064        {
065            super(orientation);
066
067            setBorder(BorderFactory.createEmptyBorder());
068            setFloatable(false);
069        }
070
071        @Override
072        protected void paintComponent(Graphics g)
073        {
074            ToolbarWrapper.this.paint(g);
075            
076            // try
077            // {
078            // if (drawButtonsMethod != null)
079            // drawButtonsMethod.invoke(ToolbarWrapper.this, g);
080            // }
081            // catch (Exception e)
082            // {
083            // IcyExceptionHandler.showErrorMessage(e, false);
084            // System.err.println("Cannot redraw toolbar buttons from ImageJ.");
085            // }
086        }
087
088        @Override
089        public void removeNotify()
090        {
091            try
092            {
093                // TODO: remove this temporary hack when the "window dispose" bug will be fixed
094                // on the OpenJDK / Sun JVM
095                if (SystemUtil.isUnix())
096                {
097                    @SuppressWarnings("rawtypes")
098                    Vector pp = (Vector) ReflectionUtil.getFieldObject(this, "popups", true);
099                    pp.clear();
100                }
101            }
102            catch (Exception e)
103            {
104                IcyExceptionHandler.showErrorMessage(e, false);
105                System.err.println("Cannot remove toolbar buttons from ImageJ.");
106            }
107
108            super.removeNotify();
109        }
110    }
111
112    /**
113     * 
114     */
115    private static final long serialVersionUID = 6546185720732862969L;
116
117    final CustomToolBar swingComponent;
118
119    private final SkinChangeListener skinChangeListener;
120
121    /**
122     * leaked methods and fields
123     */
124    // Method drawButtonsMethod;
125    Field grayField;
126    Field brighterField;
127    Field darkerField;
128    Field evenDarkerField;
129    Field toolColorField;
130
131    // private Color gray = ImageJ.backgroundColor;
132    // private Color brighter = gray.brighter();
133    // private Color darker = new Color(175, 175, 175);
134    // private Color evenDarker = new Color(110, 110, 110);
135
136    public ToolbarWrapper(ImageJWrapper ijw)
137    {
138        super();
139
140        swingComponent = new CustomToolBar(SwingConstants.HORIZONTAL);
141
142        swingComponent.setMinimumSize(getMinimumSize());
143        swingComponent.setPreferredSize(getPreferredSize());
144        swingComponent.addKeyListener(ijw);
145        swingComponent.addMouseListener(this);
146        swingComponent.addMouseMotionListener(this);
147
148        try
149        {
150            @SuppressWarnings("rawtypes")
151            final Vector popups = (Vector) ((Vector) ReflectionUtil.getFieldObject(this, "popups", true)).clone();
152
153            // transfer all popup from original toolbar to the swing toolbar
154            for (Object obj : popups)
155            {
156                final PopupMenu popup = (PopupMenu) obj;
157
158                super.remove(popup);
159                swingComponent.add(popup);
160            }
161            
162            // get access to private methods
163            // drawButtonsMethod = ReflectionUtil.getMethod(this.getClass(), "drawButtons", true,
164            // Graphics.class);
165            
166            // get access to private fields
167            grayField = ReflectionUtil.getField(this.getClass(), "gray", true);
168            brighterField = ReflectionUtil.getField(this.getClass(), "brighter", true);
169            darkerField = ReflectionUtil.getField(this.getClass(), "darker", true);
170            evenDarkerField = ReflectionUtil.getField(this.getClass(), "evenDarker", true);
171            toolColorField = ReflectionUtil.getField(this.getClass(), "toolColor", true);
172        }
173        catch (Exception e)
174        {
175            IcyExceptionHandler.showErrorMessage(e, false);
176            System.err.println("Cannot restore toolbar buttons from ImageJ.");
177        }
178
179        skinChangeListener = new SkinChangeListener()
180        {
181            @Override
182            public void skinChanged()
183            {
184                Color bgCol = LookAndFeelUtil.getBackground(swingComponent);
185                Color brighterCol;
186                Color darkerCol;
187                Color evenDarkerCol;
188
189                if (ColorUtil.getLuminance(bgCol) < 64)
190                    bgCol = ColorUtil.mix(bgCol, Color.gray);
191
192                brighterCol = ColorUtil.mix(bgCol, Color.white);
193                darkerCol = ColorUtil.mix(bgCol, Color.black);
194                evenDarkerCol = ColorUtil.mix(darkerCol, Color.black);
195
196                if (ColorUtil.getLuminance(bgCol) < 128)
197                    brighterCol = ColorUtil.mix(bgCol, brighterCol);
198                else
199                {
200                    darkerCol = ColorUtil.mix(bgCol, darkerCol);
201                    evenDarkerCol = ColorUtil.mix(darkerCol, evenDarkerCol);
202                }
203
204                try
205                {
206                    if (grayField != null)
207                        grayField.set(ToolbarWrapper.this, bgCol);
208                    if (brighterField != null)
209                        brighterField.set(ToolbarWrapper.this, brighterCol);
210                    if (darkerField != null)
211                        darkerField.set(ToolbarWrapper.this, darkerCol);
212                    if (evenDarkerField != null)
213                        evenDarkerField.set(ToolbarWrapper.this, evenDarkerCol);
214                    if (toolColorField != null)
215                        toolColorField.set(ToolbarWrapper.this, LookAndFeelUtil.getForeground(swingComponent));
216
217                    swingComponent.repaint();
218                }
219                catch (Exception e)
220                {
221                    IcyExceptionHandler.showErrorMessage(e, false);
222                    System.err.println("Cannot hack background color of ImageJ toolbar.");
223                }
224            }
225        };
226
227        // install default tools and macros
228        new MacroInstaller().run(IJ.getDirectory("macros") + "StartupMacros.txt");
229
230        LookAndFeelUtil.addSkinChangeListener(new WeakSkinChangeListener(skinChangeListener));
231    }
232    
233    @Override
234    public Container getParent()
235    {
236        return swingComponent.getParent();
237    }
238
239    /**
240     * @return the swingComponent
241     */
242    public JToolBar getSwingComponent()
243    {
244        return swingComponent;
245    }
246
247    @Override
248    public synchronized void add(PopupMenu popup)
249    {
250        if (swingComponent == null)
251            super.add(popup);
252        else
253        {
254            swingComponent.add(popup);
255            swingComponent.repaint();
256        }
257    }
258
259    @Override
260    public synchronized void remove(MenuComponent popup)
261    {
262        if (swingComponent == null)
263            super.remove(popup);
264        else
265        {
266            swingComponent.remove(popup);
267            swingComponent.repaint();
268        }
269    }
270
271    // @Override
272    // public void itemStateChanged(ItemEvent e)
273    // {
274    // super.itemStateChanged(e);
275    //
276    // swingComponent.repaint();
277    // }
278    //
279    // @Override
280    // public void paint(Graphics g)
281    // {
282    // swingComponent.repaint();
283    // }
284
285    @Override
286    public Graphics getGraphics()
287    {
288        return swingComponent.getGraphics();
289    }
290
291    // /**
292    // * Rebuild swing toolbar component
293    // */
294    // protected void rebuild()
295    // {
296    // swingComponent.removeAll();
297    // swingComponent.validate();
298    // }
299}