JAL-3253-applet headless branch - just experimenting.
[jalview.git] / src / jalview / jbgui / GSplitFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.jbgui;
22
23 import jalview.bin.Jalview;
24 import jalview.util.Platform;
25
26 import java.awt.Component;
27 import java.awt.MouseInfo;
28 import java.awt.Point;
29 import java.awt.Rectangle;
30
31 import javax.swing.JInternalFrame;
32 import javax.swing.JSplitPane;
33 import javax.swing.plaf.basic.BasicInternalFrameUI;
34
35 public class GSplitFrame extends JInternalFrame
36 {
37   protected static final int DIVIDER_SIZE = 5;
38
39   private static final long serialVersionUID = 1L;
40
41   private GAlignFrame topFrame;
42
43   private GAlignFrame bottomFrame;
44
45   private JSplitPane splitPane;
46
47   /*
48    * proportional position of split divider; saving this allows it to be
49    * restored after hiding one half and resizing
50    */
51   private double dividerRatio;
52
53   /**
54    * Constructor
55    * 
56    * @param top
57    * @param bottom
58    */
59   public GSplitFrame(GAlignFrame top, GAlignFrame bottom)
60   {
61     setName(Jalview.getAppID("splitframe"));
62     this.topFrame = top;
63     this.bottomFrame = bottom;
64
65     hideTitleBars();
66
67     addSplitPane();
68   }
69
70   /**
71    * Create and add the split pane containing the top and bottom components.
72    */
73   protected void addSplitPane()
74   {
75     splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topFrame.getIFrame(),
76             bottomFrame.getIFrame());
77     splitPane.setVisible(true);
78
79     /*
80      * set divider split at 50:50, or restore saved split if loading from
81      * project
82      */
83     int topFrameHeight = topFrame.getIFrame().getHeight();
84     splitPane.setDividerSize(DIVIDER_SIZE);
85     if (topFrameHeight == 0)
86     {
87       setRelativeDividerLocation(0.5d); // as a proportion
88     }
89     else
90     {
91       int dividerPosition = topFrameHeight + DIVIDER_SIZE / 2;
92       splitPane.setDividerLocation(dividerPosition); // absolute position
93     }
94     splitPane.setResizeWeight(0.5d);
95     add(splitPane);
96   }
97
98   /**
99    * Try to hide the title bars as a waste of precious space.
100    * 
101    * @see http
102    *      ://stackoverflow.com/questions/7218971/java-method-works-on-windows
103    *      -but-not-macintosh -java
104    */
105   protected void hideTitleBars()
106   {
107     if (Platform.isAMacAndNotJS())
108     {
109       // this saves some space - but doesn't hide the title bar
110       topFrame.getIFrame().putClientProperty("JInternalFrame.isPalette", true);
111       // topFrame.getRootPane().putClientProperty("Window.style", "small");
112       bottomFrame.getIFrame().putClientProperty("JInternalFrame.isPalette",
113               true);
114     }
115     else
116     {
117       ((BasicInternalFrameUI) topFrame.getIFrame().getUI())
118               .setNorthPane(null);
119       ((BasicInternalFrameUI) bottomFrame.getIFrame().getUI())
120               .setNorthPane(null);
121     }
122   }
123
124   public GAlignFrame getTopFrame()
125   {
126     return topFrame;
127   }
128
129   public GAlignFrame getBottomFrame()
130   {
131     return bottomFrame;
132   }
133
134   /**
135    * Returns the split pane component the mouse is in, or null if neither.
136    * 
137    * @return
138    */
139   protected GAlignFrame getFrameAtMouse()
140   {
141     Point loc = MouseInfo.getPointerInfo().getLocation();
142
143     if (isIn(loc, splitPane.getTopComponent()))
144     {
145       return getTopFrame();
146     }
147     else if (isIn(loc, splitPane.getBottomComponent()))
148     {
149       return getBottomFrame();
150     }
151     return null;
152   }
153
154   private boolean isIn(Point loc, Component comp)
155   {
156     if (!comp.isVisible())
157     {
158       return false;
159     }
160     Point p = comp.getLocationOnScreen();
161     Rectangle r = new Rectangle(p.x, p.y, comp.getWidth(),
162             comp.getHeight());
163     return r.contains(loc);
164   }
165
166   /**
167    * Makes the complement of the specified split component visible or hidden,
168    * restoring or saving the position of the split divide.
169    */
170   public void setComplementVisible(Object alignFrame, boolean show)
171   {
172     /*
173      * save divider ratio on hide, restore on show
174      */
175     if (show)
176     {
177       setRelativeDividerLocation(dividerRatio);
178     }
179     else
180     {
181       this.dividerRatio = splitPane.getDividerLocation()
182               / (double) (splitPane.getHeight()
183                       - splitPane.getDividerSize());
184     }
185
186     if (alignFrame == this.topFrame)
187     {
188       this.bottomFrame.setVisible(show);
189     }
190     else if (alignFrame == this.bottomFrame)
191     {
192       this.topFrame.setVisible(show);
193     }
194
195     validate();
196   }
197
198   /**
199    * Set the divider location as a proportion (0 <= r <= 1) of the height <br>
200    * Warning: this overloads setDividerLocation(int), and getDividerLocation()
201    * returns the int (pixel count) value
202    * 
203    * @param r
204    */
205   public void setRelativeDividerLocation(double r)
206   {
207     this.dividerRatio = r;
208     splitPane.setDividerLocation(r);
209   }
210
211   /**
212    * Sets the divider location (in pixels from top)
213    * 
214    * @return
215    */
216   protected void setDividerLocation(int p)
217   {
218     splitPane.setDividerLocation(p);
219   }
220
221   /**
222    * Returns the divider location (in pixels from top)
223    * 
224    * @return
225    */
226   protected int getDividerLocation()
227   {
228     return splitPane.getDividerLocation();
229   }
230 }