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.util;
020
021import icy.common.listener.weak.WeakComponentListener;
022import icy.common.listener.weak.WeakIcyFrameListener;
023import icy.common.listener.weak.WeakWindowListener;
024import icy.gui.component.ExternalizablePanel;
025import icy.gui.component.ExternalizablePanel.StateListener;
026import icy.gui.component.ExternalizablePanel.WeakStateListener;
027import icy.gui.frame.IcyFrame;
028import icy.gui.frame.IcyFrameAdapter;
029import icy.gui.frame.IcyFrameEvent;
030import icy.gui.main.MainFrame;
031import icy.preferences.IcyPreferences;
032import icy.preferences.XMLPreferences;
033
034import java.awt.Dimension;
035import java.awt.Point;
036import java.awt.event.ComponentAdapter;
037import java.awt.event.ComponentEvent;
038import java.awt.event.WindowAdapter;
039import java.awt.event.WindowEvent;
040
041import javax.swing.JComponent;
042import javax.swing.JFrame;
043
044/**
045 * Load and Save you window position in the registry
046 * 
047 * @author fab & stephane
048 */
049public class WindowPositionSaver
050{
051    final private static String ID_EXTERNALIZED = "Externalized";
052    final private static String ID_PANELIZED = "Panelized";
053
054    final private static String ID_XC = "XC";
055    final private static String ID_YC = "YC";
056    final private static String ID_WC = "WidthC";
057    final private static String ID_HC = "HeightC";
058
059    final private static String ID_XI = "XI";
060    final private static String ID_YI = "YI";
061    final private static String ID_WI = "WidthI";
062    final private static String ID_HI = "HeightI";
063    final private static String ID_MAXIMIZEDI = "MaximizedI";
064
065    final private static String ID_XE = "XE";
066    final private static String ID_YE = "YE";
067    final private static String ID_WE = "WidthE";
068    final private static String ID_HE = "HeightE";
069    final private static String ID_MAXIMIZEDE = "MaximizedE";
070
071    final XMLPreferences preferences;
072
073    final private MainFrame mainFrame;
074    final private IcyFrame icyFrame;
075    final private ExternalizablePanel extPanel;
076    final private JFrame jFrame;
077    final private JComponent component;
078
079    final private boolean hasLoc;
080    final private boolean hasDim;
081
082    final WindowAdapter windowAdapter;
083    final IcyFrameAdapter icyFrameAdapter;
084    final ComponentAdapter componentAdapter;
085    final StateListener stateListener;
086
087    private WindowPositionSaver(final MainFrame mainFrame, final IcyFrame icyFrame, final ExternalizablePanel extPanel,
088            final JFrame jFrame, final JComponent component, final String key, final Point defLoc,
089            final Dimension defDim)
090    {
091        preferences = IcyPreferences.root().node(key);
092
093        this.mainFrame = mainFrame;
094        this.icyFrame = icyFrame;
095        this.extPanel = extPanel;
096        this.jFrame = jFrame;
097        this.component = component;
098
099        hasLoc = defLoc != null;
100        hasDim = defDim != null;
101
102        // directly load location and dimension
103        if (hasLoc)
104            loadLocation(defLoc);
105        if (hasDim)
106            loadDimension(defDim);
107        loadState();
108
109        // keep hard reference on it
110        componentAdapter = new ComponentAdapter()
111        {
112            @Override
113            public void componentResized(ComponentEvent e)
114            {
115                // event comes from panel itself
116                if ((extPanel == null) || (e.getSource() == extPanel))
117                    saveAll();
118            }
119
120            @Override
121            public void componentMoved(ComponentEvent e)
122            {
123                // event comes from panel itself
124                if ((extPanel == null) || (e.getSource() == extPanel))
125                    saveAll();
126            }
127
128            @Override
129            public void componentShown(ComponentEvent e)
130            {
131                // correctly save internalized / externalized state
132                saveAll();
133            }
134
135            @Override
136            public void componentHidden(ComponentEvent e)
137            {
138                // correctly save internalized / externalized state
139                saveAll();
140            }
141        };
142
143        // keep hard reference on it
144        windowAdapter = new WindowAdapter()
145        {
146            @Override
147            public void windowClosing(WindowEvent e)
148            {
149                saveAll();
150            }
151        };
152
153        // keep hard reference on it
154        icyFrameAdapter = new IcyFrameAdapter()
155        {
156            @Override
157            public void icyFrameClosing(IcyFrameEvent e)
158            {
159                saveAll();
160            }
161        };
162
163        // keep hard reference on it
164        stateListener = new StateListener()
165        {
166            @Override
167            public void stateChanged(ExternalizablePanel source, boolean externalized)
168            {
169                saveAll();
170            }
171        };
172
173        if (mainFrame != null)
174        {
175            mainFrame.addWindowListener(new WeakWindowListener(windowAdapter));
176            mainFrame.addComponentListener(new WeakComponentListener(componentAdapter));
177        }
178        else if (icyFrame != null)
179        {
180            icyFrame.addFrameListener(new WeakIcyFrameListener(icyFrameAdapter));
181            icyFrame.addComponentListener(new WeakComponentListener(componentAdapter));
182        }
183        else if (extPanel != null)
184        {
185            extPanel.addComponentListener(new WeakComponentListener(componentAdapter));
186            extPanel.addStateListener(new WeakStateListener(stateListener));
187            extPanel.getFrame().addFrameListener(new WeakIcyFrameListener(icyFrameAdapter));
188            extPanel.getFrame().addComponentListener(new WeakComponentListener(componentAdapter));
189        }
190        else if (jFrame != null)
191        {
192            jFrame.addWindowListener(new WeakWindowListener(windowAdapter));
193            jFrame.addComponentListener(new WeakComponentListener(componentAdapter));
194        }
195        else if (component != null)
196        {
197            component.addComponentListener(new WeakComponentListener(componentAdapter));
198        }
199
200        checkVisibility();
201    }
202
203    public WindowPositionSaver(MainFrame frame, String key, Point defLoc, Dimension defDim)
204    {
205        this(frame, null, null, null, null, key, defLoc, defDim);
206    }
207
208    public WindowPositionSaver(MainFrame frame, String key, Point defLoc)
209    {
210        this(frame, null, null, null, null, key, defLoc, null);
211    }
212
213    public WindowPositionSaver(MainFrame frame, String key, Dimension defDim)
214    {
215        this(frame, null, null, null, null, key, null, defDim);
216    }
217
218    public WindowPositionSaver(IcyFrame frame, String key, Point defLoc, Dimension defDim)
219    {
220        this(null, frame, null, null, null, key, defLoc, defDim);
221    }
222
223    public WindowPositionSaver(IcyFrame frame, String key, Point defLoc)
224    {
225        this(null, frame, null, null, null, key, defLoc, null);
226    }
227
228    public WindowPositionSaver(IcyFrame frame, String key, Dimension defDim)
229    {
230        this(null, frame, null, null, null, key, null, defDim);
231    }
232
233    public WindowPositionSaver(ExternalizablePanel extPanel, String key, Point defLoc, Dimension defDim)
234    {
235        this(null, null, extPanel, null, null, key, defLoc, defDim);
236    }
237
238    public WindowPositionSaver(ExternalizablePanel extPanel, String key, Point defLoc)
239    {
240        this(null, null, extPanel, null, null, key, defLoc, null);
241    }
242
243    public WindowPositionSaver(ExternalizablePanel extPanel, String key, Dimension defDim)
244    {
245        this(null, null, extPanel, null, null, key, null, defDim);
246    }
247
248    public WindowPositionSaver(JFrame frame, String key, Point defLoc, Dimension defDim)
249    {
250        this(null, null, null, frame, null, key, defLoc, defDim);
251    }
252
253    public WindowPositionSaver(JFrame frame, String key, Point defLoc)
254    {
255        this(null, null, null, frame, null, key, defLoc, null);
256    }
257
258    public WindowPositionSaver(JFrame frame, String key, Dimension defDim)
259    {
260        this(null, null, null, frame, null, key, null, defDim);
261    }
262
263    public WindowPositionSaver(JComponent component, String key, Point defLoc, Dimension defDim)
264    {
265        this(null, null, null, null, component, key, defLoc, defDim);
266    }
267
268    public WindowPositionSaver(JComponent component, String key, Point defLoc)
269    {
270        this(null, null, null, null, component, key, defLoc, null);
271    }
272
273    public WindowPositionSaver(JComponent component, String key, Dimension defDim)
274    {
275        this(null, null, null, null, component, key, null, defDim);
276    }
277
278    // void checkPosition()
279    // {
280    // final Rectangle rect;
281    //
282    // ComponentUtil.fixPosition(rect, rect);
283    //
284    // // only for frame
285    // if (mainFrame != null)
286    // ComponentUtil.fixP
287    // rect = mainFrame.getBounds();
288    // else if (icyFrame != null)
289    // rect = icyFrame.getBounds();
290    // // check position only for frame
291    // else if ((extPanel != null) && extPanel.isExternalized())
292    // rect = extPanel.getFrame().getBounds();
293    // else if (jFrame != null)
294    // rect = jFrame.getBounds();
295    // else
296    // return;
297    //
298    // if (fixPosition(rect))
299    // {
300    // if (mainFrame != null)
301    // mainFrame.setBounds(rect);
302    // else if (icyFrame != null)
303    // icyFrame.setBounds(rect);
304    // // check position only for frame
305    // else if ((extPanel != null) && extPanel.isExternalized())
306    // extPanel.getFrame().setBounds(rect);
307    // else if (jFrame != null)
308    // jFrame.setBounds(rect);
309    // }
310    // }
311    //
312    // public static boolean fixPosition(Rectangle rect)
313    // {
314    // Rectangle desktopRect = SystemUtil.getDesktopBounds();
315    // boolean result = false;
316    // int limit;
317    //
318    // limit = (int) (desktopRect.getMaxX() - DESKTOP_MARGIN);
319    // if (rect.x >= limit)
320    // {
321    // rect.x = limit;
322    // result = true;
323    // }
324    // else
325    // {
326    // limit = (int) desktopRect.getMinX();
327    // if (((rect.x + rect.width) - DESKTOP_MARGIN) < limit)
328    // {
329    // rect.x = DESKTOP_MARGIN - rect.width;
330    // result = true;
331    // }
332    // }
333    // limit = (int) (desktopRect.getMaxY() - DESKTOP_MARGIN);
334    // if (rect.y >= limit)
335    // {
336    // rect.y = limit;
337    // result = true;
338    // }
339    // else
340    // {
341    // limit = (int) desktopRect.getMinY();
342    // if (rect.y < limit)
343    // {
344    // rect.y = limit;
345    // result = true;
346    // }
347    // }
348    //
349    // return result;
350    // }
351
352    public XMLPreferences getPreferences()
353    {
354        return preferences;
355    }
356
357    public void loadLocation(Point defaultPos)
358    {
359        final int x, y;
360
361        if (defaultPos == null)
362        {
363            x = 0;
364            y = 0;
365        }
366        else
367        {
368            x = defaultPos.x;
369            y = defaultPos.y;
370        }
371
372        final Point positionC = new Point(preferences.getInt(ID_XC, x), preferences.getInt(ID_YC, y));
373        final Point positionI = new Point(preferences.getInt(ID_XI, x), preferences.getInt(ID_YI, y));
374        final Point positionE = new Point(preferences.getInt(ID_XE, x), preferences.getInt(ID_YE, y));
375
376        if (mainFrame != null)
377        {
378            mainFrame.setLocation(positionE);
379        }
380        else if (icyFrame != null)
381        {
382            icyFrame.setLocationInternal(positionI);
383            icyFrame.setLocationExternal(positionE);
384        }
385        else if (extPanel != null)
386        {
387            extPanel.setLocation(positionC);
388
389            // get the panel frame
390            final IcyFrame f = extPanel.getFrame();
391
392            f.setLocationInternal(positionI);
393            f.setLocationExternal(positionE);
394        }
395        else if (jFrame != null)
396        {
397            jFrame.setLocation(positionE);
398        }
399        else if (component != null)
400        {
401            component.setLocation(positionC);
402        }
403    }
404
405    public void loadDimension(Dimension defaultDim)
406    {
407        final int w, h;
408
409        if (defaultDim == null)
410        {
411            w = 300;
412            h = 300;
413        }
414        else
415        {
416            w = defaultDim.width;
417            h = defaultDim.height;
418        }
419
420        // minimum size is 10 pixels
421        int widthC = Math.max(preferences.getInt(ID_WC, w), 10);
422        int heightC = Math.max(preferences.getInt(ID_HC, h), 10);
423        int widthI = Math.max(preferences.getInt(ID_WI, w), 10);
424        int heightI = Math.max(preferences.getInt(ID_HI, h), 10);
425        int widthE = Math.max(preferences.getInt(ID_WE, w), 10);
426        int heightE = Math.max(preferences.getInt(ID_HE, h), 10);
427
428        final Dimension dimC = new Dimension(widthC, heightC);
429        final Dimension dimI = new Dimension(widthI, heightI);
430        final Dimension dimE = new Dimension(widthE, heightE);
431
432        if (mainFrame != null)
433        {
434            // set size only else we cannot pack anymore the frame for detached mode
435            mainFrame.setSize(dimE);
436        }
437        else if (icyFrame != null)
438        {
439            icyFrame.setPreferredSizeExternal(dimE);
440            icyFrame.setSizeExternal(dimE);
441            icyFrame.setPreferredSizeInternal(dimI);
442            icyFrame.setSizeInternal(dimI);
443        }
444        else if (extPanel != null)
445        {
446            extPanel.setPreferredSize(dimC);
447
448            // get the panel frame
449            final IcyFrame f = extPanel.getFrame();
450
451            f.setPreferredSizeExternal(dimE);
452            f.setSizeExternal(dimE);
453            f.setPreferredSizeInternal(dimI);
454            f.setSizeInternal(dimI);
455        }
456        else if (jFrame != null)
457        {
458            jFrame.setPreferredSize(dimE);
459            jFrame.setSize(dimE);
460        }
461        else if (component != null)
462        {
463            component.setPreferredSize(dimC);
464        }
465    }
466
467    public void loadState()
468    {
469        // default is internalized and panelized
470        final boolean externalized = preferences.getBoolean(ID_EXTERNALIZED, false);
471        final boolean panelized = preferences.getBoolean(ID_PANELIZED, true);
472        final boolean maximizedE = preferences.getBoolean(ID_MAXIMIZEDE, false);
473        final boolean maximizedI = preferences.getBoolean(ID_MAXIMIZEDI, false);
474
475        if (mainFrame != null)
476        {
477            ComponentUtil.setMaximized(mainFrame, maximizedE);
478        }
479        else if (icyFrame != null)
480        {
481            if (externalized)
482                icyFrame.externalize();
483            else
484                icyFrame.internalize();
485            icyFrame.setMaximizedExternal(maximizedE);
486            icyFrame.setMaximizedInternal(maximizedI);
487        }
488        else if (extPanel != null)
489        {
490            // get the panel frame
491            final IcyFrame f = extPanel.getFrame();
492
493            if (externalized)
494                f.externalize();
495            else
496                f.internalize();
497            f.setMaximizedExternal(maximizedE);
498            f.setMaximizedInternal(maximizedI);
499
500            if (panelized)
501                extPanel.internalize();
502            else
503                extPanel.externalize();
504        }
505        else if (jFrame != null)
506        {
507            ComponentUtil.setMaximized(jFrame, maximizedE);
508        }
509    }
510
511    public void checkVisibility()
512    {
513        if (!hasLoc)
514            return;
515
516        if (icyFrame != null)
517        {
518            // not visible ?
519            if (icyFrame.getVisibleRect().isEmpty())
520            {
521                final Point location = icyFrame.getLocation();
522
523                // potentially outside visible area ? --> reset its position
524                if ((location.x < 0) || (location.x > 700) || (location.y < 0) || (location.y > 500))
525                    icyFrame.setLocation(100, 100);
526            }
527        }
528        else if (extPanel != null)
529        {
530            // not visible ? reset its position
531            if (extPanel.getVisibleRect().isEmpty())
532            {
533                final Point location = extPanel.getLocation();
534
535                // potentially outside visible area ? --> reset its position
536                if ((location.x < 0) || (location.x > 500) || (location.y < 0) || (location.y > 300))
537                    extPanel.setLocation(100, 100);
538            }
539        }
540        else if (component != null)
541        {
542            // not visible ? reset its position
543            if (component.getVisibleRect().isEmpty())
544            {
545                final Point location = component.getLocation();
546
547                // potentially outside visible area ? --> reset its position
548                if ((location.x < 0) || (location.x > 500) || (location.y < 0) || (location.y > 300))
549                    component.setLocation(100, 100);
550            }
551        }
552    }
553
554    public void saveLocation()
555    {
556        if (mainFrame != null)
557        {
558            if (!(ComponentUtil.isMaximized(mainFrame) || ComponentUtil.isMinimized(mainFrame)))
559            {
560                preferences.putInt(ID_XE, mainFrame.getX());
561                preferences.putInt(ID_YE, mainFrame.getY());
562            }
563        }
564        else if (icyFrame != null)
565        {
566            if (!(icyFrame.isMaximizedExternal() || icyFrame.isMinimizedExternal()))
567            {
568                preferences.putInt(ID_XE, icyFrame.getXExternal());
569                preferences.putInt(ID_YE, icyFrame.getYExternal());
570            }
571            if (!(icyFrame.isMaximizedInternal() || icyFrame.isMinimizedInternal()))
572            {
573                preferences.putInt(ID_XI, icyFrame.getXInternal());
574                preferences.putInt(ID_YI, icyFrame.getYInternal());
575            }
576        }
577        else if (extPanel != null)
578        {
579            preferences.putInt(ID_XC, extPanel.getX());
580            preferences.putInt(ID_YC, extPanel.getY());
581
582            // get the panel frame
583            final IcyFrame f = extPanel.getFrame();
584
585            if (!(f.isMaximizedExternal() || f.isMinimizedExternal()))
586            {
587                preferences.putInt(ID_XE, f.getXExternal());
588                preferences.putInt(ID_YE, f.getYExternal());
589            }
590            if (!(f.isMaximizedInternal() || f.isMinimizedInternal()))
591            {
592                preferences.putInt(ID_XI, f.getXInternal());
593                preferences.putInt(ID_YI, f.getYInternal());
594            }
595        }
596        else if (jFrame != null)
597        {
598            if (!(ComponentUtil.isMaximized(jFrame) || ComponentUtil.isMinimized(jFrame)))
599            {
600                preferences.putInt(ID_XE, jFrame.getX());
601                preferences.putInt(ID_YE, jFrame.getY());
602            }
603        }
604        else if (component != null)
605        {
606            preferences.putInt(ID_XC, component.getX());
607            preferences.putInt(ID_YC, component.getY());
608        }
609    }
610
611    public void saveDimension()
612    {
613        if (mainFrame != null)
614        {
615            if (!(ComponentUtil.isMaximized(mainFrame) || ComponentUtil.isMinimized(mainFrame)))
616            {
617                final Dimension dim;
618
619                if (mainFrame.isDetachedMode())
620                    dim = new Dimension(mainFrame.getWidth(), mainFrame.getPreviousHeight());
621                else
622                    dim = mainFrame.getSize();
623
624                preferences.putInt(ID_WE, dim.width);
625                preferences.putInt(ID_HE, dim.height);
626            }
627        }
628        else if (icyFrame != null)
629        {
630            if (!(icyFrame.isMaximizedExternal() || icyFrame.isMinimizedExternal()))
631            {
632                preferences.putInt(ID_WE, icyFrame.getWidthExternal());
633                preferences.putInt(ID_HE, icyFrame.getHeightExternal());
634            }
635            if (!(icyFrame.isMaximizedInternal() || icyFrame.isMinimizedInternal()))
636            {
637                preferences.putInt(ID_WI, icyFrame.getWidthInternal());
638                preferences.putInt(ID_HI, icyFrame.getHeightInternal());
639            }
640        }
641        else if (extPanel != null)
642        {
643            preferences.putInt(ID_WC, extPanel.getWidth());
644            preferences.putInt(ID_HC, extPanel.getHeight());
645
646            // get the panel frame
647            final IcyFrame f = extPanel.getFrame();
648
649            if (!(f.isMaximizedExternal() || f.isMinimizedExternal()))
650            {
651                preferences.putInt(ID_WE, f.getWidthExternal());
652                preferences.putInt(ID_HE, f.getHeightExternal());
653            }
654            if (!(f.isMaximizedInternal() || f.isMinimizedInternal()))
655            {
656                preferences.putInt(ID_WI, f.getWidthInternal());
657                preferences.putInt(ID_HI, f.getHeightInternal());
658            }
659        }
660        else if (jFrame != null)
661        {
662            if (!(ComponentUtil.isMaximized(jFrame) || ComponentUtil.isMinimized(jFrame)))
663            {
664                preferences.putInt(ID_WE, jFrame.getWidth());
665                preferences.putInt(ID_HE, jFrame.getHeight());
666            }
667        }
668        else if (component != null)
669        {
670            preferences.putInt(ID_WC, component.getWidth());
671            preferences.putInt(ID_HC, component.getHeight());
672        }
673    }
674
675    public void saveState()
676    {
677        if (mainFrame != null)
678        {
679            final boolean b;
680
681            if (mainFrame.isDetachedMode())
682                b = mainFrame.getPreviousMaximized();
683            else
684                b = ComponentUtil.isMaximized(mainFrame);
685
686            preferences.putBoolean(ID_MAXIMIZEDE, b);
687        }
688        if (icyFrame != null)
689        {
690            preferences.putBoolean(ID_EXTERNALIZED, icyFrame.isExternalized());
691            preferences.putBoolean(ID_MAXIMIZEDI, icyFrame.isMaximizedInternal());
692            preferences.putBoolean(ID_MAXIMIZEDE, icyFrame.isMaximizedExternal());
693        }
694        else if (extPanel != null)
695        {
696            preferences.putBoolean(ID_PANELIZED, extPanel.isInternalized());
697
698            // get the panel frame
699            final IcyFrame f = extPanel.getFrame();
700
701            preferences.putBoolean(ID_EXTERNALIZED, f.isExternalized());
702            preferences.putBoolean(ID_MAXIMIZEDI, f.isMaximizedInternal());
703            preferences.putBoolean(ID_MAXIMIZEDE, f.isMaximizedExternal());
704        }
705        else if (jFrame != null)
706        {
707            preferences.putBoolean(ID_MAXIMIZEDE, ComponentUtil.isMaximized(jFrame));
708        }
709    }
710
711    public void saveAll()
712    {
713        if (hasLoc)
714            saveLocation();
715        if (hasDim)
716            saveDimension();
717        saveState();
718    }
719}