KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > xam > ui > layout > SplitterLayout


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.xml.xam.ui.layout;
21
22 import java.awt.Component JavaDoc;
23 import java.awt.Container JavaDoc;
24 import java.awt.Dimension JavaDoc;
25 import java.awt.Insets JavaDoc;
26 import java.awt.LayoutManager2 JavaDoc;
27 import java.awt.Rectangle JavaDoc;
28 import javax.swing.JComponent JavaDoc;
29 import javax.swing.JPanel JavaDoc;
30 import javax.swing.JScrollBar JavaDoc;
31 import javax.swing.JScrollPane JavaDoc;
32
33 /**
34  * SplitterLayout is a layout manager that will layout a container holding
35  * other components and SplitterBars.
36  *
37  * <p>Each component added to a container to be laid out using SplitterLayout
38  * must provide a String containing a "weight" for the component. This
39  * weight will be used to determine the initial spacing of all components
40  * being laid out. The weight numbers are arbitrary integers. The
41  * amount of space initially allocated for a component is
42  * <pre>
43  * (wc/wt) * (size-insets-splitterSize)
44  * </pre>
45  * <p>where
46  * <dl>
47  * <dt>wc
48  * <dd>the weight number for the component
49  * <dt>wt
50  * <dd>the total weight of all visible components in the container
51  * <dt>size
52  * <dd>the space free to display the components
53  * <dt>insets
54  * <dd>space used by insets in the container
55  * <dt>splitterSize
56  * <dd>amount of space needed to display SplitterBars
57  * </dl>
58  *
59  * <p>If the container being laid out holds no SplitterBars, SplitterLayout
60  * acts like a relational-weight layout manager. All components are always
61  * laid out based on their proportionate weights.
62  *
63  * <p>If the container being laid out holds some SplitterBars, SplitterLayout
64  * will initially size all non JSplitterBar components based on their weights.
65  * Any succesive layouts are computed strictly on the locations of the
66  * SplitterBars.
67  *
68  * <p>SplitterLayout can be oriented Horizontally or Vertically. Any SpliterBars
69  * placed in the container will automatically be oriented.
70  *
71  * <p>If a JSplitterBar has been modified (adding components to it) you will
72  * need to add JSplitterSpace components to it. See JSplitterBar for more
73  * details.
74  *
75  * <p><b>Known Problems</b>:
76  * <ul>
77  * <li>If there are any SplitterBars contained in the container,
78  * it is best to have them between <u>every</u> non-JSplitterBar.
79  * Otherwise, once SplitterBars are moved, some components will
80  * use their proportional size while others will use the
81  * JSplitterBar positions. (Non-Splitterbars will check the next
82  * component to see if it's a JSplitterBar. If it's not, it uses
83  * its proportional size.) This may eventually be changed...
84  * <li>Results of adding new SplitterBars to an existing (and user-
85  * interacted) SplitterLayout-laid container might be a bit
86  * unpredictable. The safest way to ensure the container is laid
87  * out correctly would be to explicitly set all pre-existing
88  * JSplitterBar positions to (0,0). This will cause the relational
89  * layout algorithm to take effect.
90  * </ul>
91  *
92  * <p>Use this code at your own risk! MageLang Institute is not
93  * responsible for any damage caused directly or indirctly through
94  * use of this code.
95  * <p><p>
96  * <b>SOFTWARE RIGHTS</b>
97  * <p>
98  * MageLang support classes, version 1.0, MageLang Institute
99  * <p>
100  * We reserve no legal rights to this code--it is fully in the
101  * public domain. An individual or company may do whatever
102  * they wish with source code distributed with it, including
103  * including the incorporation of it into commerical software.
104  *
105  * <p>However, this code cannot be sold as a standalone product.
106  * <p>
107  * We encourage users to develop software with this code. However,
108  * we do ask that credit is given to us for developing it
109  * By "credit", we mean that if you use these components or
110  * incorporate any source code into one of your programs
111  * (commercial product, research project, or otherwise) that
112  * you acknowledge this fact somewhere in the documentation,
113  * research report, etc... If you like these components and have
114  * developed a nice tool with the output, please mention that
115  * you developed it using these components. In addition, we ask that
116  * the headers remain intact in our source code. As long as these
117  * guidelines are kept, we expect to continue enhancing this
118  * system and expect to make other tools available as they are
119  * completed.
120  * <p>
121  * The MageLang Support Classes Gang:
122  * @version MageLang Support Classes 1.0, MageLang Insitute, 1997
123  * @author <a HREF="http:www.scruz.net/~thetick">Scott Stanchfield</a>, <a HREF=http://www.MageLang.com>MageLang Institute</a>
124  * @see JSplitterBar
125  * @see JSplitterSpace
126  *
127  * @author Jeri Lockhart - jeri.lockhart@sun.com
128  * Modified for use in the NbColumnView widget.
129  * When the user moves the splitter bar to the left, the column that is adjacent to the
130  * left maintains its minimum size.
131  * When the user moves the splitter bar to the right, the columns to the right of the
132  * splitter bar, maintain their widths.
133  *
134  * layoutComponent() - can be called when the components in the container
135  * do not yet have their bounds set. In this case, use the component's
136  * preferred size. JSplitterBar can set the bounds of the components
137  * when the user drags a splitter bar. If the bounds for a component
138  * are set, use this size.
139  *
140  * checkLayoutSize() - is called for both preferredLayoutSize() and
141  * minimumLayoutSize(). To calculate the width of the layout, uses the
142  * actual width of the component, if present, or uses the preferred width
143  * of the component.
144  *
145  */

