001/*
002 * Copyright (c) 2002-2006 JGoodies Karsten Lentzsch. All Rights Reserved.
003 *
004 * Redistribution and use in source and binary forms, with or without
005 * modification, are permitted provided that the following conditions are met:
006 *
007 *  o Redistributions of source code must retain the above copyright notice,
008 *    this list of conditions and the following disclaimer.
009 *
010 *  o Redistributions in binary form must reproduce the above copyright notice,
011 *    this list of conditions and the following disclaimer in the documentation
012 *    and/or other materials provided with the distribution.
013 *
014 *  o Neither the name of JGoodies Karsten Lentzsch nor the names of
015 *    its contributors may be used to endorse or promote products derived
016 *    from this software without specific prior written permission.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030
031package com.jgoodies.forms.builder;
032
033import java.awt.Component;
034import java.util.MissingResourceException;
035import java.util.ResourceBundle;
036
037import javax.swing.JComponent;
038import javax.swing.JLabel;
039import javax.swing.JPanel;
040
041import com.jgoodies.forms.layout.CellConstraints;
042import com.jgoodies.forms.layout.FormLayout;
043
044/**
045 * A general purpose panel builder that uses the {@link FormLayout}
046 * to lay out <code>JPanel</code>s. In addition to its superclass
047 * {@link PanelBuilder} this class provides convenience behavior to map
048 * resource keys to their associated internationalized (i15d) strings
049 * when adding labels, titles and titled separators.<p>
050 *
051 * The localized texts used in methods <code>#addI15dLabel</code>
052 * and <code>#addI15dTitle</code> can contain an optional mnemonic marker.
053 * The mnemonic and mnemonic index are indicated by a single ampersand
054 * (<tt>&amp;</tt>). For example <tt>&quot;&amp;Save&quot;</tt>, or
055 * <tt>&quot;Save&nbsp;&amp;as&quot;</tt>. To use the ampersand itself,
056 * duplicate it, for example <tt>&quot;Look&amp;&amp;Feel&quot;</tt>.<p>
057 *
058 * @author        Karsten Lentzsch
059 * @version $Revision$
060 * @since 1.0.3
061 *
062 * @see        ResourceBundle
063 */
064public class I15dPanelBuilder extends PanelBuilder {
065
066    /**
067     * Holds the <code>ResourceBundle</code> used to lookup internationalized
068     * (i15d) String resources.
069     */
070    private final ResourceBundle bundle;
071
072    // Instance Creation ****************************************************
073
074    /**
075     * Constructs an instance of <code>I15dPanelBuilder</code> for the given
076     * layout. Uses an instance of <code>JPanel</code> as layout container.
077     *
078     * @param layout    the form layout used to layout the container
079     * @param bundle    the resource bundle used to lookup i15d strings
080     */
081    public I15dPanelBuilder(FormLayout layout, ResourceBundle bundle) {
082        this(new JPanel(null), layout, bundle);
083    }
084
085    /**
086     * Constructs an instance of <code>I15dPanelBuilder</code>
087     * for the given FormLayout and layout container.
088     *
089     * @param layout  the <code>FormLayout</code> used to layout the container
090     * @param bundle  the <code>ResourceBundle</code> used to lookup i15d strings
091     * @param panel   the layout container
092     */
093    public I15dPanelBuilder(FormLayout layout, ResourceBundle bundle,
094            JPanel panel) {
095        super(layout, panel);
096        this.bundle = bundle;
097    }
098
099    /**
100     * Constructs an instance of <code>I15dPanelBuilder</code>
101     * for the given FormLayout and layout container.
102     *
103     * @param panel   the layout container
104     * @param bundle  the <code>ResourceBundle</code> used to lookup i15d strings
105     * @param layout  the <code>FormLayout</code> used to layout the container
106     *
107     * @deprecated Replaced by {@link #I15dPanelBuilder(FormLayout, ResourceBundle, JPanel)}.
108     */
109    @Deprecated
110    public I15dPanelBuilder(JPanel panel, FormLayout layout,
111            ResourceBundle bundle) {
112        this(layout, bundle, panel);
113    }
114
115    // Adding Labels and Separators *****************************************
116
117    /**
118     * Adds an internationalized (i15d) textual label to the form using the
119     * specified constraints.
120     *
121     * @param resourceKey        the resource key for the label's text
122     * @param constraints        the label's cell constraints
123     * @return the added label
124     */
125    public final JLabel addI15dLabel(String resourceKey,
126            CellConstraints constraints) {
127        return addLabel(getI15dString(resourceKey), constraints);
128    }
129
130    /**
131     * Adds an internationalized (i15d) textual label to the form using the
132     * specified constraints.
133     *
134     * @param resourceKey         the resource key for the label's text
135     * @param encodedConstraints  a string representation for the constraints
136     * @return the added label
137     */
138    public final JLabel addI15dLabel(String resourceKey,
139            String encodedConstraints) {
140        return addI15dLabel(resourceKey,
141                new CellConstraints(encodedConstraints));
142    }
143
144    /**
145     * Adds an internationalized (i15d) label and component to the panel using
146     * the given cell constraints. Sets the label as <i>the</i> component label
147     * using {@link JLabel#setLabelFor(java.awt.Component)}.<p>
148     *
149     * <strong>Note:</strong> The {@link CellConstraints} objects for the label
150     * and the component must be different. Cell constraints are implicitly
151     * cloned by the <code>FormLayout</code> when added to the container.
152     * However, in this case you may be tempted to reuse a
153     * <code>CellConstraints</code> object in the same way as with many other
154     * builder methods that require a single <code>CellConstraints</code>
155     * parameter.
156     * The pitfall is that the methods <code>CellConstraints.xy**(...)</code>
157     * just set the coordinates but do <em>not</em> create a new instance.
158     * And so the second invocation of <code>xy***(...)</code> overrides
159     * the settings performed in the first invocation before the object
160     * is cloned by the <code>FormLayout</code>.<p>
161     *
162     * <strong>Wrong:</strong><pre>
163     * builder.add("name.key",
164     *             cc.xy(1, 7),         // will be modified by the code below
165     *             nameField,
166     *             cc.xy(3, 7)          // sets the single instance to (3, 7)
167     *            );
168     * </pre>
169     * <strong>Correct:</strong><pre>
170     * builder.add("name.key",
171     *             cc.xy(1, 7).clone(), // cloned before the next modification
172     *             nameField,
173     *             cc.xy(3, 7)          // sets this instance to (3, 7)
174     *            );
175     * </pre>
176     *
177     * @param resourceKey           the resource key for the label
178     * @param labelConstraints      the label's cell constraints
179     * @param component             the component to add
180     * @param componentConstraints  the component's cell constraints
181     * @return the added label
182     * @exception IllegalArgumentException if the same cell constraints instance
183     *     is used for the label and the component
184     * @see JLabel#setLabelFor(java.awt.Component)
185     */
186    public final JLabel addI15dLabel(String resourceKey,
187            CellConstraints labelConstraints, Component component,
188            CellConstraints componentConstraints) {
189
190        return addLabel(getI15dString(resourceKey), labelConstraints, component,
191                componentConstraints);
192    }
193
194    /**
195     * Adds an internationalized (i15d) titled separator to the form using the
196     * specified constraints.
197     *
198     * @param resourceKey  the resource key for the separator title
199     * @param constraints  the separator's cell constraints
200     * @return the added titled separator
201     */
202    public final JComponent addI15dSeparator(String resourceKey,
203            CellConstraints constraints) {
204        return addSeparator(getI15dString(resourceKey), constraints);
205    }
206
207    /**
208     * Adds an internationalized (i15d)  titled separator to the form using
209     * the specified constraints.
210     *
211     * @param resourceKey         the resource key for the separator title
212     * @param encodedConstraints  a string representation for the constraints
213     * @return the added titled separator
214     */
215    public final JComponent addI15dSeparator(String resourceKey,
216            String encodedConstraints) {
217        return addI15dSeparator(resourceKey,
218                new CellConstraints(encodedConstraints));
219    }
220
221    /**
222     * Adds a title to the form using the specified constraints.
223     *
224     * @param resourceKey  the resource key for  the separator title
225     * @param constraints  the separator's cell constraints
226     * @return the added title label
227     */
228    public final JLabel addI15dTitle(String resourceKey,
229            CellConstraints constraints) {
230        return addTitle(getI15dString(resourceKey), constraints);
231    }
232
233    /**
234     * Adds a title to the form using the specified constraints.
235     *
236     * @param resourceKey         the resource key for the separator title
237     * @param encodedConstraints  a string representation for the constraints
238     * @return the added title label
239     */
240    public final JLabel add15dTitle(String resourceKey,
241            String encodedConstraints) {
242        return addI15dTitle(resourceKey,
243                new CellConstraints(encodedConstraints));
244    }
245
246    // Helper Code **********************************************************
247
248    /**
249     * Looks up and returns the internationalized (i15d) string for the given
250     * resource key from the <code>ResourceBundle</code>.
251     *
252     * @param resourceKey  the key to look for in the resource bundle
253     * @return the associated internationalized string, or the resource key
254     *     itself in case of a missing resource
255     * @exception IllegalStateException  if no <code>ResourceBundle</code>
256     *     has been set
257     */
258    protected String getI15dString(String resourceKey) {
259        if (bundle == null) {
260            throw new IllegalStateException("You must specify a ResourceBundle"
261                    + " before using the internationalization support.");
262        }
263        try {
264            return bundle.getString(resourceKey);
265        } catch (MissingResourceException mre) {
266            return resourceKey;
267        }
268    }
269
270}