View Javadoc

1   /*
2    * Copyright 2006-2016 The JGUIraffe Team.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.jguiraffe.gui.layout;
17  
18  /**
19   * <p>
20   * A layout manager that deals with button bars for dialogs.
21   * </p>
22   * <p>
23   * With this layout manager typical horizontal button bars for dialogs can be
24   * created in an easy way. The button objects simply need to be added to the
25   * container, no constraints need to be passed. These button bars have the
26   * following properties:
27   * <ul>
28   * <li>All buttons have the same width. This is the width of the widest button.</li>
29   * <li>Between the buttons there is a gap, which can be configured.</li>
30   * <li>Margins can be defined for all directions. All margins and the gap
31   * between the buttons can be defined in several units.</li>
32   * <li>The alignment of the buttons can be defined. This can be left aligned
33   * (i.e. the right margin grows if more space is available in the dialog), right
34   * aligned (the left margins grows) or center aligned (both margins grow).</li>
35   * </ul>
36   * </p>
37   * <p>
38   * This class is a special implementation of <code>PercentLayoutBase</code>. It
39   * implements the button layout on top of a percent layout. As its ancestor this
40   * class is platform neutral, i.e. it can work together with different GUI
41   * libraries for which a {@link PercentLayoutPlatformAdapter} implementation is
42   * available.
43   * </p>
44   *
45   * @author Oliver Heger
46   * @version $Id: ButtonLayout.java 205 2012-01-29 18:29:57Z oheger $
47   */
48  public class ButtonLayout extends PercentLayoutBase
49  {
50      /** Constant for the default margin value. */
51      static final NumberWithUnit DEFAULT_MARGIN = new NumberWithUnit(2, Unit.DLU);
52  
53      /** Constant for the default gap value. */
54      static final NumberWithUnit DEFAULT_GAP = new NumberWithUnit(1, Unit.DLU);
55  
56      /** Constant for the number of rows of this layout. */
57      private static final int ROW_SIZE = 3;
58  
59      /** Constant for the full weight factor. */
60      private static final int WEIGHT_FULL = 100;
61  
62      /** Constant for the half weight factor. */
63      private static final int WEIGHT_HALF = 50;
64  
65      /** Constant for no weight factor. */
66      private static final int WEIGHT_NULL = 0;
67  
68      /**
69       * The serial version UID.
70       */
71      private static final long serialVersionUID = 20090730L;
72  
73      /** Stores the top margin. */
74      private NumberWithUnit topMargin;
75  
76      /** Stores the bottom margin. */
77      private NumberWithUnit bottomMargin;
78  
79      /** Stores the left margin. */
80      private NumberWithUnit leftMargin;
81  
82      /** Stores the right margin. */
83      private NumberWithUnit rightMargin;
84  
85      /** Stores the width of the gap between the buttons. */
86      private NumberWithUnit gap;
87  
88      /** Stores the alignment flag. */
89      private Alignment alignment;
90  
91      /**
92       * Creates a new instance of <code>ButtonLayout</code>. All properties are
93       * set to default values.
94       */
95      public ButtonLayout()
96      {
97          leftMargin = DEFAULT_MARGIN;
98          rightMargin = DEFAULT_MARGIN;
99          topMargin = DEFAULT_MARGIN;
100         bottomMargin = DEFAULT_MARGIN;
101         gap = DEFAULT_GAP;
102         alignment = Alignment.RIGHT;
103     }
104 
105     /**
106      * Returns the top margin.
107      *
108      * @return the top margin
109      */
110     public NumberWithUnit getTopMargin()
111     {
112         return topMargin;
113     }
114 
115     /**
116      * Sets the top margin. This is the space above the buttons.
117      *
118      * @param topMargin the top margin (a <b>null</b> reference is converted to
119      *        a value of 0)
120      */
121     public void setTopMargin(NumberWithUnit topMargin)
122     {
123         this.topMargin = NumberWithUnit.nonNull(topMargin);
124     }
125 
126     /**
127      * Returns the bottom margin.
128      *
129      * @return the bottom margin
130      */
131     public NumberWithUnit getBottomMargin()
132     {
133         return bottomMargin;
134     }
135 
136     /**
137      * Sets the bottom margin. This is the space below the buttons.
138      *
139      * @param bottomMargin the bottom margin
140      */
141     public void setBottomMargin(NumberWithUnit bottomMargin)
142     {
143         this.bottomMargin = NumberWithUnit.nonNull(bottomMargin);
144     }
145 
146     /**
147      * Returns the left margin.
148      *
149      * @return the left margin
150      */
151     public NumberWithUnit getLeftMargin()
152     {
153         return leftMargin;
154     }
155 
156     /**
157      * Sets the left margin. This is the space between the window's left edge
158      * and the first button. This value is fixed only if the button bar is left
159      * aligned; otherwise this space may grow.
160      *
161      * @param leftMargin the left margin (a <b>null</b> reference is converted
162      *        to a value of 0)
163      */
164     public void setLeftMargin(NumberWithUnit leftMargin)
165     {
166         this.leftMargin = NumberWithUnit.nonNull(leftMargin);
167     }
168 
169     /**
170      * Returns the right margin.
171      *
172      * @return the right margin
173      */
174     public NumberWithUnit getRightMargin()
175     {
176         return rightMargin;
177     }
178 
179     /**
180      * Sets the right margin. This is the space between the window's right edge
181      * and the last button. This value is fixed only if the button bar is right
182      * aligned; otherwise this space may grow.
183      *
184      * @param rightMargin the right margin (a <b>null</b> reference is converted
185      *        to a value of 0)
186      */
187     public void setRightMargin(NumberWithUnit rightMargin)
188     {
189         this.rightMargin = NumberWithUnit.nonNull(rightMargin);
190     }
191 
192     /**
193      * Returns the width of the gap between the buttons.
194      *
195      * @return the gap
196      */
197     public NumberWithUnit getGap()
198     {
199         return gap;
200     }
201 
202     /**
203      * Sets the width of the gap between the buttons.
204      *
205      * @param gap the gap's width (a <b>null</b> reference is converted to a
206      *        value of 0)
207      */
208     public void setGap(NumberWithUnit gap)
209     {
210         this.gap = NumberWithUnit.nonNull(gap);
211     }
212 
213     /**
214      * Returns the alignment of the button bar.
215      *
216      * @return the alignment
217      */
218     public Alignment getAlignment()
219     {
220         return alignment;
221     }
222 
223     /**
224      * Sets the alignment of the button bar.
225      *
226      * @param alignment the new alignment (must not be <b>null</b>)
227      * @throws IllegalArgumentException if the alignment is <b>null</b>
228      */
229     public void setAlignment(Alignment alignment)
230     {
231         if (alignment == null)
232         {
233             throw new IllegalArgumentException("Alignment must not be null!");
234         }
235         this.alignment = alignment;
236     }
237 
238     /**
239      * Initializes the whole layout. Creates a percent layout based on the
240      * current property values and the contained buttons.
241      *
242      * @param adapter the currently used platform adapter
243      */
244     @Override
245     protected void initCells(PercentLayoutPlatformAdapter adapter)
246     {
247         int buttonCount = adapter.getComponentCount();
248         int lastIndex = 2 * buttonCount;
249         initDimensions(lastIndex + 1, ROW_SIZE);
250         clearCells(lastIndex + 1, ROW_SIZE);
251 
252         initRowConstraints();
253         initColumnConstraints(lastIndex, buttonCount);
254         insertButtons(adapter, buttonCount);
255     }
256 
257     /**
258      * Initializes the row constraints.
259      */
260     protected void initRowConstraints()
261     {
262         CellConstraints.Builder cBuilder = getConstraintsBuilder();
263         setRowConstraints(0, cBuilder.withMinimumSize(getTopMargin()).create());
264         setRowConstraints(1, cBuilder.defaultRow().create());
265         setRowConstraints(2, cBuilder.withMinimumSize(getBottomMargin())
266                 .create());
267     }
268 
269     /**
270      * Initializes the column constraints.
271      *
272      * @param lastIndex the index of the last column
273      * @param buttonCount the number of buttons
274      */
275     protected void initColumnConstraints(int lastIndex, int buttonCount)
276     {
277         CellConstraints.Builder cBuilder = getConstraintsBuilder();
278         setColumnConstraints(0, cBuilder.withCellAlignment(CellAlignment.FULL)
279                 .withMinimumSize(getLeftMargin()).withWeight(
280                         calcWeightFactor(Alignment.LEFT)).create());
281         setColumnConstraints(lastIndex, cBuilder.withCellAlignment(
282                 CellAlignment.FULL).withMinimumSize(getRightMargin())
283                 .withWeight(calcWeightFactor(Alignment.RIGHT)).create());
284 
285         CellConstraints ccGap = cBuilder.withMinimumSize(getGap()).create();
286         for (int i = 2; i < lastIndex - 1; i += 2)
287         {
288             setColumnConstraints(i, ccGap);
289         }
290 
291         CellConstraints ccBtn = cBuilder.withCellAlignment(CellAlignment.FULL)
292                 .withCellSize(CellSize.PREFERRED).create();
293         int[] buttonIndices = new int[buttonCount];
294         int btnIdx = 0;
295         for (int i = 1; i < lastIndex; i += 2, btnIdx++)
296         {
297             buttonIndices[btnIdx] = i;
298             setColumnConstraints(i, ccBtn);
299         }
300 
301         if (buttonCount > 1)
302         {
303             addColumnGroup(CellGroup.fromArray(buttonIndices));
304         }
305     }
306 
307     /**
308      * Inserts all buttons into the percent layout.
309      *
310      * @param adapter the platform adapter
311      * @param buttonCount the number of available buttons
312      */
313     protected void insertButtons(PercentLayoutPlatformAdapter adapter,
314             int buttonCount)
315     {
316         PercentData.Builder pcb = new PercentData.Builder();
317 
318         for (int i = 0; i < buttonCount; i++)
319         {
320             PercentData pd = pcb.pos(2 * i + 1, 1);
321             initCell(adapter.getComponent(i), pd);
322         }
323     }
324 
325     /**
326      * Calculates the weight factor for the left or right margin cell.
327      *
328      * @param align the alignment of this margin
329      * @return the weight factor for this margin cell
330      */
331     private int calcWeightFactor(Alignment align)
332     {
333         if (getAlignment() == Alignment.CENTER)
334         {
335             return WEIGHT_HALF;
336         }
337         else
338         {
339             return (getAlignment() != align) ? WEIGHT_FULL : WEIGHT_NULL;
340         }
341     }
342 
343     /**
344      * An enumeration class for the alignment of a {@code ButtonLayout}. The
345      * alignment defines the horizontal orientation of the buttons in the
346      * layout.
347      *
348      * @author Oliver Heger
349      * @version $Id: ButtonLayout.java 205 2012-01-29 18:29:57Z oheger $
350      */
351     public static enum Alignment
352     {
353         /**
354          * The alignment <em>left</em>. All buttons are aligned to the left
355          * margin of the layout. If more space becomes available, the right
356          * margin grows.
357          */
358         LEFT,
359 
360         /**
361          * The alignment <em>right</em>. All buttons are aligned to the right
362          * margin of the layout. If more space becomes available, the left
363          * margin grows.
364          */
365         RIGHT,
366 
367         /**
368          * The alignment <em>center</em>. The buttons are centered in the
369          * hosting container. If more space becomes available, both the left and
370          * the right margin grow.
371          */
372         CENTER
373     }
374 }