146 public class SplitterLayout implements LayoutManager2 JavaDoc, java.io.Serializable JavaDoc {
147     /** Aligns components vertically -- SplitterBars will move up/down */
148     public static final int VERTICAL = 0;
149     /** Aligns components horizontally -- SplitterBars will move left-right */
150     public static final int HORIZONTAL = 1;
151     
152     static JSplitterBar dragee;
153     
154     private int lastW=-1, lastH=-1;
155     private boolean newComponentAdded;
156     
157     private static final long serialVersionUID = -8658291919501921765L;
158     private boolean fill = true; // false - use preferred size,
159
// instead of weights
160
private Dimension JavaDoc originalPreferredSize;
161     
162     
163     public SplitterLayout() {
164     }
165     
166     /** Create a new SplitterLayout
167      * @param orientation -- VERTICAL or HORIZONTAL
168      * @param fill - expand to fill target or use preferred size of components
169      */

170     public SplitterLayout( boolean fill) {
171         setFill(fill);
172     }
173     /** Adds a component w/ constraints to the layout. This should only
174      * be called by java.awt.Container's add method.
175      */

176     public final void addLayoutComponent(Component JavaDoc comp, Object JavaDoc constraints) {
177 // //System.out.println("addLayoutContainer(Component, Object) comp " + comp + ", constraints " + constraints);
178
if (constraints == null) constraints = "1";
179         if (constraints instanceof Integer JavaDoc) {
180             newComponentAdded = true;
181         } else
182             addLayoutComponent((String JavaDoc)constraints, comp);
183     }
184     /** Adds a component w/ a String constraint to the layout. This should
185      * only be called by java.awt.Container's add method.
186      */

187     public final void addLayoutComponent(String JavaDoc name, Component JavaDoc comp) {
188 // //System.out.println("addLayoutComponent(String, Component) name " + name + ", comp "+ comp);
189
newComponentAdded = true;
190                 
191     }
192     
193     
194     // preferred and min layout size
195
public final Dimension JavaDoc checkLayoutSize(Container JavaDoc target, boolean getPrefSize) {
196 // //System.out.println("checkLayoutSize getPrefSize: " + getPrefSize);
197
Dimension JavaDoc dim = new Dimension JavaDoc(0, 0);
198         Component JavaDoc c[] = target.getComponents();
199         
200         Dimension JavaDoc d = null;
201         for(int i = 0; i < c.length; i++) {
202             if (c[i].isVisible()) {
203                 if (getPrefSize || (c[i] instanceof JSplitterBar)) {
204                     d = c[i].getPreferredSize();
205                 }
206                 else {
207                     d = c[i].getMinimumSize();
208                 }
209                 dim.height = Math.max(d.height, dim.height);
210                 dim.width += d.width;
211 // //System.out.println("checkLayoutSize comp #" + i + " d.height: " + d.height + ", dim.height: " + dim.height);
212
// //System.out.println("checkLayoutSize comp #" + i + " d.width: " + d.width + ", dim.width: " + dim.width);
213
}
214         }
215         
216         Insets JavaDoc insets = target.getInsets();
217 // //System.out.println("checkLayoutSize insets " + insets);
218
dim.width += insets.left + insets.right;
219         dim.height += insets.top + insets.bottom;
220 // //System.out.println("checkLayoutSize returning dim " + dim);
221
return dim;
222     }
223     /** Tells the caller that we prefer to be centered */
224     public final float getLayoutAlignmentX(Container JavaDoc parent) {return 0.5f;}
225     /** Tells the caller that we prefer to be centered */
226     public final float getLayoutAlignmentY(Container JavaDoc parent) {return 0.5f;}
227     /** Does not have any effect (overridden to null the effect) */
228     public final void invalidateLayout(Container JavaDoc target) {}
229     
230     
231     
232     /** Lays out the components in the specified container by telling
233      * them what their size will be
234      */

235     public final void layoutContainer(Container JavaDoc target) {
236 // //System.out.println("layoutContainer start");
237
//System.out.println("layoutContainer target start preferred size " + target.getPreferredSize());
238
if (originalPreferredSize == null){ // save it the first time
239
originalPreferredSize = target.getPreferredSize();
240             }
241 // Thread.dumpStack();
242
Component JavaDoc c[] = target.getComponents();
243         Insets JavaDoc insets = target.getInsets();
244         Dimension JavaDoc dim = target.getSize();
245 // //System.out.println("layoutContainer target original size " + dim);
246
int top = insets.top;
247         int bottom = dim.height - insets.bottom;
248         int left = insets.left;
249         int right = dim.width - insets.right;
250         
251         boolean reScaleW = false, reScaleH=false;
252 // float scaleW = 0, scaleH = 0;
253

254         // if the width/height has changed, scale the splitter bar positions
255
// //System.out.println("layoutContainer lastW "+ lastW + ", dim.width " + dim.width);
256
// //System.out.println("layoutContainer lastH "+ lastH + ", dim.height " + dim.height);
257
if (lastW == -1) { // save it the first time
258
lastW = dim.width;
259             lastH = dim.height;
260         } else {
261             if (lastW != dim.width) {
262                 reScaleW = true;
263 // scaleW = (float)dim.width/(float)lastW;
264
// //System.out.println("layoutContainer scaleW "+ scaleW);
265
lastW = dim.width;
266             }
267             if (lastH != dim.height) {
268                 reScaleH = true;
269 // scaleH = (float)dim.height/(float)lastH;
270
// //System.out.println("layoutContainer scaleH "+ scaleH);
271
lastH = dim.height;
272             }
273         }
274 // //System.out.println("layoutContainer reScaleW " + reScaleW);
275
// //System.out.println("layoutContainer reScaleH " + reScaleH);
276

277         dim.width = right - left;
278         dim.height = bottom - top;
279         
280         
281         int x = left;
282         int y = top;
283         for(int i = 0; i < c.length; i++) {
284 // //System.out.println("layoutContainer bounds " + i + " " + c[i].getBounds());
285
// //System.out.println("layoutContainer pref size " + i + " " + c[i].getPreferredSize());
286
// //System.out.println("layoutContainer " + i + " is visible " + c[i].isVisible());
287
if (c[i].isVisible()) {
288 // if (c[i] instanceof JSplitterBar) {
289
// if (reScaleW) {
290
// //System.out.println("layoutContainer reScaleW");
291
// Point p = c[i].getLocation();
292
// c[i].setLocation((int)(((float)p.x)*scaleW),p.y); // dims set later
293
// //System.out.println("layoutContainer setLocation " + i + " " + c[i].getLocation());
294
// }
295
// }
296

297                 // if the component hasn't been sized, use it's preferred size, else use its bounds
298
Dimension JavaDoc prefD = c[i].getPreferredSize();
299                 Dimension JavaDoc size = c[i].getSize();
300                 if (size.width == 0){
301                     c[i].setBounds(x, y, prefD.width, dim.height);
302                     x += prefD.width;
303                 }
304                 else {
305                                     // get the ColumnView height
306
Container JavaDoc scrollpane = target.getParent().getParent();
307                                     Container JavaDoc cv = scrollpane.getParent();
308                                     int cvHeight = 0;
309 // int vBarWidth = 0;
310
if (cv instanceof JPanel JavaDoc){
311                                         cvHeight = cv.getSize().height;
312                                         
313                                     }
314                                     if (scrollpane instanceof JScrollPane JavaDoc){
315                                         JScrollBar JavaDoc hBar = ((JScrollPane JavaDoc)scrollpane).getHorizontalScrollBar();
316                                         //System.out.println("layoutContainer hBar isVisible " + hBar.isVisible());
317
// JScrollBar vBar = ((JScrollPane)scrollpane).getVerticalScrollBar();
318
if (hBar.isVisible()){
319                                             cvHeight -= hBar.getHeight();
320                                         }
321 // if (vBar.isVisible()){
322
// //System.out.println("layoutContainer vBar isVisible " + vBar.isVisible());
323
// vBarWidth = vBar.getWidth();
324
// }
325
}
326                     c[i].setBounds(x, y, size.width, cvHeight-2);
327 // c[i].setBounds(x, y, size.width, dim.height);
328
x += size.width;
329                 }
330                                 
331 // //System.out.println("layoutContainer new bounds " + i + " " + c[i].getBounds());
332
}
333         }
334         
335                 // set new width for container if it's too small
336
// or if the total width of the components is smaller
337
// than the container (because columns have been removed)
338
Rectangle JavaDoc lastComp = c[c.length-1].getBounds();
339                 int totalCompsWidth = lastComp.x + lastComp.width;
340                 Dimension JavaDoc targetSize = target.getSize();
341                 //System.out.println("layoutContainer target size " + target.getSize());
342
//System.out.println("layoutContainer target pref size " + target.getPreferredSize());
343
//System.out.println("layoutContainer lastComp height "+ lastComp.height);
344
//System.out.println("layoutContainer target height "+ targetSize.height);
345
if (!(targetSize.width == totalCompsWidth && targetSize.height == lastComp.height)){
346                     target.setPreferredSize(new Dimension JavaDoc(totalCompsWidth, lastComp.height));
347                     if (target instanceof JComponent JavaDoc){
348                         ((JComponent JavaDoc)target).revalidate();
349                     }
350                 }
351                 //System.out.println("layoutContainer end preferred size " + target.getPreferredSize());
352
newComponentAdded = false;
353     }
354     /** Determines the maximum amount of space that could be used
355      * when laying out the components in the specified container.
356      * @param -- the container being laid out
357      */

358     public final Dimension JavaDoc maximumLayoutSize(Container JavaDoc target) {
359 // //System.out.println("maximumLayoutSize ");
360
return new Dimension JavaDoc(Integer.MAX_VALUE, Integer.MAX_VALUE);
361     }
362     /** Determines the minimum amount of room requested for the layout
363      * of components contained in the specified container.
364      * @param target -- the Container being laid out
365      */

366 // public final Dimension minimumLayoutSize(Container target) {return checkLayoutSize(target, false);}
367
public final Dimension JavaDoc minimumLayoutSize(Container JavaDoc target) {
368 // //System.out.println("minimumLayoutSize");
369
return checkLayoutSize(target, true);
370     }
371     // TEMP -- CHECK TO SEE HOW minsize==prefsize seems
372

373     /** Determines the preferred amount of room requested for the layout
374      * of components contained in the specified container.
375      * @param target -- the Container being laid out
376      */

377     public final Dimension JavaDoc preferredLayoutSize(Container JavaDoc target) {
378 // //System.out.println("preferredLayoutSize");
379
return checkLayoutSize(target, true);
380     }
381     /** Removes a component from the layout. This should
382      * only be called by java.awt.Container's remove method.
383      */

384     public final void removeLayoutComponent(Component JavaDoc comp) {
385         newComponentAdded = true; // so layout gets re-adjusted
386
}
387     
388     /**
389      *
390      *
391      */

392     public void setFill(boolean fill){
393         this.fill = fill;
394     }
395     
396     
397     
398     /**
399      *
400      *
401      */

402     public boolean getFill( ){
403         return this.fill;
404     }
405     
406     
407     /** Returns a String representation of the Layout */
408     public final String JavaDoc toString() {
409         return getClass().getName();
410     }
411 }
412
Popular Tags