Merge branch 'releases/Release_2_11_4_Branch'
[jalview.git] / 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.util.Platform;
24
25 import java.awt.Component;
26 import java.awt.MouseInfo;
27 import java.awt.Point;
28 import java.awt.Rectangle;
29
30 import javax.swing.JInternalFrame;
31 import javax.swing.JSplitPane;
32 import javax.swing.plaf.basic.BasicInternalFrameUI;
33
34 public class GSplitFrame extends JInternalFrame
35 {
36   protected static final int DIVIDER_SIZE = 5;
37
38   private static final long serialVersionUID = 1L;
39
40   private GAlignFrame topFrame;
41
42   private GAlignFrame bottomFrame;
43
44   private JSplitPane splitPane;
45
46   /*
47    * proportional position of split divider; saving this allows it to be
48    * restored after hiding one half and resizing
49    */
50   private double dividerRatio;
51
52   /**
53    * Constructor
54    * 
55    * @param top
56    * @param bottom
57    */
58   public GSplitFrame(GAlignFrame top, GAlignFrame bottom)
59   {
60     this.topFrame = top;
61     this.bottomFrame = bottom;
62
63     hideTitleBars();
64
65     addSplitPane();
66   }
67
68   /**
69    * Create and add the split pane containing the top and bottom components.
70    */
71   protected void addSplitPane()
72   {
73     splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topFrame,
74             bottomFrame);
75     splitPane.setVisible(true);
76
77     /*
78      * set divider split at 50:50, or restore saved split if loading from
79      * project
80      */
81     int topFrameHeight = topFrame.getHeight();
82     splitPane.setDividerSize(DIVIDER_SIZE);
83     if (topFrameHeight == 0)
84     {
85       setRelativeDividerLocation(0.5d); // as a proportion
86     }
87     else
88     {
89       int dividerPosition = topFrameHeight + DIVIDER_SIZE / 2;
90       splitPane.setDividerLocation(dividerPosition); // absolute position
91     }
92     splitPane.setResizeWeight(0.5d);
93     add(splitPane);
94   }
95
96   /**
97    * Try to hide the title bars as a waste of precious space.
98    * 
99    * @see http
100    *      ://stackoverflow.com/questions/7218971/java-method-works-on-windows
101    *      -but-not-macintosh -java
102    */
103   protected void hideTitleBars()
104   {
105     if (new Platform().isAMac())
106     {
107       // this saves some space - but doesn't hide the title bar
108       topFrame.putClientProperty("JInternalFrame.isPalette", true);
109       // topFrame.getRootPane().putClientProperty("Window.style", "small");
110       bottomFrame.putClientProperty("JInternalFrame.isPalette", true);
111     }
112     else
113     {
114       ((BasicInternalFrameUI) topFrame.getUI()).setNorthPane(null);
115       ((BasicInternalFrameUI) bottomFrame.getUI()).setNorthPane(null);
116     }
117   }
118
119   public GAlignFrame getTopFrame()
120   {
121     return topFrame;
122   }
123
124   public GAlignFrame getBottomFrame()
125   {
126     return bottomFrame;
127   }
128
129   /**
130    * Returns the split pane component the mouse is in, or null if neither.
131    * 
132    * @return
133    */
134   protected GAlignFrame getFrameAtMouse()
135   {
136     Point loc = MouseInfo.getPointerInfo().getLocation();
137
138     if (isIn(loc, splitPane.getTopComponent()))
139     {
140       return getTopFrame();
141     }
142     else if (isIn(loc, splitPane.getBottomComponent()))
143     {
144       return getBottomFrame();
145     }
146     return null;
147   }
148
149   private boolean isIn(Point loc, Component comp)
150   {
151     if (!comp.isVisible())
152     {
153       return false;
154     }
155     Point p = comp.getLocationOnScreen();
156     Rectangle r = new Rectangle(p.x, p.y, comp.getWidth(), comp.getHeight());
157     return r.contains(loc);
158   }
159
160   /**
161    * Makes the complement of the specified split component visible or hidden,
162    * restoring or saving the position of the split divide.
163    */
164   public void setComplementVisible(Object alignFrame, boolean show)
165   {
166     /*
167      * save divider ratio on hide, restore on show
168      */
169     if (show)
170     {
171       setRelativeDividerLocation(dividerRatio);
172     }
173     else
174     {
175       this.dividerRatio = splitPane.getDividerLocation()
176               / (double) (splitPane.getHeight() - splitPane
177                       .getDividerSize());
178     }
179
180     if (alignFrame == this.topFrame)
181     {
182       this.bottomFrame.setVisible(show);
183     }
184     else if (alignFrame == this.bottomFrame)
185     {
186       this.topFrame.setVisible(show);
187     }
188
189     validate();
190   }
191
192   /**
193    * Set the divider location as a proportion (0 <= r <= 1) of the height <br>
194    * Warning: this overloads setDividerLocation(int), and getDividerLocation()
195    * returns the int (pixel count) value
196    * 
197    * @param r
198    */
199   public void setRelativeDividerLocation(double r)
200   {
201     this.dividerRatio = r;
202     splitPane.setDividerLocation(r);
203   }
204
205   /**
206    * Sets the divider location (in pixels from top)
207    * 
208    * @return
209    */
210   protected void setDividerLocation(int p)
211   {
212     splitPane.setDividerLocation(p);
213   }
214
215   /**
216    * Returns the divider location (in pixels from top)
217    * 
218    * @return
219    */
220   protected int getDividerLocation()
221   {
222     return splitPane.getDividerLocation();
223   }
224 }