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.frame;
020
021import java.awt.AWTEvent;
022import java.awt.Color;
023import java.awt.Component;
024import java.awt.Container;
025import java.awt.Dimension;
026import java.awt.Image;
027import java.awt.LayoutManager;
028import java.awt.Point;
029import java.awt.Rectangle;
030import java.awt.Toolkit;
031import java.awt.event.ActionEvent;
032import java.awt.event.ComponentListener;
033import java.awt.event.KeyEvent;
034import java.awt.event.KeyListener;
035import java.awt.event.WindowEvent;
036import java.awt.event.WindowListener;
037import java.awt.image.ImageObserver;
038import java.beans.PropertyChangeEvent;
039import java.beans.PropertyChangeListener;
040import java.beans.PropertyVetoException;
041import java.util.ArrayList;
042
043import javax.swing.ActionMap;
044import javax.swing.InputMap;
045import javax.swing.JDesktopPane;
046import javax.swing.JFrame;
047import javax.swing.JInternalFrame;
048import javax.swing.JLayeredPane;
049import javax.swing.JMenu;
050import javax.swing.JMenuBar;
051import javax.swing.JPanel;
052import javax.swing.JRootPane;
053import javax.swing.WindowConstants;
054import javax.swing.border.Border;
055import javax.swing.event.EventListenerList;
056import javax.swing.event.InternalFrameEvent;
057import javax.swing.event.InternalFrameListener;
058
059import icy.action.IcyAbstractAction;
060import icy.common.MenuCallback;
061import icy.gui.main.MainFrame;
062import icy.gui.util.ComponentUtil;
063import icy.main.Icy;
064import icy.resource.ResourceUtil;
065import icy.resource.icon.IcyIcon;
066import icy.system.thread.ThreadUtil;
067import icy.util.StringUtil;
068
069/**
070 * This class behave either as a JFrame or a JInternalFrame.<br>
071 * IcyFrame should be 100% AWT safe
072 * 
073 * @author Fabrice de Chaumont & Stephane Dallongeville
074 */
075public class IcyFrame implements InternalFrameListener, WindowListener, ImageObserver, PropertyChangeListener
076{
077    private class SwitchStateAction extends IcyAbstractAction
078    {
079        /**
080         * 
081         */
082        private static final long serialVersionUID = -4433831471426743128L;
083
084        final IcyIcon detachIcon;
085        final IcyIcon attachIcon;
086
087        public SwitchStateAction()
088        {
089            super("");
090
091            detachIcon = new IcyIcon(ResourceUtil.ICON_WINDOW_EXPAND, 20);
092            attachIcon = new IcyIcon(ResourceUtil.ICON_WINDOW_COLLAPSE, 20);
093            setAccelerator(KeyEvent.VK_F3);
094
095            refreshState();
096        }
097
098        @Override
099        public boolean doAction(ActionEvent e)
100        {
101            switchState();
102            return true;
103        }
104
105        void refreshState()
106        {
107            if (isInternalized())
108            {
109                setName("Detach");
110                setIcon(detachIcon);
111                setDescription("Externalize the window");
112            }
113            else
114            {
115                setName("Attach");
116                setIcon(attachIcon);
117                setDescription("Internalize the window");
118            }
119        }
120    }
121
122    /**
123     * list containing all active frames
124     */
125    static ArrayList<IcyFrame> frames = new ArrayList<IcyFrame>();
126
127    /**
128     * Return all active (not closed) IcyFrame
129     */
130    public static ArrayList<IcyFrame> getAllFrames()
131    {
132        synchronized (frames)
133        {
134            return new ArrayList<IcyFrame>(frames);
135        }
136    }
137
138    /**
139     * Return all active IcyFrame which derive from the specified class
140     */
141    public static ArrayList<IcyFrame> getAllFrames(Class<?> frameClass)
142    {
143        final ArrayList<IcyFrame> result = new ArrayList<IcyFrame>();
144
145        if (frameClass != null)
146        {
147            synchronized (frames)
148            {
149                for (IcyFrame frame : frames)
150                    if (frameClass.isInstance(frame))
151                        result.add(frame);
152
153            }
154        }
155
156        return result;
157    }
158
159    /**
160     * Find IcyFrame corresponding to the specified JInternalFrame
161     */
162    public static IcyFrame findIcyFrame(JInternalFrame frame)
163    {
164        synchronized (frames)
165        {
166            for (IcyFrame f : frames)
167                if (f.getInternalFrame() == frame)
168                    return f;
169
170            return null;
171        }
172    }
173
174    public enum IcyFrameState
175    {
176        INTERNALIZED, EXTERNALIZED
177    }
178
179    protected IcyExternalFrame externalFrame;
180    protected IcyInternalFrame internalFrame;
181
182    /**
183     * frame state (internal / external)
184     */
185    protected IcyFrameState state;
186
187    /**
188     * sync flag for AWT thread process
189     */
190    protected boolean syncProcess;
191
192    /**
193     * listeners
194     */
195    protected EventListenerList frameEventListeners;
196
197    /**
198     * internals
199     */
200    protected final MenuCallback defaultSystemMenuCallback;
201    protected SwitchStateAction switchStateAction;
202    protected boolean switchStateItemVisible;
203    protected IcyFrameState previousState;
204
205    public IcyFrame()
206    {
207        this("", false, true, false, false, true);
208    }
209
210    public IcyFrame(String title)
211    {
212        this(title, false, true, false, false, true);
213    }
214
215    public IcyFrame(String title, boolean resizable)
216    {
217        this(title, resizable, true, false, false, true);
218    }
219
220    public IcyFrame(String title, boolean resizable, boolean closable)
221    {
222        this(title, resizable, closable, false, false, true);
223    }
224
225    public IcyFrame(String title, boolean resizable, boolean closable, boolean maximizable)
226    {
227        this(title, resizable, closable, maximizable, false, true);
228    }
229
230    public IcyFrame(final String title, final boolean resizable, final boolean closable, final boolean maximizable,
231            final boolean iconifiable)
232    {
233        this(title, resizable, closable, maximizable, iconifiable, true);
234    }
235
236    public IcyFrame(final String title, final boolean resizable, final boolean closable, final boolean maximizable,
237            final boolean iconifiable, final boolean waitCreate)
238    {
239        super();
240
241        frameEventListeners = new EventListenerList();
242        defaultSystemMenuCallback = new MenuCallback()
243        {
244            @Override
245            public JMenu getMenu()
246            {
247                return getDefaultSystemMenu();
248            }
249        };
250
251        syncProcess = false;
252
253        // set default state
254        if (canBeInternalized())
255            state = IcyFrameState.INTERNALIZED;
256        else
257            state = IcyFrameState.EXTERNALIZED;
258
259        switchStateItemVisible = true;
260        // wanted default state
261        previousState = IcyFrameState.INTERNALIZED;
262
263        // create action after state has been set
264        switchStateAction = new SwitchStateAction();
265        switchStateAction.setEnabled(canBeInternalized());
266
267        ThreadUtil.invoke(new Runnable()
268        {
269            @Override
270            public void run()
271            {
272                externalFrame = createExternalFrame(title);
273                // redirect frame / window events
274                externalFrame.addWindowListener(IcyFrame.this);
275                externalFrame.setLocationRelativeTo(null);
276                externalFrame.setResizable(resizable);
277                externalFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
278                // default size
279                externalFrame.setSize(480, 400);
280
281                internalFrame = createInternalFrame(title, resizable, closable, maximizable, iconifiable);
282                // redirect frame / window events
283                internalFrame.addInternalFrameListener(IcyFrame.this);
284                // default size
285                internalFrame.setSize(480, 400);
286
287                // default system menu callback
288                externalFrame.setSystemMenuCallback(defaultSystemMenuCallback);
289                internalFrame.setSystemMenuCallback(defaultSystemMenuCallback);
290
291                // register to the list
292                synchronized (frames)
293                {
294                    frames.add(IcyFrame.this);
295                }
296            }
297        }, waitCreate);
298
299        final MainFrame mainFrame = Icy.getMainInterface().getMainFrame();
300        // listen main frame mode change
301        if (mainFrame != null)
302            mainFrame.addPropertyChangeListener(MainFrame.PROPERTY_DETACHEDMODE, this);
303    }
304
305    /**
306     * Permit IcyExternalFrame overriding
307     */
308    protected IcyExternalFrame createExternalFrame(String title)
309    {
310        return new IcyExternalFrame(title);
311    }
312
313    /**
314     * Permit IcyInternalFrame overriding
315     */
316    protected IcyInternalFrame createInternalFrame(String title, boolean resizable, boolean closable,
317            boolean maximizable, boolean iconifiable)
318    {
319        return new IcyInternalFrame(title, resizable, closable, maximizable, iconifiable);
320    }
321
322    /**
323     * Return true if the frame can be internalized
324     */
325    protected boolean canBeInternalized()
326    {
327        final MainFrame frame = Icy.getMainInterface().getMainFrame();
328
329        // internalization possible only in single window mode
330        if (frame != null)
331            return !frame.isDetachedMode();
332
333        return false;
334    }
335
336    /**
337     * Refresh system menu
338     */
339    public void updateSystemMenu()
340    {
341        // AWT safe
342        ThreadUtil.invoke(new Runnable()
343        {
344            @Override
345            public void run()
346            {
347                if (isInternalized())
348                    internalFrame.updateSystemMenu();
349                else
350                    externalFrame.updateSystemMenu();
351            }
352        }, syncProcess);
353    }
354
355    /**
356     * Close frame (send closing event)
357     */
358    public void close()
359    {
360        // AWT safe
361        ThreadUtil.invoke(new Runnable()
362        {
363            @Override
364            public void run()
365            {
366                internalFrame.close(true);
367                externalFrame.close();
368            }
369        }, syncProcess);
370    }
371
372    /**
373     * Dispose frame (send closed event)
374     */
375    public void dispose()
376    {
377        // AWT safe
378        ThreadUtil.invoke(new Runnable()
379        {
380            @Override
381            public void run()
382            {
383                if (isInternalized())
384                    internalFrame.dispose();
385                else
386                    externalFrame.dispose();
387            }
388        }, syncProcess);
389    }
390
391    /** go from detached to attached and opposite */
392    public void switchState()
393    {
394        if (isInternalized())
395            detach();
396        else
397            attach();
398    }
399
400    /** set the frame to be an inner frame on the desktop pane */
401    public void internalize()
402    {
403        if (isExternalized())
404            attach();
405    }
406
407    /** the frame becomes detached in an independent frame */
408    public void externalize()
409    {
410        if (isInternalized())
411            detach();
412    }
413
414    /** Set the frame to be an inner frame on the desktop pane */
415    public void attach()
416    {
417        if (isInternalized() || !canBeInternalized())
418            return;
419
420        // AWT safe
421        ThreadUtil.invoke(new Runnable()
422        {
423            @Override
424            public void run()
425            {
426                // save current visible state
427                final boolean visible = externalFrame.isVisible();
428
429                // hide external frame
430                if (visible)
431                    externalFrame.setVisible(false);
432
433                final JMenuBar menuBar = externalFrame.getJMenuBar();
434                final Container content = externalFrame.getContentPane();
435
436                // remove components from external frame
437                externalFrame.setJMenuBar(null);
438                externalFrame.setContentPane(new JPanel());
439                externalFrame.validate();
440
441                internalFrame.setJMenuBar(menuBar);
442                internalFrame.setContentPane(content);
443                internalFrame.validate();
444
445                // show internal frame
446                if (visible)
447                {
448                    internalFrame.setVisible(true);
449                    try
450                    {
451                        internalFrame.setSelected(true);
452                    }
453                    catch (PropertyVetoException e)
454                    {
455                        // ignore
456                    }
457                }
458
459                state = IcyFrameState.INTERNALIZED;
460
461                // notify state change
462                stateChanged();
463            }
464        }, syncProcess);
465    }
466
467    /** Set the frame to be detached in an independent frame */
468    public void detach()
469    {
470        if (isExternalized())
471            return;
472
473        // AWT safe
474        ThreadUtil.invoke(new Runnable()
475        {
476            @Override
477            public void run()
478            {
479                // save current visible state
480                final boolean visible = internalFrame.isVisible();
481
482                // hide internal frame
483                if (visible)
484                    internalFrame.setVisible(false);
485
486                final JMenuBar menuBar = internalFrame.getJMenuBar();
487                final Container content = internalFrame.getContentPane();
488
489                // remove components from internal frame
490                internalFrame.setJMenuBar(null);
491                internalFrame.setContentPane(new JPanel());
492                internalFrame.validate();
493
494                externalFrame.setJMenuBar(menuBar);
495                externalFrame.setContentPane(content);
496                externalFrame.validate();
497
498                // show external frame
499                if (visible)
500                {
501                    externalFrame.setVisible(true);
502                    externalFrame.requestFocus();
503                }
504
505                // TODO : we have to force a refresh with resizing or we get a refresh bug on
506                // scrollbar (OSX only ?)
507                // externalFrame.setSize(externalFrame.getWidth(), externalFrame.getHeight() - 1);
508                // externalFrame.setSize(externalFrame.getWidth(), externalFrame.getHeight() + 1);
509
510                state = IcyFrameState.EXTERNALIZED;
511
512                // notify state change
513                stateChanged();
514            }
515        }, syncProcess);
516    }
517
518    /**
519     * Called on state (internalized / externalized) change
520     */
521    public void stateChanged()
522    {
523        // refresh switch action state
524        switchStateAction.refreshState();
525
526        // refresh system menu
527        updateSystemMenu();
528
529        // fire event
530        if (isInternalized())
531            fireFrameInternalized(new IcyFrameEvent(IcyFrame.this, null, null));
532        else
533            fireFrameExternalized(new IcyFrameEvent(IcyFrame.this, null, null));
534    }
535
536    /** Center frame on the desktop */
537    public void center()
538    {
539        // AWT safe
540        ThreadUtil.invoke(new Runnable()
541        {
542            @Override
543            public void run()
544            {
545                if (isInternalized())
546                    ComponentUtil.center(internalFrame);
547                else
548                    ComponentUtil.center(externalFrame);
549
550            }
551        }, syncProcess);
552    }
553
554    /**
555     * Add to the container c
556     */
557    public void addTo(final Container c)
558    {
559        if (isInternalized())
560        {
561            // AWT safe
562            ThreadUtil.invoke(new Runnable()
563            {
564                @Override
565                public void run()
566                {
567                    c.add(internalFrame);
568                }
569            }, syncProcess);
570        }
571    }
572
573    /**
574     * Add to the container c
575     */
576    public void addTo(final Container c, final int index)
577    {
578        if (isInternalized())
579        {
580            // AWT safe
581            ThreadUtil.invoke(new Runnable()
582            {
583                @Override
584                public void run()
585                {
586                    c.add(internalFrame, index);
587                }
588            }, syncProcess);
589        }
590    }
591
592    /**
593     * @deprecated Use {@link #addToDesktopPane()} instead.
594     */
595    @Deprecated
596    public void addTo(final Container c, final Object constraints)
597    {
598        // AWT safe
599        ThreadUtil.invoke(new Runnable()
600        {
601            @Override
602            public void run()
603            {
604                c.add(internalFrame, constraints);
605            }
606        }, syncProcess);
607    }
608
609    /**
610     * Add the frame to the Icy desktop pane with specified constraint.
611     */
612    public void addToDesktopPane(final Object constraints)
613    {
614        // AWT safe
615        ThreadUtil.invoke(new Runnable()
616        {
617            @Override
618            public void run()
619            {
620                final JDesktopPane desktop = Icy.getMainInterface().getDesktopPane();
621
622                if (desktop != null)
623                    desktop.add(internalFrame, constraints);
624            }
625        }, syncProcess);
626    }
627
628    /**
629     * Add the frame to the Icy desktop pane
630     */
631    public void addToDesktopPane()
632    {
633        addToDesktopPane(JLayeredPane.DEFAULT_LAYER);
634    }
635
636    /**
637     * @deprecated Use {@link #addToDesktopPane()} instead.
638     */
639    @Deprecated
640    public void addToMainDesktopPane()
641    {
642        addToDesktopPane();
643    }
644
645    /**
646     * Implement add method
647     */
648    public void add(final Component comp)
649    {
650        // AWT safe
651        ThreadUtil.invoke(new Runnable()
652        {
653            @Override
654            public void run()
655            {
656                if (isInternalized())
657                    internalFrame.add(comp);
658                else
659                    externalFrame.add(comp);
660            }
661        }, syncProcess);
662    }
663
664    /**
665     * Implement add method
666     */
667    public void add(final Component comp, final Object constraints)
668    {
669        // AWT safe
670        ThreadUtil.invoke(new Runnable()
671        {
672            @Override
673            public void run()
674            {
675                if (isInternalized())
676                    internalFrame.add(comp, constraints);
677                else
678                    externalFrame.add(comp, constraints);
679            }
680        }, syncProcess);
681    }
682
683    /**
684     * Implement add method
685     */
686    public void add(final String name, final Component comp)
687    {
688        // AWT safe
689        ThreadUtil.invoke(new Runnable()
690        {
691            @Override
692            public void run()
693            {
694                if (isInternalized())
695                    internalFrame.add(name, comp);
696                else
697                    externalFrame.add(name, comp);
698            }
699        }, syncProcess);
700    }
701
702    /**
703     * Remove from the container
704     */
705    public void removeFrom(final Container c)
706    {
707        // AWT safe
708        ThreadUtil.invoke(new Runnable()
709        {
710            @Override
711            public void run()
712            {
713                c.remove(internalFrame);
714            }
715        }, syncProcess);
716    }
717
718    /**
719     * Implement removeAll method
720     */
721    public void removeAll()
722    {
723        // AWT safe
724        ThreadUtil.invoke(new Runnable()
725        {
726            @Override
727            public void run()
728            {
729                if (isInternalized())
730                    internalFrame.removeAll();
731                else
732                    externalFrame.removeAll();
733            }
734        }, syncProcess);
735    }
736
737    /**
738     * Implement remove method
739     */
740    public void remove(final Component comp)
741    {
742        // AWT safe
743        ThreadUtil.invoke(new Runnable()
744        {
745            @Override
746            public void run()
747            {
748                if (isInternalized())
749                    internalFrame.remove(comp);
750                else
751                    externalFrame.remove(comp);
752            }
753        }, syncProcess);
754    }
755
756    /**
757     * Remove the frame from the main pane of ICY
758     */
759    public void removeFromMainDesktopPane()
760    {
761        removeFrom(Icy.getMainInterface().getDesktopPane());
762    }
763
764    /**
765     * Implement toFront method
766     */
767    public void toFront()
768    {
769        // AWT safe
770        ThreadUtil.invoke(new Runnable()
771        {
772            @Override
773            public void run()
774            {
775                if (isInternalized())
776                    internalFrame.toFront();
777                else
778                    externalFrame.toFront();
779            }
780        }, syncProcess);
781    }
782
783    /**
784     * Implement toBack method
785     */
786    public void toBack()
787    {
788        // AWT safe
789        ThreadUtil.invoke(new Runnable()
790        {
791            @Override
792            public void run()
793            {
794                if (isInternalized())
795                    internalFrame.toBack();
796                else
797                    externalFrame.toBack();
798            }
799        }, syncProcess);
800    }
801
802    /**
803     * Implement pack method
804     */
805    public void pack()
806    {
807        // AWT safe
808        ThreadUtil.invoke(new Runnable()
809        {
810            @Override
811            public void run()
812            {
813                if (isInternalized())
814                    internalFrame.pack();
815                else
816                    externalFrame.pack();
817            }
818        }, syncProcess);
819    }
820
821    public Container getFrame()
822    {
823        if (isInternalized())
824            return internalFrame;
825
826        return externalFrame;
827    }
828
829    public IcyInternalFrame getIcyInternalFrame()
830    {
831        return internalFrame;
832    }
833
834    public IcyExternalFrame getIcyExternalFrame()
835    {
836        return externalFrame;
837    }
838
839    public JInternalFrame getInternalFrame()
840    {
841        return internalFrame;
842    }
843
844    public JFrame getExternalFrame()
845    {
846        return externalFrame;
847    }
848
849    /**
850     * Indicate if system menu show display item to switch frame state (internal / external)
851     */
852    public void setSwitchStateItemVisible(boolean value)
853    {
854        if (switchStateItemVisible != value)
855        {
856            switchStateItemVisible = value;
857            switchStateAction.setEnabled(value);
858            updateSystemMenu();
859        }
860    }
861
862    /**
863     * @return the systemMenuCallback
864     */
865    public MenuCallback getSystemMenuCallback()
866    {
867        // always have same callback on each frame
868        final MenuCallback result = internalFrame.getSystemMenuCallback();
869
870        // default callback ? this means we set it to null
871        if (result == defaultSystemMenuCallback)
872            return null;
873
874        return result;
875    }
876
877    /**
878     * Set the system menu callback (this allow modification of system menu)
879     * 
880     * @param value
881     *        the systemMenuCallback to set
882     */
883    public void setSystemMenuCallback(MenuCallback value)
884    {
885        if (value != null)
886        {
887            internalFrame.setSystemMenuCallback(value);
888            externalFrame.setSystemMenuCallback(value);
889        }
890        else
891        {
892            internalFrame.setSystemMenuCallback(defaultSystemMenuCallback);
893            externalFrame.setSystemMenuCallback(defaultSystemMenuCallback);
894        }
895    }
896
897    /**
898     * Return the default system menu
899     */
900    public JMenu getDefaultSystemMenu()
901    {
902        final JMenu result;
903
904        if (isInternalized())
905            result = internalFrame.getDefaultSystemMenu();
906        else
907            result = externalFrame.getDefaultSystemMenu();
908
909        if (switchStateItemVisible)
910        {
911            result.insert(switchStateAction, 0);
912            if (result.getMenuComponentCount() > 1)
913                result.insertSeparator(1);
914        }
915
916        return result;
917    }
918
919    /**
920     * Implement getParent
921     */
922    public Container getParent()
923    {
924        if (isInternalized())
925            return internalFrame.getParent();
926
927        return externalFrame.getParent();
928    }
929
930    /**
931     * Implement getContentPane method
932     */
933    public Container getContentPane()
934    {
935        if (isInternalized())
936            return internalFrame.getContentPane();
937
938        return externalFrame.getContentPane();
939    }
940
941    /**
942     * Implement getRootPane method
943     */
944    public JRootPane getRootPane()
945    {
946        if (isInternalized())
947            return internalFrame.getRootPane();
948
949        return externalFrame.getRootPane();
950    }
951
952    public Border getBorder()
953    {
954        if (isInternalized())
955            return internalFrame.getBorder();
956
957        return null;
958    }
959
960    /**
961     * @return the switchStateAction
962     */
963    public SwitchStateAction getSwitchStateAction()
964    {
965        return switchStateAction;
966    }
967
968    /**
969     * Implement getMinimumSize method
970     */
971    public Dimension getMinimumSize()
972    {
973        if (isInternalized())
974            return internalFrame.getMinimumSize();
975
976        return externalFrame.getMinimumSize();
977    }
978
979    /**
980     * Implement getMinimumSize method for internal frame only
981     */
982    public Dimension getMinimumSizeInternal()
983    {
984        return internalFrame.getMinimumSize();
985    }
986
987    /**
988     * Implement getMinimumSize method for external frame only
989     */
990    public Dimension getMinimumSizeExternal()
991    {
992        return externalFrame.getMinimumSize();
993    }
994
995    /**
996     * Implement getMaximumSize method
997     */
998    public Dimension getMaximumSize()
999    {
1000        if (isInternalized())
1001            return internalFrame.getMaximumSize();
1002
1003        return externalFrame.getMaximumSize();
1004    }
1005
1006    /**
1007     * Implement getMaximumSize method for internal frame only
1008     */
1009    public Dimension getMaximumSizeInternal()
1010    {
1011        return internalFrame.getMaximumSize();
1012    }
1013
1014    /**
1015     * Implement getMaximumSize method for external frame only
1016     */
1017    public Dimension getMaximumSizeExternal()
1018    {
1019        return externalFrame.getMaximumSize();
1020    }
1021
1022    /**
1023     * Implement getPreferredSize method
1024     */
1025    public Dimension getPreferredSize()
1026    {
1027        if (isInternalized())
1028            return internalFrame.getPreferredSize();
1029
1030        return externalFrame.getPreferredSize();
1031    }
1032
1033    /**
1034     * Implement getPreferredSize method for internal frame only
1035     */
1036    public Dimension getPreferredSizeInternal()
1037    {
1038        return internalFrame.getPreferredSize();
1039    }
1040
1041    /**
1042     * Implement getPreferredSize method for external frame only
1043     */
1044    public Dimension getPreferredSizeExternal()
1045    {
1046        return externalFrame.getPreferredSize();
1047    }
1048
1049    /**
1050     * Implement getSize method
1051     */
1052    public Dimension getSize()
1053    {
1054        if (isInternalized())
1055            return internalFrame.getSize();
1056
1057        return externalFrame.getSize();
1058    }
1059
1060    /**
1061     * Implement getSize method for internal frame only
1062     */
1063    public Dimension getSizeInternal()
1064    {
1065        return internalFrame.getSize();
1066    }
1067
1068    /**
1069     * Implement getSize method for external frame only
1070     */
1071    public Dimension getSizeExternal()
1072    {
1073        return externalFrame.getSize();
1074    }
1075
1076    /**
1077     * Implement getHeight method
1078     */
1079    public int getHeight()
1080    {
1081        if (isInternalized())
1082            return internalFrame.getHeight();
1083
1084        return externalFrame.getHeight();
1085    }
1086
1087    /**
1088     * Implement getHeight method for internal frame only
1089     */
1090    public int getHeightInternal()
1091    {
1092        return internalFrame.getHeight();
1093    }
1094
1095    /**
1096     * Implement getHeight method for external frame only
1097     */
1098    public int getHeightExternal()
1099    {
1100        return externalFrame.getHeight();
1101    }
1102
1103    /**
1104     * Implement getWidth method
1105     */
1106    public int getWidth()
1107    {
1108        if (isInternalized())
1109            return internalFrame.getWidth();
1110
1111        return externalFrame.getWidth();
1112    }
1113
1114    /**
1115     * Implement getWidth method for internal frame only
1116     */
1117    public int getWidthInternal()
1118    {
1119        return internalFrame.getWidth();
1120    }
1121
1122    /**
1123     * Implement getWidth method for external frame only
1124     */
1125    public int getWidthExternal()
1126    {
1127        return externalFrame.getWidth();
1128    }
1129
1130    /**
1131     * Implement getX method
1132     */
1133    public int getX()
1134    {
1135        if (isInternalized())
1136            return internalFrame.getX();
1137
1138        return externalFrame.getX();
1139    }
1140
1141    /**
1142     * Implement getX method for internal frame only
1143     */
1144    public int getXInternal()
1145    {
1146        return internalFrame.getX();
1147    }
1148
1149    /**
1150     * Implement getX method for external frame only
1151     */
1152    public int getXExternal()
1153    {
1154        return externalFrame.getX();
1155    }
1156
1157    /**
1158     * Implement getY method
1159     */
1160    public int getY()
1161    {
1162        if (isInternalized())
1163            return internalFrame.getY();
1164
1165        return externalFrame.getY();
1166    }
1167
1168    /**
1169     * Implement getY method for internal frame only
1170     */
1171    public int getYInternal()
1172    {
1173        return internalFrame.getY();
1174    }
1175
1176    /**
1177     * Implement getY method for external frame only
1178     */
1179    public int getYExternal()
1180    {
1181        return externalFrame.getY();
1182    }
1183
1184    /**
1185     * Implement getLocation method
1186     */
1187    public Point getLocation()
1188    {
1189        if (isInternalized())
1190            return internalFrame.getLocation();
1191
1192        return externalFrame.getLocation();
1193    }
1194
1195    /**
1196     * Implement getLocation method
1197     */
1198    public Point getLocationInternal()
1199    {
1200        return internalFrame.getLocation();
1201    }
1202
1203    /**
1204     * Implement getLocation method for external frame only
1205     */
1206    public Point getLocationExternal()
1207    {
1208        return externalFrame.getLocation();
1209    }
1210
1211    /**
1212     * Implement getBounds method
1213     */
1214    public Rectangle getBounds()
1215    {
1216        if (isInternalized())
1217            return internalFrame.getBounds();
1218
1219        return externalFrame.getBounds();
1220    }
1221
1222    /**
1223     * Implement getBounds method for internal frame only
1224     */
1225    public Rectangle getBoundsInternal()
1226    {
1227        return internalFrame.getBounds();
1228    }
1229
1230    /**
1231     * Implement getBounds method for external frame only
1232     */
1233    public Rectangle getBoundsExternal()
1234    {
1235        return externalFrame.getBounds();
1236    }
1237
1238    /**
1239     * Implement getBounds method for external frame only
1240     */
1241    public Rectangle getVisibleRect()
1242    {
1243        if (isInternalized())
1244            return internalFrame.getVisibleRect();
1245
1246        // not supported on external frame
1247        if (externalFrame.isVisible())
1248            return externalFrame.getBounds();
1249
1250        return new Rectangle();
1251    }
1252
1253    /**
1254     * Implement getJMenuBar method
1255     */
1256    public JMenuBar getJMenuBar()
1257    {
1258        if (isInternalized())
1259            return internalFrame.getJMenuBar();
1260
1261        return externalFrame.getJMenuBar();
1262    }
1263
1264    /**
1265     * Returns the content pane InputMap
1266     */
1267    public InputMap getInputMap(int condition)
1268    {
1269        if (isInternalized())
1270            return ((JPanel) internalFrame.getContentPane()).getInputMap(condition);
1271
1272        return ((JPanel) externalFrame.getContentPane()).getInputMap(condition);
1273    }
1274
1275    /**
1276     * Returns the content pane InputMap
1277     */
1278    public ActionMap getActionMap()
1279    {
1280        if (isInternalized())
1281            return ((JPanel) internalFrame.getContentPane()).getActionMap();
1282
1283        return ((JPanel) externalFrame.getContentPane()).getActionMap();
1284    }
1285
1286    /**
1287     * Implement getToolkit method
1288     */
1289    public Toolkit getToolkit()
1290    {
1291        if (isInternalized())
1292            return internalFrame.getToolkit();
1293
1294        return externalFrame.getToolkit();
1295    }
1296
1297    /**
1298     * Implement setTitle method
1299     */
1300    public String getTitle()
1301    {
1302        if (isInternalized())
1303            return internalFrame.getTitle();
1304
1305        return externalFrame.getTitle();
1306    }
1307
1308    /**
1309     * Return true if title bar is visible
1310     */
1311    public boolean getTitleBarVisible()
1312    {
1313        if (isInternalized())
1314            return internalFrame.isTitleBarVisible();
1315
1316        return externalFrame.isTitleBarVisible();
1317    }
1318
1319    /**
1320     * @return the displaySwitchStateItem
1321     */
1322    public boolean isSwitchStateItemVisible()
1323    {
1324        return switchStateItemVisible;
1325    }
1326
1327    /**
1328     * Implement getMousePosition method
1329     */
1330    public Point getMousePosition()
1331    {
1332        if (isInternalized())
1333            return internalFrame.getMousePosition();
1334
1335        return externalFrame.getMousePosition();
1336    }
1337
1338    /**
1339     * Implement isMinimized method
1340     */
1341    public boolean isMinimized()
1342    {
1343        if (isInternalized())
1344            return internalFrame.isIcon();
1345
1346        return ComponentUtil.isMinimized(externalFrame);
1347    }
1348
1349    /**
1350     * Implement isMinimized method for internal frame only
1351     */
1352    public boolean isMinimizedInternal()
1353    {
1354        return internalFrame.isIcon();
1355    }
1356
1357    /**
1358     * Implement isMinimized method for external frame only
1359     */
1360    public boolean isMinimizedExternal()
1361    {
1362        return ComponentUtil.isMinimized(externalFrame);
1363    }
1364
1365    /**
1366     * Implement isMaximized method
1367     */
1368    public boolean isMaximized()
1369    {
1370        if (isInternalized())
1371            return internalFrame.isMaximum();
1372
1373        return ComponentUtil.isMaximized(externalFrame);
1374    }
1375
1376    /**
1377     * Implement isMaximized method for internal frame only
1378     */
1379    public boolean isMaximizedInternal()
1380    {
1381        return internalFrame.isMaximum();
1382    }
1383
1384    /**
1385     * Implement isMaximized method for external frame only
1386     */
1387    public boolean isMaximizedExternal()
1388    {
1389        return ComponentUtil.isMaximized(externalFrame);
1390    }
1391
1392    /**
1393     * Implement isVisible method
1394     */
1395    public boolean isVisible()
1396    {
1397        if (isInternalized())
1398            return internalFrame.isVisible();
1399
1400        return externalFrame.isVisible();
1401    }
1402
1403    /**
1404     * Implement isResizable method
1405     */
1406    public boolean isResizable()
1407    {
1408        if (isInternalized())
1409            return internalFrame.isResizable();
1410
1411        return externalFrame.isResizable();
1412    }
1413
1414    /**
1415     * Implement isClosable method
1416     */
1417    public boolean isClosable()
1418    {
1419        if (isInternalized())
1420            return internalFrame.isClosable();
1421
1422        // external frame is always closable
1423        return true;
1424    }
1425
1426    /**
1427     * return true if frame is in internalized state
1428     */
1429    public boolean isInternalized()
1430    {
1431        return (state == IcyFrameState.INTERNALIZED);
1432    }
1433
1434    /**
1435     * return true if frame is in externalized state
1436     */
1437    public boolean isExternalized()
1438    {
1439        return (state == IcyFrameState.EXTERNALIZED);
1440    }
1441
1442    /**
1443     * return true if frame is active
1444     */
1445    public boolean isActive()
1446    {
1447        if (isInternalized())
1448            return internalFrame.isSelected();
1449
1450        return externalFrame.isActive();
1451    }
1452
1453    /**
1454     * Implement isAlwaysOnTop method (only for externalized frame)
1455     */
1456    public boolean isAlwaysOnTop()
1457    {
1458        return externalFrame.isAlwaysOnTop();
1459    }
1460
1461    /**
1462     * Implement hasFocus method
1463     */
1464    public boolean hasFocus()
1465    {
1466        if (isInternalized())
1467            return internalFrame.hasFocus();
1468
1469        return externalFrame.hasFocus();
1470    }
1471
1472    /**
1473     * Implement setTitle method
1474     */
1475    public void setTitle(final String title)
1476    {
1477        // AWT safe
1478        ThreadUtil.invoke(new Runnable()
1479        {
1480            @Override
1481            public void run()
1482            {
1483                internalFrame.setTitle(title);
1484                externalFrame.setTitle(title);
1485            }
1486        }, syncProcess);
1487    }
1488
1489    /**
1490     * Implement setToolTipText method (only for internalized frame)
1491     */
1492    public void setToolTipText(final String text)
1493    {
1494        // AWT safe
1495        ThreadUtil.invoke(new Runnable()
1496        {
1497            @Override
1498            public void run()
1499            {
1500                // only internal frame support it
1501                internalFrame.setToolTipText(text);
1502                // externalFrame.setToolTipText(text);
1503            }
1504        }, syncProcess);
1505    }
1506
1507    /**
1508     * Implement setBackground method
1509     */
1510    public void setBackground(final Color value)
1511    {
1512        // AWT safe
1513        ThreadUtil.invoke(new Runnable()
1514        {
1515            @Override
1516            public void run()
1517            {
1518                internalFrame.setBackground(value);
1519                externalFrame.setBackground(value);
1520            }
1521        }, syncProcess);
1522    }
1523
1524    /**
1525     * Implement setForeground method
1526     */
1527    public void setForeground(final Color value)
1528    {
1529        // AWT safe
1530        ThreadUtil.invoke(new Runnable()
1531        {
1532            @Override
1533            public void run()
1534            {
1535                internalFrame.setForeground(value);
1536                externalFrame.setForeground(value);
1537            }
1538        }, syncProcess);
1539    }
1540
1541    /**
1542     * Implement setResizable method
1543     */
1544    public void setResizable(final boolean value)
1545    {
1546        // AWT safe
1547        ThreadUtil.invoke(new Runnable()
1548        {
1549            @Override
1550            public void run()
1551            {
1552                internalFrame.setResizable(value);
1553                externalFrame.setResizable(value);
1554            }
1555        }, syncProcess);
1556
1557    }
1558
1559    /**
1560     * Implement setLocation method
1561     */
1562    public void setLocation(final Point p)
1563    {
1564        // AWT safe
1565        ThreadUtil.invoke(new Runnable()
1566        {
1567            @Override
1568            public void run()
1569            {
1570                if (isInternalized())
1571                    internalFrame.setLocation(p);
1572                else
1573                    externalFrame.setLocation(p);
1574            }
1575        }, syncProcess);
1576    }
1577
1578    /**
1579     * Implement setLocation method
1580     */
1581    public void setLocation(final int x, final int y)
1582    {
1583        // AWT safe
1584        ThreadUtil.invoke(new Runnable()
1585        {
1586            @Override
1587            public void run()
1588            {
1589                if (isInternalized())
1590                    internalFrame.setLocation(x, y);
1591                else
1592                    externalFrame.setLocation(x, y);
1593            }
1594        }, syncProcess);
1595    }
1596
1597    /**
1598     * Implement setLocation method for internal frame only
1599     */
1600    public void setLocationInternal(final Point p)
1601    {
1602        // AWT safe
1603        ThreadUtil.invoke(new Runnable()
1604        {
1605            @Override
1606            public void run()
1607            {
1608                internalFrame.setLocation(p);
1609            }
1610        }, syncProcess);
1611    }
1612
1613    /**
1614     * Implement setLocation method for internal frame only
1615     */
1616    public void setLocationInternal(final int x, final int y)
1617    {
1618        // AWT safe
1619        ThreadUtil.invoke(new Runnable()
1620        {
1621            @Override
1622            public void run()
1623            {
1624                internalFrame.setLocation(x, y);
1625            }
1626        }, syncProcess);
1627    }
1628
1629    /**
1630     * Implement setLocation method for external frame only
1631     */
1632    public void setLocationExternal(final Point p)
1633    {
1634        // AWT safe
1635        ThreadUtil.invoke(new Runnable()
1636        {
1637            @Override
1638            public void run()
1639            {
1640                externalFrame.setLocation(p);
1641            }
1642        }, syncProcess);
1643    }
1644
1645    /**
1646     * Implement setLocation method for external frame only
1647     */
1648    public void setLocationExternal(final int x, final int y)
1649    {
1650        // AWT safe
1651        ThreadUtil.invoke(new Runnable()
1652        {
1653            @Override
1654            public void run()
1655            {
1656                externalFrame.setLocation(x, y);
1657            }
1658        }, syncProcess);
1659    }
1660
1661    /**
1662     * Implement setSize method
1663     */
1664    public void setSize(final Dimension d)
1665    {
1666        // AWT safe
1667        ThreadUtil.invoke(new Runnable()
1668        {
1669            @Override
1670            public void run()
1671            {
1672                if (isInternalized())
1673                    internalFrame.setSize(d);
1674                else
1675                    externalFrame.setSize(d);
1676            }
1677        }, syncProcess);
1678    }
1679
1680    /**
1681     * Implement setSize method
1682     */
1683    public void setSize(final int width, final int height)
1684    {
1685        // AWT safe
1686        ThreadUtil.invoke(new Runnable()
1687        {
1688            @Override
1689            public void run()
1690            {
1691                if (isInternalized())
1692                    internalFrame.setSize(width, height);
1693                else
1694                    externalFrame.setSize(width, height);
1695            }
1696        }, syncProcess);
1697    }
1698
1699    /**
1700     * Implement setSize method for internal frame only
1701     */
1702    public void setSizeInternal(final Dimension d)
1703    {
1704        // AWT safe
1705        ThreadUtil.invoke(new Runnable()
1706        {
1707            @Override
1708            public void run()
1709            {
1710                internalFrame.setSize(d);
1711            }
1712        }, syncProcess);
1713    }
1714
1715    /**
1716     * Implement setSize method for internal frame only
1717     */
1718    public void setSizeInternal(final int width, final int height)
1719    {
1720        // AWT safe
1721        ThreadUtil.invoke(new Runnable()
1722        {
1723            @Override
1724            public void run()
1725            {
1726                internalFrame.setSize(width, height);
1727            }
1728        }, syncProcess);
1729    }
1730
1731    /**
1732     * Implement setSize method for external frame only
1733     */
1734    public void setSizeExternal(final Dimension d)
1735    {
1736        // AWT safe
1737        ThreadUtil.invoke(new Runnable()
1738        {
1739            @Override
1740            public void run()
1741            {
1742                externalFrame.setSize(d);
1743            }
1744        }, syncProcess);
1745    }
1746
1747    /**
1748     * Implement setSize method for external frame only
1749     */
1750    public void setSizeExternal(final int width, final int height)
1751    {
1752        // AWT safe
1753        ThreadUtil.invoke(new Runnable()
1754        {
1755            @Override
1756            public void run()
1757            {
1758                externalFrame.setSize(width, height);
1759            }
1760        }, syncProcess);
1761    }
1762
1763    /**
1764     * Implement setPreferredSize method
1765     */
1766    public void setPreferredSize(final Dimension d)
1767    {
1768        // AWT safe
1769        ThreadUtil.invoke(new Runnable()
1770        {
1771            @Override
1772            public void run()
1773            {
1774                if (isInternalized())
1775                    internalFrame.setPreferredSize(d);
1776                else
1777                    externalFrame.setPreferredSize(d);
1778            }
1779        }, syncProcess);
1780    }
1781
1782    /**
1783     * Implement setPreferredSize method for internal frame only
1784     */
1785    public void setPreferredSizeInternal(final Dimension d)
1786    {
1787        // AWT safe
1788        ThreadUtil.invoke(new Runnable()
1789        {
1790            @Override
1791            public void run()
1792            {
1793                internalFrame.setPreferredSize(d);
1794            }
1795        }, syncProcess);
1796    }
1797
1798    /**
1799     * Implement setPreferredSize method for external frame only
1800     */
1801    public void setPreferredSizeExternal(final Dimension d)
1802    {
1803        // AWT safe
1804        ThreadUtil.invoke(new Runnable()
1805        {
1806            @Override
1807            public void run()
1808            {
1809                externalFrame.setPreferredSize(d);
1810            }
1811        }, syncProcess);
1812    }
1813
1814    /**
1815     * Implement setMinimumSize method
1816     */
1817    public void setMinimumSize(final Dimension d)
1818    {
1819        // AWT safe
1820        ThreadUtil.invoke(new Runnable()
1821        {
1822            @Override
1823            public void run()
1824            {
1825                if (isInternalized())
1826                    internalFrame.setMinimumSize(d);
1827                else
1828                    externalFrame.setMinimumSize(d);
1829            }
1830        }, syncProcess);
1831    }
1832
1833    /**
1834     * Implement setMaximumSize method
1835     */
1836    public void setMaximumSize(final Dimension d)
1837    {
1838        // AWT safe
1839        ThreadUtil.invoke(new Runnable()
1840        {
1841            @Override
1842            public void run()
1843            {
1844                if (isInternalized())
1845                    internalFrame.setMaximumSize(d);
1846                else
1847                    externalFrame.setMaximumSize(d);
1848            }
1849        }, syncProcess);
1850    }
1851
1852    /**
1853     * Implement setMinimumSize method for internal frame only
1854     */
1855    public void setMinimumSizeInternal(final Dimension d)
1856    {
1857        // AWT safe
1858        ThreadUtil.invoke(new Runnable()
1859        {
1860            @Override
1861            public void run()
1862            {
1863                internalFrame.setMinimumSize(d);
1864            }
1865        }, syncProcess);
1866    }
1867
1868    /**
1869     * Implement setMaximumSize method for internal frame only
1870     */
1871    public void setMaximumSizeInternal(final Dimension d)
1872    {
1873        // AWT safe
1874        ThreadUtil.invoke(new Runnable()
1875        {
1876            @Override
1877            public void run()
1878            {
1879                internalFrame.setMaximumSize(d);
1880            }
1881        }, syncProcess);
1882    }
1883
1884    /**
1885     * Implement setMinimumSize method for external frame only
1886     */
1887    public void setMinimumSizeExternal(final Dimension d)
1888    {
1889        // AWT safe
1890        ThreadUtil.invoke(new Runnable()
1891        {
1892            @Override
1893            public void run()
1894            {
1895                externalFrame.setMinimumSize(d);
1896            }
1897        }, syncProcess);
1898    }
1899
1900    /**
1901     * Implement setMaximumSize method for external frame only
1902     */
1903    public void setMaximumSizeExternal(final Dimension d)
1904    {
1905        // AWT safe
1906        ThreadUtil.invoke(new Runnable()
1907        {
1908            @Override
1909            public void run()
1910            {
1911                externalFrame.setMaximumSize(d);
1912            }
1913        }, syncProcess);
1914    }
1915
1916    /**
1917     * Implement setBounds method
1918     */
1919    public void setBounds(final Rectangle r)
1920    {
1921        // AWT safe
1922        ThreadUtil.invoke(new Runnable()
1923        {
1924            @Override
1925            public void run()
1926            {
1927                if (isInternalized())
1928                    internalFrame.setBounds(r);
1929                else
1930                    externalFrame.setBounds(r);
1931            }
1932        }, syncProcess);
1933
1934    }
1935
1936    /**
1937     * Implement setMaximisable method
1938     */
1939    public void setMaximisable(final boolean value)
1940    {
1941        // AWT safe
1942        ThreadUtil.invoke(new Runnable()
1943        {
1944            @Override
1945            public void run()
1946            {
1947                // only for internal frame
1948                internalFrame.setMaximizable(value);
1949            }
1950        }, syncProcess);
1951    }
1952
1953    /**
1954     * Implement setMinimized method
1955     */
1956    public void setMinimized(final boolean value)
1957    {
1958        // only relevant if state changed
1959        if (isMinimized() ^ value)
1960        {
1961            // AWT safe
1962            ThreadUtil.invoke(new Runnable()
1963            {
1964                @Override
1965                public void run()
1966                {
1967                    if (isInternalized())
1968                        internalFrame.setMinimized(value);
1969                    else
1970                        externalFrame.setMinimized(value);
1971                }
1972            }, syncProcess);
1973        }
1974    }
1975
1976    /**
1977     * Implement setMinimized method for internal frame only
1978     */
1979    public void setMinimizedInternal(final boolean value)
1980    {
1981        // only relevant if state changed
1982        if (internalFrame.isMinimized() ^ value)
1983        {
1984            // AWT safe
1985            ThreadUtil.invoke(new Runnable()
1986            {
1987                @Override
1988                public void run()
1989                {
1990                    internalFrame.setMinimized(value);
1991                }
1992            }, syncProcess);
1993        }
1994    }
1995
1996    /**
1997     * Implement setMinimized method for external frame only
1998     */
1999    public void setMinimizedExternal(final boolean value)
2000    {
2001        // only relevant if state changed
2002        if (externalFrame.isMinimized() ^ value)
2003        {
2004            // AWT safe
2005            ThreadUtil.invoke(new Runnable()
2006            {
2007                @Override
2008                public void run()
2009                {
2010                    externalFrame.setMinimized(value);
2011                }
2012            }, syncProcess);
2013        }
2014    }
2015
2016    /**
2017     * Implement setMaximized method
2018     */
2019    public void setMaximized(final boolean value)
2020    {
2021        // only relevant if state changed
2022        if (isMaximized() ^ value)
2023        {
2024            // AWT safe
2025            ThreadUtil.invoke(new Runnable()
2026            {
2027                @Override
2028                public void run()
2029                {
2030                    if (isInternalized())
2031                        internalFrame.setMaximized(value);
2032                    else
2033                        externalFrame.setMaximized(value);
2034                }
2035            }, syncProcess);
2036        }
2037    }
2038
2039    /**
2040     * Implement setMaximized method for internal frame only
2041     */
2042    public void setMaximizedInternal(final boolean value)
2043    {
2044        // only relevant if state changed
2045        if (internalFrame.isMaximized() ^ value)
2046        {
2047            // AWT safe
2048            ThreadUtil.invoke(new Runnable()
2049            {
2050                @Override
2051                public void run()
2052                {
2053                    internalFrame.setMaximized(value);
2054                }
2055            }, syncProcess);
2056        }
2057    }
2058
2059    /**
2060     * Implement setMaximized method for external frame only
2061     */
2062    public void setMaximizedExternal(final boolean value)
2063    {
2064        // only relevant if state changed
2065        if (externalFrame.isMaximized() ^ value)
2066        {
2067            // AWT safe
2068            ThreadUtil.invoke(new Runnable()
2069            {
2070                @Override
2071                public void run()
2072                {
2073                    externalFrame.setMaximized(value);
2074                }
2075            }, syncProcess);
2076        }
2077    }
2078
2079    /**
2080     * Implement setClosable method
2081     */
2082    public void setClosable(final boolean value)
2083    {
2084        // AWT safe
2085        ThreadUtil.invoke(new Runnable()
2086        {
2087            @Override
2088            public void run()
2089            {
2090                internalFrame.setClosable(value);
2091            }
2092        }, syncProcess);
2093    }
2094
2095    /**
2096     * Implement setDefaultCloseOperation method
2097     * 
2098     * @see JFrame#setDefaultCloseOperation(int)
2099     */
2100    public void setDefaultCloseOperation(final int operation)
2101    {
2102        // AWT safe
2103        ThreadUtil.invoke(new Runnable()
2104        {
2105            @Override
2106            public void run()
2107            {
2108                internalFrame.setDefaultCloseOperation(operation);
2109                externalFrame.setDefaultCloseOperation(operation);
2110            }
2111        }, syncProcess);
2112    }
2113
2114    /**
2115     * Implement setFocusable method
2116     */
2117    public void setFocusable(final boolean value)
2118    {
2119        // AWT safe
2120        ThreadUtil.invoke(new Runnable()
2121        {
2122            @Override
2123            public void run()
2124            {
2125                internalFrame.setFocusable(value);
2126                externalFrame.setFocusable(value);
2127            }
2128        }, syncProcess);
2129    }
2130
2131    /**
2132     * Implement setVisible method
2133     */
2134    public void setVisible(final boolean value)
2135    {
2136        // AWT safe
2137        ThreadUtil.invoke(new Runnable()
2138        {
2139            @Override
2140            public void run()
2141            {
2142                if (isInternalized())
2143                    internalFrame.setVisible(value);
2144                else
2145                    externalFrame.setVisible(value);
2146            }
2147        }, syncProcess);
2148    }
2149
2150    /**
2151     * Implement setAlwaysOnTop method (only for externalized frame)
2152     */
2153    public void setAlwaysOnTop(final boolean alwaysOnTop)
2154    {
2155        // AWT safe
2156        ThreadUtil.invoke(new Runnable()
2157        {
2158            @Override
2159            public void run()
2160            {
2161                externalFrame.setAlwaysOnTop(alwaysOnTop);
2162            }
2163        }, syncProcess);
2164    }
2165
2166    /**
2167     * Implement setJMenuBar method
2168     */
2169    public void setJMenuBar(final JMenuBar m)
2170    {
2171        // AWT safe
2172        ThreadUtil.invoke(new Runnable()
2173        {
2174            @Override
2175            public void run()
2176            {
2177                if (isInternalized())
2178                    internalFrame.setJMenuBar(m);
2179                else
2180                    externalFrame.setJMenuBar(m);
2181            }
2182        }, syncProcess);
2183    }
2184
2185    /**
2186     * Hide or show the title bar (frame should not be displayable when you set this property)
2187     */
2188    public void setTitleBarVisible(final boolean value)
2189    {
2190        // AWT safe
2191        ThreadUtil.invoke(new Runnable()
2192        {
2193            @Override
2194            public void run()
2195            {
2196                internalFrame.setTitleBarVisible(value);
2197                externalFrame.setTitleBarVisible(value);
2198            }
2199        }, syncProcess);
2200    }
2201
2202    /**
2203     * Implement setLayout method
2204     */
2205    public void setLayout(final LayoutManager layout)
2206    {
2207        // AWT safe
2208        ThreadUtil.invoke(new Runnable()
2209        {
2210            @Override
2211            public void run()
2212            {
2213                if (isInternalized())
2214                    internalFrame.setLayout(layout);
2215                else
2216                    externalFrame.setLayout(layout);
2217            }
2218        }, syncProcess);
2219    }
2220
2221    /**
2222     * Implement setBorder method (only for internal frame)
2223     */
2224    public void setBorder(final Border border)
2225    {
2226        // AWT safe
2227        ThreadUtil.invoke(new Runnable()
2228        {
2229            @Override
2230            public void run()
2231            {
2232                internalFrame.setBorder(border);
2233            }
2234        }, syncProcess);
2235    }
2236
2237    /**
2238     * Implement setContentPane method
2239     */
2240    public void setContentPane(final Container value)
2241    {
2242        // AWT safe
2243        ThreadUtil.invoke(new Runnable()
2244        {
2245            @Override
2246            public void run()
2247            {
2248                if (isInternalized())
2249                    internalFrame.setContentPane(value);
2250                else
2251                    externalFrame.setContentPane(value);
2252            }
2253        }, syncProcess);
2254    }
2255
2256    /**
2257     * @return the syncProcess
2258     */
2259    public boolean isSyncProcess()
2260    {
2261        return syncProcess;
2262    }
2263
2264    /**
2265     * By default IcyFrame does asych processing, you can force sync processing<br>
2266     * with this property
2267     * 
2268     * @param syncProcess
2269     *        the syncProcess to set
2270     */
2271    public void setSyncProcess(boolean syncProcess)
2272    {
2273        this.syncProcess = syncProcess;
2274    }
2275
2276    /**
2277     * Frame becomes the active/focused frame
2278     */
2279    public void requestFocus()
2280    {
2281        // AWT safe
2282        ThreadUtil.invoke(new Runnable()
2283        {
2284            @Override
2285            public void run()
2286            {
2287                if (isInternalized())
2288                {
2289                    try
2290                    {
2291                        internalFrame.setSelected(true);
2292                    }
2293                    catch (PropertyVetoException e)
2294                    {
2295                        // ignore
2296                    }
2297                }
2298                else
2299                    externalFrame.requestFocus();
2300            }
2301        }, syncProcess);
2302    }
2303
2304    /**
2305     * Implement validate
2306     */
2307    public void validate()
2308    {
2309        // AWT safe
2310        ThreadUtil.invoke(new Runnable()
2311        {
2312            @Override
2313            public void run()
2314            {
2315                if (isInternalized())
2316                    internalFrame.validate();
2317                else
2318                    externalFrame.validate();
2319            }
2320        }, syncProcess);
2321    }
2322
2323    /**
2324     * Implement revalidate
2325     */
2326    public void revalidate()
2327    {
2328        // AWT safe
2329        ThreadUtil.invoke(new Runnable()
2330        {
2331            @Override
2332            public void run()
2333            {
2334                if (isInternalized())
2335                    internalFrame.revalidate();
2336                else
2337                {
2338                    externalFrame.invalidate();
2339                    externalFrame.repaint();
2340                }
2341            }
2342        }, syncProcess);
2343    }
2344
2345    /**
2346     * Implement repaint
2347     */
2348    public void repaint()
2349    {
2350        // AWT safe
2351        ThreadUtil.invoke(new Runnable()
2352        {
2353            @Override
2354            public void run()
2355            {
2356                if (isInternalized())
2357                    internalFrame.repaint();
2358                else
2359                    externalFrame.repaint();
2360            }
2361        }, syncProcess);
2362    }
2363
2364    /**
2365     * Implement updateUI
2366     */
2367    public void updateUI()
2368    {
2369        // AWT safe
2370        ThreadUtil.invoke(new Runnable()
2371        {
2372            @Override
2373            public void run()
2374            {
2375                internalFrame.updateUI();
2376            }
2377        }, syncProcess);
2378    }
2379
2380    /**
2381     * Fire frame activated event
2382     */
2383    private void fireFrameActivated(IcyFrameEvent e)
2384    {
2385        for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
2386            l.icyFrameActivated(e);
2387    }
2388
2389    /**
2390     * Fire frame deactivated event
2391     */
2392    private void fireFrameDeactivated(IcyFrameEvent e)
2393    {
2394        for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
2395            l.icyFrameDeactivated(e);
2396    }
2397
2398    /**
2399     * Fire frame closing event
2400     */
2401    private void fireFrameClosing(IcyFrameEvent e)
2402    {
2403        for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
2404            l.icyFrameClosing(e);
2405    }
2406
2407    /**
2408     * Fire frame closed event
2409     */
2410    private void fireFrameClosed(IcyFrameEvent e)
2411    {
2412        for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
2413            l.icyFrameClosed(e);
2414    }
2415
2416    /**
2417     * Fire frame iconified event
2418     */
2419    private void fireFrameIconified(IcyFrameEvent e)
2420    {
2421        for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
2422            l.icyFrameIconified(e);
2423    }
2424
2425    /**
2426     * Fire frame deiconified event
2427     */
2428    private void fireFrameDeiconified(IcyFrameEvent e)
2429    {
2430        for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
2431            l.icyFrameDeiconified(e);
2432    }
2433
2434    /**
2435     * Fire frame opened event
2436     */
2437    private void fireFrameOpened(IcyFrameEvent e)
2438    {
2439        for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
2440            l.icyFrameOpened(e);
2441    }
2442
2443    /**
2444     * Fire frame internalized event
2445     */
2446    void fireFrameInternalized(IcyFrameEvent e)
2447    {
2448        for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
2449            l.icyFrameInternalized(e);
2450    }
2451
2452    /**
2453     * Fire frame externalized event
2454     */
2455    void fireFrameExternalized(IcyFrameEvent e)
2456    {
2457        for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
2458            l.icyFrameExternalized(e);
2459    }
2460
2461    /**
2462     * Implement addFrameListener method
2463     */
2464    public void addFrameListener(IcyFrameListener l)
2465    {
2466        frameEventListeners.add(IcyFrameListener.class, l);
2467    }
2468
2469    /**
2470     * Implement removeFrameListener method
2471     */
2472    public void removeFrameListener(IcyFrameListener l)
2473    {
2474        frameEventListeners.remove(IcyFrameListener.class, l);
2475    }
2476
2477    /**
2478     * Implement addComponentListener method
2479     */
2480    public void addComponentListener(ComponentListener l)
2481    {
2482        internalFrame.addComponentListener(l);
2483        externalFrame.addComponentListener(l);
2484    }
2485
2486    /**
2487     * Implement removeComponentListener method
2488     */
2489    public void removeComponentListener(ComponentListener l)
2490    {
2491        internalFrame.removeComponentListener(l);
2492        externalFrame.removeComponentListener(l);
2493    }
2494
2495    /**
2496     * Implement addKeyListener method
2497     */
2498    public void addKeyListener(KeyListener l)
2499    {
2500        internalFrame.addKeyListener(l);
2501        externalFrame.addKeyListener(l);
2502    }
2503
2504    /**
2505     * Implement addKeyListener method
2506     */
2507    public void removeKeyListener(KeyListener l)
2508    {
2509        internalFrame.removeKeyListener(l);
2510        externalFrame.removeKeyListener(l);
2511    }
2512
2513    /**
2514     * internal close stuff
2515     */
2516    public void frameClosed(AWTEvent e)
2517    {
2518        final MainFrame mainFrame = Icy.getMainInterface().getMainFrame();
2519        // remove listener on main frame mode change
2520        if (mainFrame != null)
2521            mainFrame.removePropertyChangeListener(MainFrame.PROPERTY_DETACHEDMODE, this);
2522        // remove others listeners
2523        externalFrame.removeWindowListener(IcyFrame.this);
2524        internalFrame.removeInternalFrameListener(IcyFrame.this);
2525
2526        if (e instanceof InternalFrameEvent)
2527        {
2528            fireFrameClosed(new IcyFrameEvent(this, (InternalFrameEvent) e, null));
2529            // don't forget to close external frame
2530            externalFrame.dispose();
2531        }
2532        else if (e instanceof WindowEvent)
2533        {
2534            fireFrameClosed(new IcyFrameEvent(this, null, (WindowEvent) e));
2535            // don't forget to close internal frame
2536            internalFrame.dispose();
2537        }
2538
2539        // easy onClosed handling
2540        onClosed();
2541    }
2542
2543    /**
2544     * easy onClosed job
2545     */
2546    public void onClosed()
2547    {
2548        // unregister from list
2549        synchronized (frames)
2550        {
2551            frames.remove(this);
2552        }
2553
2554        // release some stuff else we have cycling reference
2555        externalFrame.systemMenuCallback = null;
2556        internalFrame.systemMenuCallback = null;
2557        switchStateAction = null;
2558    }
2559
2560    @Override
2561    public void internalFrameActivated(InternalFrameEvent e)
2562    {
2563        fireFrameActivated(new IcyFrameEvent(this, e, null));
2564    }
2565
2566    @Override
2567    public void internalFrameClosed(InternalFrameEvent e)
2568    {
2569        frameClosed(e);
2570    }
2571
2572    @Override
2573    public void internalFrameClosing(InternalFrameEvent e)
2574    {
2575        fireFrameClosing(new IcyFrameEvent(this, e, null));
2576    }
2577
2578    @Override
2579    public void internalFrameDeactivated(InternalFrameEvent e)
2580    {
2581        fireFrameDeactivated(new IcyFrameEvent(this, e, null));
2582    }
2583
2584    @Override
2585    public void internalFrameDeiconified(InternalFrameEvent e)
2586    {
2587        fireFrameDeiconified(new IcyFrameEvent(this, e, null));
2588    }
2589
2590    @Override
2591    public void internalFrameIconified(InternalFrameEvent e)
2592    {
2593        fireFrameIconified(new IcyFrameEvent(this, e, null));
2594    }
2595
2596    @Override
2597    public void internalFrameOpened(InternalFrameEvent e)
2598    {
2599        fireFrameOpened(new IcyFrameEvent(this, e, null));
2600    }
2601
2602    @Override
2603    public void windowActivated(WindowEvent e)
2604    {
2605        fireFrameActivated(new IcyFrameEvent(this, null, e));
2606    }
2607
2608    @Override
2609    public void windowClosed(WindowEvent e)
2610    {
2611        frameClosed(e);
2612    }
2613
2614    @Override
2615    public void windowClosing(WindowEvent e)
2616    {
2617        fireFrameClosing(new IcyFrameEvent(this, null, e));
2618    }
2619
2620    @Override
2621    public void windowDeactivated(WindowEvent e)
2622    {
2623        fireFrameDeactivated(new IcyFrameEvent(this, null, e));
2624    }
2625
2626    @Override
2627    public void windowDeiconified(WindowEvent e)
2628    {
2629        fireFrameDeiconified(new IcyFrameEvent(this, null, e));
2630    }
2631
2632    @Override
2633    public void windowIconified(WindowEvent e)
2634    {
2635        fireFrameIconified(new IcyFrameEvent(this, null, e));
2636    }
2637
2638    @Override
2639    public void windowOpened(WindowEvent e)
2640    {
2641        fireFrameOpened(new IcyFrameEvent(this, null, e));
2642    }
2643
2644    @Override
2645    public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
2646    {
2647        if (isInternalized())
2648            return internalFrame.imageUpdate(img, infoflags, x, y, width, height);
2649
2650        return externalFrame.imageUpdate(img, infoflags, x, y, width, height);
2651    }
2652
2653    @Override
2654    public void propertyChange(PropertyChangeEvent evt)
2655    {
2656        if (StringUtil.equals(evt.getPropertyName(), MainFrame.PROPERTY_DETACHEDMODE))
2657        {
2658            // window mode has been changed
2659            final boolean detachedMode = ((Boolean) evt.getNewValue()).booleanValue();
2660
2661            // detached mode set --> externalize
2662            if (detachedMode)
2663            {
2664                // save previous state
2665                previousState = state;
2666                externalize();
2667                // disable switch state item
2668                if (switchStateAction != null)
2669                    switchStateAction.setEnabled(false);
2670            }
2671            else
2672            {
2673                // restore previous state
2674                if (previousState == IcyFrameState.INTERNALIZED)
2675                    internalize();
2676                // enable switch state item
2677                if (switchStateAction != null)
2678                    switchStateAction.setEnabled(true);
2679            }
2680        }
2681    }
2682}