1 package be
.nikiroo
.utils
.ui
;
3 import java
.awt
.Component
;
4 import java
.awt
.Container
;
5 import java
.awt
.Dimension
;
6 import java
.awt
.FlowLayout
;
7 import java
.awt
.Insets
;
9 import javax
.swing
.JScrollPane
;
10 import javax
.swing
.SwingUtilities
;
13 * FlowLayout subclass that fully supports wrapping of components.
15 * @author https://tips4java.wordpress.com/2008/11/06/wrap-layout/
17 public class WrapLayout
extends FlowLayout
{
18 private static final long serialVersionUID
= 1L;
21 * Constructs a new <code>WrapLayout</code> with a left alignment and a
22 * default 5-unit horizontal and vertical gap.
29 * Constructs a new <code>FlowLayout</code> with the specified alignment and
30 * a default 5-unit horizontal and vertical gap. The value of the alignment
31 * argument must be one of <code>WrapLayout</code>, <code>WrapLayout</code>,
32 * or <code>WrapLayout</code>.
37 public WrapLayout(int align
) {
42 * Creates a new flow layout manager with the indicated alignment and the
43 * indicated horizontal and vertical gaps.
45 * The value of the alignment argument must be one of
46 * <code>WrapLayout</code>, <code>WrapLayout</code>, or
47 * <code>WrapLayout</code>.
52 * the horizontal gap between components
54 * the vertical gap between components
56 public WrapLayout(int align
, int hgap
, int vgap
) {
57 super(align
, hgap
, vgap
);
61 * Returns the preferred dimensions for this layout given the <i>visible</i>
62 * components in the specified target container.
65 * the component which needs to be laid out
66 * @return the preferred dimensions to lay out the subcomponents of the
70 public Dimension
preferredLayoutSize(Container target
) {
71 return layoutSize(target
, true);
75 * Returns the minimum dimensions needed to layout the <i>visible</i>
76 * components contained in the specified target container.
79 * the component which needs to be laid out
80 * @return the minimum dimensions to lay out the subcomponents of the
84 public Dimension
minimumLayoutSize(Container target
) {
85 Dimension minimum
= layoutSize(target
, false);
86 minimum
.width
-= (getHgap() + 1);
91 * Returns the minimum or preferred dimension needed to layout the target
95 * target to get layout size for
97 * should preferred size be calculated
98 * @return the dimension to layout the target container
100 private Dimension
layoutSize(Container target
, boolean preferred
) {
101 synchronized (target
.getTreeLock()) {
102 // Each row must fit with the width allocated to the containter.
103 // When the container width = 0, the preferred width of the
105 // has not yet been calculated so lets ask for the maximum.
107 int targetWidth
= target
.getSize().width
;
108 Container container
= target
;
110 while (container
.getSize().width
== 0
111 && container
.getParent() != null) {
112 container
= container
.getParent();
115 targetWidth
= container
.getSize().width
;
117 if (targetWidth
== 0)
118 targetWidth
= Integer
.MAX_VALUE
;
120 int hgap
= getHgap();
121 int vgap
= getVgap();
122 Insets insets
= target
.getInsets();
123 int horizontalInsetsAndGap
= insets
.left
+ insets
.right
125 int maxWidth
= targetWidth
- horizontalInsetsAndGap
;
127 // Fit components into the allowed width
129 Dimension dim
= new Dimension(0, 0);
133 int nmembers
= target
.getComponentCount();
135 for (int i
= 0; i
< nmembers
; i
++) {
136 Component m
= target
.getComponent(i
);
139 Dimension d
= preferred ? m
.getPreferredSize() : m
142 // Can't add the component to current row. Start a new
145 if (rowWidth
+ d
.width
> maxWidth
) {
146 addRow(dim
, rowWidth
, rowHeight
);
151 // Add a horizontal gap for all components after the
159 rowHeight
= Math
.max(rowHeight
, d
.height
);
163 addRow(dim
, rowWidth
, rowHeight
);
165 dim
.width
+= horizontalInsetsAndGap
;
166 dim
.height
+= insets
.top
+ insets
.bottom
+ vgap
* 2;
168 // When using a scroll pane or the DecoratedLookAndFeel we need
170 // make sure the preferred size is less than the size of the
171 // target containter so shrinking the container size works
172 // correctly. Removing the horizontal gap is an easy way to do
175 Container scrollPane
= SwingUtilities
.getAncestorOfClass(
176 JScrollPane
.class, target
);
178 if (scrollPane
!= null && target
.isValid()) {
179 dim
.width
-= (hgap
+ 1);
187 * A new row has been completed. Use the dimensions of this row to update
188 * the preferred size for the container.
190 * @param dim update the width and height when appropriate
192 * @param rowWidth the width of the row to add
194 * @param rowHeight the height of the row to add
196 private void addRow(Dimension dim
, int rowWidth
, int rowHeight
) {
197 dim
.width
= Math
.max(dim
.width
, rowWidth
);
199 if (dim
.height
> 0) {
200 dim
.height
+= getVgap();
203 dim
.height
+= rowHeight
;