| FixedSplitPane.java |
1 /**
2 * Distribution License:
3 * JSword is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Lesser General Public License, version 2.1 as published by
5 * the Free Software Foundation. This program is distributed in the hope
6 * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU Lesser General Public License for more details.
9 *
10 * The License is available on the internet at:
11 * http://www.gnu.org/copyleft/lgpl.html
12 * or by writing to:
13 * Free Software Foundation, Inc.
14 * 59 Temple Place - Suite 330
15 * Boston, MA 02111-1307, USA
16 *
17 * Copyright: 2005
18 * The copyright to this program is held by it's authors.
19 *
20 * ID: $Id: FixedSplitPane.java 2050 2010-12-09 15:31:45Z dmsmith $
21 */
22 package org.crosswire.common.swing;
23
24 import java.awt.Component;
25 import java.awt.Dimension;
26
27 import javax.swing.JComponent;
28 import javax.swing.JSplitPane;
29 import javax.swing.border.Border;
30 import javax.swing.border.EmptyBorder;
31 import javax.swing.plaf.SplitPaneUI;
32 import javax.swing.plaf.basic.BasicSplitPaneUI;
33
34 /**
35 * This is a hack to fix the setDividerLocation problem and other layout
36 * problems.
37 * <p>
38 * See Bug Parade 4101306, 4485465 for a description of the WIDE divider
39 * problem.
40 * <p>
41 * Bug Reports on JSplitpane setDividerLocation<br>
42 * 4101306, 4125713, 4148530
43 *<p>
44 * From the javadoc for setDividerLocation(double):
45 * -------------------------------------------<br>
46 * <p>
47 * This method is implemented in terms of setDividerLocation(int). This method
48 * immediately changes the size of the receiver based on its current size. If
49 * the receiver is not correctly realized and on screen, this method will have
50 * no effect (new divider location will become (current size *
51 * proportionalLocation) which is 0).<br>
52 * -------------------------------------------<br>
53 * So, as you can see the JSplitPane MUST be visible invoking this method
54 * otherwise it will not have the desired effect.
55 * <p>
56 * Another, Bug Report 4786896 notes that if the preferred sizes of the two
57 * components plus the divider of the split pane adds up to more than the
58 * preferred size of the JSplitPane, then JSplitPane will use the minimum size
59 * of the components.
60 * <p>
61 * Since the preferred way of managing the sizes of containers is not with pixel
62 * counts, the solution here is to set the preferred size to zero.
63 *
64 * @see gnu.lgpl.License for license details.<br>
65 * The copyright to this program is held by it's authors.
66 * @author DM Smith [dmsmith555 at yahoo dot com]
67 */
68 public class FixedSplitPane extends JSplitPane {
69 /* BUG_PARADE(DMS): many bugs here */
70
71 /**
72 * Constructor for FixedSplitPane
73 */
74 public FixedSplitPane() {
75 }
76
77 /**
78 * Constructor for FixedSplitPane that has no divider shadow and starts out
79 * with an empty border.
80 */
81 public FixedSplitPane(boolean visibleDividerBorder) {
82 this();
83 this.visibleDividerBorder = visibleDividerBorder;
84 setBorder(EMPTY_BORDER);
85 }
86
87 /**
88 * Constructor for FixedSplitPane
89 */
90 public FixedSplitPane(int arg0) {
91 super(arg0);
92 }
93
94 /**
95 * Constructor for FixedSplitPane
96 */
97 public FixedSplitPane(int arg0, boolean arg1) {
98 super(arg0, arg1);
99 }
100
101 /**
102 * Constructor for FixedSplitPane
103 */
104 public FixedSplitPane(int arg0, Component arg1, Component arg2) {
105 super(arg0, arg1, arg2);
106 }
107
108 /**
109 * Constructor for FixedSplitPane
110 */
111 public FixedSplitPane(int arg0, boolean arg1, Component arg2, Component arg3) {
112 super(arg0, arg1, arg2, arg3);
113 }
114
115 /*
116 * (non-Javadoc)
117 *
118 * @see java.awt.Container#addImpl(java.awt.Component, java.lang.Object,
119 * int)
120 */
121 @Override
122 protected void addImpl(Component comp, Object constraints, int index) {
123 if (comp instanceof JComponent) {
124 ((JComponent) comp).setPreferredSize(DOT);
125 }
126 super.addImpl(comp, constraints, index);
127 }
128
129 /*
130 * (non-Javadoc)
131 *
132 * @see javax.swing.JSplitPane#setBottomComponent(java.awt.Component)
133 */
134 @Override
135 public void setBottomComponent(Component comp) {
136 if (comp instanceof JComponent) {
137 ((JComponent) comp).setPreferredSize(DOT);
138 }
139 super.setBottomComponent(comp);
140 }
141
142 /*
143 * (non-Javadoc)
144 *
145 * @see javax.swing.JSplitPane#setLeftComponent(java.awt.Component)
146 */
147 @Override
148 public void setLeftComponent(Component comp) {
149 if (comp instanceof JComponent) {
150 ((JComponent) comp).setPreferredSize(DOT);
151 }
152 super.setLeftComponent(comp);
153 }
154
155 /*
156 * (non-Javadoc)
157 *
158 * @see javax.swing.JSplitPane#setRightComponent(java.awt.Component)
159 */
160 @Override
161 public void setRightComponent(Component comp) {
162 if (comp instanceof JComponent) {
163 ((JComponent) comp).setPreferredSize(DOT);
164 }
165 super.setRightComponent(comp);
166 }
167
168 /*
169 * (non-Javadoc)
170 *
171 * @see javax.swing.JSplitPane#setTopComponent(java.awt.Component)
172 */
173 @Override
174 public void setTopComponent(Component comp) {
175 if (comp instanceof JComponent) {
176 ((JComponent) comp).setPreferredSize(DOT);
177 }
178 super.setTopComponent(comp);
179 }
180
181 /**
182 * Validates this container and all of its subcomponents. The first time
183 * this method is called, the initial divider position is set.
184 */
185 @Override
186 public void validate() {
187 if (firstValidate) {
188 firstValidate = false;
189 if (hasProportionalLocation) {
190 setDividerLocation(proportionalLocation);
191 }
192 }
193 super.validate();
194 }
195
196 /**
197 * Sets the divider location as a percentage of the JSplitPane's size.
198 */
199 @Override
200 public void setDividerLocation(double newProportionalLoc) {
201 if (!firstValidate) {
202 hasProportionalLocation = true;
203 proportionalLocation = newProportionalLoc;
204 } else {
205 super.setDividerLocation(newProportionalLoc);
206 }
207 }
208
209 /**
210 * Whether visible borders are hinted
211 *
212 * @return the divider border visiblity hint
213 */
214 public boolean isVisibleDividerBorder() {
215 return visibleDividerBorder;
216 }
217
218 /**
219 * Set a hint whether the border should be visible or not. Look and feels
220 * may ignore this.
221 *
222 * @param newVisibility
223 */
224 public void setVisibleDividerBorder(boolean newVisibility) {
225 boolean oldVisibility = isVisibleDividerBorder();
226 if (oldVisibility == newVisibility) {
227 return;
228 }
229 visibleDividerBorder = newVisibility;
230 firePropertyChange(PROPERTYNAME_VISIBLE_DIVIDER_BORDER, oldVisibility, newVisibility);
231 }
232
233 /*
234 * (non-Javadoc)
235 *
236 * @see javax.swing.JComponent#updateUI()
237 */
238 @Override
239 public void updateUI() {
240 super.updateUI();
241 if (!visibleDividerBorder) {
242 SplitPaneUI splitPaneUI = getUI();
243 if (splitPaneUI instanceof BasicSplitPaneUI) {
244 BasicSplitPaneUI basicUI = (BasicSplitPaneUI) splitPaneUI;
245 basicUI.getDivider().setBorder(EMPTY_BORDER);
246 }
247 }
248 }
249
250 private static final Dimension DOT = new Dimension(0, 0);
251 private boolean firstValidate = true;
252 private boolean hasProportionalLocation;
253 private double proportionalLocation;
254
255 /**
256 * Property for border visibility
257 */
258 public static final String PROPERTYNAME_VISIBLE_DIVIDER_BORDER = "visibleDividerBorder";
259
260 /**
261 * An Empty Border
262 */
263 private static final Border EMPTY_BORDER = new EmptyBorder(0, 0, 0, 0);
264
265 /**
266 * Hint for whether Divider border should be visible.
267 */
268 private boolean visibleDividerBorder;
269
270 /**
271 * Serialization ID
272 */
273 private static final long serialVersionUID = 3761687909593789241L;
274 }
275