001: /*
002: * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
003: *
004: * http://izpack.org/
005: * http://izpack.codehaus.org/
006: *
007: * Copyright 2002 Elmar Grom
008: *
009: * Licensed under the Apache License, Version 2.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.apache.org/licenses/LICENSE-2.0
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: */
021:
022: package com.izforge.izpack.gui;
023:
024: import java.awt.Component;
025: import java.awt.Container;
026: import java.awt.Dimension;
027: import java.awt.Insets;
028: import java.awt.LayoutManager;
029:
030: /*---------------------------------------------------------------------------*/
031: /**
032: * A flow layout arranges components in a left-to-right flow, much like lines of text in a
033: * paragraph. Flow layouts are typically used to arrange buttons in a panel. It will arrange buttons
034: * left to right until no more buttons fit on the same line. Each line is centered.
035: * <p>
036: * For example, the following picture shows an applet using the flow layout manager (its default
037: * layout manager) to position three buttons:
038: * <p>
039: * <img src="doc-files/FlowLayout-1.gif" ALT="Graphic of Layout for Three Buttons" ALIGN=center
040: * HSPACE=10 VSPACE=7>
041: * <p>
042: * Here is the code for this applet:
043: * <p>
044: * <hr>
045: * <blockquote>
046: *
047: * <pre>
048: * import java.awt.*;
049: * import java.applet.Applet;
050: *
051: * public class myButtons extends Applet
052: * {
053: *
054: * Button button1, button2, button3;
055: *
056: * public void init()
057: * {
058: * button1 = new Button("Ok");
059: * button2 = new Button("Open");
060: * button3 = new Button("Close");
061: * add(button1);
062: * add(button2);
063: * add(button3);
064: * }
065: * }
066: *
067: * </pre>
068: *
069: * </blockquote>
070: * <hr>
071: * <p>
072: * A flow layout lets each component assume its natural (preferred) size.
073: *
074: * This class is a bit different from java.awt.FlowLayout. <blockquote> java.awt.FlowLayout has a
075: * minor problem that was bugging me when I wrote the UserInputPanel. FlowLayout puts some amount of
076: * space in between each component that it lays out. In addition it adds that same amount of space
077: * to the left and to the right of the entire group. Therefore items such as the RuleInputfield that
078: * are laid out with a FlowLayout would never line up properly with the other components (it would
079: * appear to be slightly indented). Because there is no way to circumvent this behavior in
080: * FlowLayout (it's hard coded) I copied the source and modified it so that it does not add the
081: * space to the left and to the right. Now my stuff lines up properly. (Elmar Grom)</blockquote>
082: *
083: * @version 1.39, 11/29/02
084: * @author Arthur van Hoff
085: * @author Sami Shaio
086: * @author Elmar Grom
087: */
088: /*---------------------------------------------------------------------------*/
089: public class FlowLayout implements LayoutManager {
090:
091: /**
092: * This value indicates that each row of components should be left-justified.
093: */
094: public static final int LEFT = 0;
095:
096: /**
097: * This value indicates that each row of components should be centered.
098: */
099: public static final int CENTER = 1;
100:
101: /**
102: * This value indicates that each row of components should be right-justified.
103: */
104: public static final int RIGHT = 2;
105:
106: /**
107: * This value indicates that each row of components should be justified to the leading edge of
108: * the container's orientation, for example, to the left in left-to-right orientations.
109: *
110: * @see java.awt.Component#getComponentOrientation
111: * @see java.awt.ComponentOrientation
112: * @since 1.2 Package-private pending API change approval
113: */
114: public static final int LEADING = 3;
115:
116: /**
117: * This value indicates that each row of components should be justified to the leading edge of
118: * the container's orientation, for example, to the right in left-to-right orientations.
119: *
120: * @see java.awt.Component#getComponentOrientation
121: * @see java.awt.ComponentOrientation
122: * @since 1.2 Package-private pending API change approval
123: */
124: public static final int TRAILING = 4;
125:
126: /**
127: * <code>align</code> is the proprty that determines how each row distributes empty space. It
128: * can be one of the following three values : <code>LEFT</code>
129: * <code>RIGHT</code>
130: * <code>CENTER</code>
131: *
132: * @serial
133: * @see #getAlignment
134: * @see #setAlignment
135: */
136: int align; // This is for 1.1 serialization compatibilitys
137:
138: /**
139: * <code>newAlign</code> is the property that determines how each row distributes empty space
140: * for the Java 2 platform, v1.2 and greater. It can be one of the following three values :
141: * <code>LEFT</code>
142: * <code>RIGHT</code>
143: * <code>CENTER</code>
144: *
145: * @serial
146: * @since 1.2
147: * @see #getAlignment
148: * @see #setAlignment
149: */
150: int newAlign; // This is the one we actually use
151:
152: /**
153: * The flow layout manager allows a seperation of components with gaps. The horizontal gap will
154: * specify the space between components.
155: *
156: * @serial
157: * @see #getHgap
158: * @see #setHgap
159: */
160: int hgap;
161:
162: /**
163: * The flow layout manager allows a seperation of components with gaps. The vertical gap will
164: * specify the space between rows.
165: *
166: * @serial
167: * @see #getVgap
168: * @see #setVgap
169: */
170: int vgap;
171:
172: /*--------------------------------------------------------------------------*/
173: /**
174: * Constructs a new Flow Layout with a centered alignment and a default 5-unit horizontal and
175: * vertical gap.
176: */
177: /*--------------------------------------------------------------------------*/
178: public FlowLayout() {
179: this (CENTER, 5, 5);
180: }
181:
182: /*--------------------------------------------------------------------------*/
183: /**
184: * Constructs a new Flow Layout with the specified alignment and a default 5-unit horizontal and
185: * vertical gap. The value of the alignment argument must be one of <code>FlowLayout.LEFT</code>,
186: * <code>FlowLayout.RIGHT</code>, or <code>FlowLayout.CENTER</code>.
187: *
188: * @param align the alignment value
189: */
190: /*--------------------------------------------------------------------------*/
191: public FlowLayout(int align) {
192: this (align, 5, 5);
193: }
194:
195: /*--------------------------------------------------------------------------*/
196: /**
197: * Creates a new flow layout manager with the indicated alignment and the indicated horizontal
198: * and vertical gaps.
199: * <p>
200: * The value of the alignment argument must be one of <code>FlowLayout.LEFT</code>,
201: * <code>FlowLayout.RIGHT</code>, or <code>FlowLayout.CENTER</code>.
202: *
203: * @param align the alignment value.
204: * @param hgap the horizontal gap between components.
205: * @param vgap the vertical gap between components.
206: */
207: /*--------------------------------------------------------------------------*/
208: public FlowLayout(int align, int hgap, int vgap) {
209: this .hgap = hgap;
210: this .vgap = vgap;
211: setAlignment(align);
212: }
213:
214: /*--------------------------------------------------------------------------*/
215: /**
216: * Gets the alignment for this layout. Possible values are <code>FlowLayout.LEFT</code>,
217: * <code>FlowLayout.RIGHT</code>, or <code>FlowLayout.CENTER</code>.
218: *
219: * @return the alignment value for this layout.
220: *
221: * @see java.awt.FlowLayout#setAlignment
222: */
223: /*--------------------------------------------------------------------------*/
224: public int getAlignment() {
225: return (newAlign);
226: }
227:
228: /*--------------------------------------------------------------------------*/
229: /**
230: * Sets the alignment for this layout. Possible values are <code>FlowLayout.LEFT</code>,
231: * <code>FlowLayout.RIGHT</code>, and <code>FlowLayout.CENTER</code>.
232: *
233: * @param align the alignment value.
234: *
235: * @see #getAlignment()
236: */
237: /*--------------------------------------------------------------------------*/
238: public void setAlignment(int align) {
239: this .newAlign = align;
240:
241: // this.align is used only for serialization compatibility,
242: // so set it to a value compatible with the 1.1 version
243: // of the class
244:
245: switch (align) {
246: case LEADING:
247: this .align = LEFT;
248: break;
249: case TRAILING:
250: this .align = RIGHT;
251: break;
252: default:
253: this .align = align;
254: break;
255: }
256: }
257:
258: /*--------------------------------------------------------------------------*/
259: /**
260: * Gets the horizontal gap between components.
261: *
262: * @return the horizontal gap between components.
263: *
264: * @see #setHgap(int)
265: */
266: /*--------------------------------------------------------------------------*/
267: public int getHgap() {
268: return (hgap);
269: }
270:
271: /*--------------------------------------------------------------------------*/
272: /**
273: * Sets the horizontal gap between components.
274: *
275: * @param hgap the horizontal gap between components
276: *
277: * @see #getHgap()
278: */
279: /*--------------------------------------------------------------------------*/
280: public void setHgap(int hgap) {
281: this .hgap = hgap;
282: }
283:
284: /*--------------------------------------------------------------------------*/
285: /**
286: * Gets the vertical gap between components.
287: *
288: * @return the vertical gap between components.\
289: *
290: * @see #setVgap(int)
291: */
292: /*--------------------------------------------------------------------------*/
293: public int getVgap() {
294: return (vgap);
295: }
296:
297: /*--------------------------------------------------------------------------*/
298: /**
299: * Sets the vertical gap between components.
300: *
301: * @param vgap the vertical gap between components
302: *
303: * @see #getVgap()
304: */
305: /*--------------------------------------------------------------------------*/
306: public void setVgap(int vgap) {
307: this .vgap = vgap;
308: }
309:
310: /*--------------------------------------------------------------------------*/
311: /**
312: * Adds the specified component to the layout. Not used by this class.
313: *
314: * @param name the name of the component
315: * @param comp the component to be added
316: */
317: /*--------------------------------------------------------------------------*/
318: public void addLayoutComponent(String name, Component comp) {
319: }
320:
321: /*--------------------------------------------------------------------------*/
322: /**
323: * Removes the specified component from the layout. Not used by this class.
324: *
325: * @param comp the component to remove
326: *
327: */
328: /*--------------------------------------------------------------------------*/
329: public void removeLayoutComponent(Component comp) {
330: }
331:
332: /*--------------------------------------------------------------------------*/
333: /**
334: * Returns the preferred dimensions for this layout given the components in the specified target
335: * container.
336: *
337: * @param target the component which needs to be laid out
338: *
339: * @return the preferred dimensions to lay out the subcomponents of the specified container.
340: * @see #minimumLayoutSize(Container)
341: */
342: /*--------------------------------------------------------------------------*/
343: public Dimension preferredLayoutSize(Container target) {
344: synchronized (target.getTreeLock()) {
345: Dimension dim = new Dimension(0, 0);
346: int nmembers = target.getComponentCount();
347: boolean firstVisibleComponent = true;
348:
349: for (int i = 0; i < nmembers; i++) {
350: Component m = target.getComponent(i);
351: if (m.isVisible()) {
352: Dimension d = m.getPreferredSize();
353: dim.height = Math.max(dim.height, d.height);
354: if (firstVisibleComponent) {
355: firstVisibleComponent = false;
356: } else {
357: dim.width += hgap;
358: }
359: dim.width += d.width;
360: }
361: }
362:
363: Insets insets = target.getInsets();
364: dim.width += insets.left + insets.right + hgap * 2;
365: dim.height += insets.top + insets.bottom + vgap * 2;
366:
367: return (dim);
368: }
369: }
370:
371: /*--------------------------------------------------------------------------*/
372: /**
373: * Returns the minimum dimensions needed to layout the components contained in the specified
374: * target container.
375: *
376: * @param target the component which needs to be laid out
377: *
378: * @return the minimum dimensions to lay out the subcomponents of the specified container.
379: *
380: * @see #preferredLayoutSize(Container)
381: */
382: /*--------------------------------------------------------------------------*/
383: public Dimension minimumLayoutSize(Container target) {
384: synchronized (target.getTreeLock()) {
385: Dimension dim = new Dimension(0, 0);
386: int nmembers = target.getComponentCount();
387:
388: for (int i = 0; i < nmembers; i++) {
389: Component m = target.getComponent(i);
390: if (m.isVisible()) {
391: Dimension d = m.getMinimumSize();
392: dim.height = Math.max(dim.height, d.height);
393: if (i > 0) {
394: dim.width += hgap;
395: }
396: dim.width += d.width;
397: }
398: }
399:
400: Insets insets = target.getInsets();
401: dim.width += insets.left + insets.right + hgap * 2;
402: dim.height += insets.top + insets.bottom + vgap * 2;
403:
404: return (dim);
405: }
406: }
407:
408: /*--------------------------------------------------------------------------*/
409: /**
410: * Centers the elements in the specified row, if there is any slack.
411: *
412: * @param target the component which needs to be moved
413: * @param x the x coordinate
414: * @param y the y coordinate
415: * @param width the width dimensions
416: * @param height the height dimensions
417: * @param rowStart the beginning of the row
418: * @param rowEnd the the ending of the row
419: */
420: /*--------------------------------------------------------------------------*/
421: private void moveComponents(Container target, int x, int y,
422: int width, int height, int rowStart, int rowEnd, boolean ltr) {
423: synchronized (target.getTreeLock()) {
424: switch (newAlign) {
425: case LEFT:
426: x += ltr ? 0 : width;
427: break;
428: case CENTER:
429: x += width / 2;
430: break;
431: case RIGHT:
432: x += ltr ? width : 0;
433: break;
434: case LEADING:
435: break;
436: case TRAILING:
437: x += width;
438: break;
439: }
440:
441: for (int i = rowStart; i < rowEnd; i++) {
442: Component m = target.getComponent(i);
443:
444: if (m.isVisible()) {
445: if (ltr) {
446: m.setLocation(x, y
447: + (height - m.getSize().height) / 2);
448: } else {
449: m.setLocation(target.getSize().width - x
450: - m.getSize().width, y
451: + (height - m.getSize().height) / 2);
452: }
453:
454: x += m.getSize().width + hgap;
455: }
456: }
457: }
458: }
459:
460: /*--------------------------------------------------------------------------*/
461: /**
462: * Lays out the container. This method lets each component take its preferred size by reshaping
463: * the components in the target container in order to satisfy the constraints of this
464: * <code>FlowLayout</code> object.
465: *
466: * @param target the specified component being laid out.
467: *
468: */
469: /*--------------------------------------------------------------------------*/
470: public void layoutContainer(Container target) {
471: synchronized (target.getTreeLock()) {
472: Insets insets = target.getInsets();
473: int maxWidth = target.getSize().width
474: - (insets.left + insets.right + hgap * 2);
475: int nMembers = target.getComponentCount();
476: int x = 0;
477: int y = insets.top + vgap;
478: int rowh = 0;
479: int start = 0;
480:
481: boolean ltr = target.getComponentOrientation()
482: .isLeftToRight();
483:
484: for (int i = 0; i < nMembers; i++) {
485: Component m = target.getComponent(i);
486:
487: if (m.isVisible()) {
488: Dimension d = m.getPreferredSize();
489: m.setSize(d.width, d.height);
490:
491: if ((x == 0) || ((x + d.width) <= maxWidth)) {
492: if (x > 0) {
493: x += hgap;
494: }
495: x += d.width;
496: rowh = Math.max(rowh, d.height);
497: } else {
498: moveComponents(target, insets.left, y, maxWidth
499: - x, rowh, start, i, ltr);
500: x = d.width;
501: y += vgap + rowh;
502: rowh = d.height;
503: start = i;
504: }
505: }
506: }
507:
508: moveComponents(target, insets.left, y, maxWidth - x, rowh,
509: start, nMembers, ltr);
510: }
511: }
512:
513: /*--------------------------------------------------------------------------*/
514: /**
515: * Returns a string representation of this <code>FlowLayout</code> object and its values.
516: *
517: * @return a string representation of this layout.
518: */
519: /*--------------------------------------------------------------------------*/
520: public String toString() {
521: String str = "";
522:
523: switch (align) {
524: case LEFT:
525: str = ",align=left";
526: break;
527: case CENTER:
528: str = ",align=center";
529: break;
530: case RIGHT:
531: str = ",align=right";
532: break;
533: case LEADING:
534: str = ",align=leading";
535: break;
536: case TRAILING:
537: str = ",align=trailing";
538: break;
539: }
540:
541: return (getClass().getName() + "[hgap=" + hgap + ",vgap="
542: + vgap + str + "]");
543: }
544: }
545: /*---------------------------------------------------------------------------*/
|