001/*
002 * Copyright (c) 2002-2007 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.factories;
032
033import java.awt.Component;
034import java.awt.Graphics;
035import java.awt.Insets;
036import java.util.StringTokenizer;
037
038import javax.swing.border.Border;
039
040import com.jgoodies.forms.layout.ConstantSize;
041import com.jgoodies.forms.layout.Sizes;
042import com.jgoodies.forms.util.LayoutStyle;
043
044/**
045 * Provides constants and factory methods for <code>Border</code>s that use
046 * instances of {@link ConstantSize} to define the margins.<p>
047 *
048 * <strong>Examples:</strong><br>
049 * <pre>
050 * Borders.DLU2_BORDER
051 * Borders.createEmptyBorder(Sizes.DLUY4, Sizes.DLUX2, Sizes.DLUY4, Sizes.DLUX2);
052 * Borders.createEmptyBorder("4dlu, 2dlu, 4dlu, 2dlu");
053 * </pre>
054 *
055 * @author  Karsten Lentzsch
056 * @version $Revision$
057 *
058 * @see     Border
059 * @see     Sizes
060 */
061public final class Borders {
062
063    private Borders() {
064        // Overrides default constructor; prevents instantiation.
065    }
066
067    // Constant Borders *****************************************************
068
069    /**
070     * A prepared and reusable EmptyBorder without gaps.
071     */
072    public static final Border EMPTY_BORDER = new javax.swing.border.EmptyBorder(
073            0, 0, 0, 0);
074
075    /**
076     * A prepared and reusable Border with 2dlu on all sides.
077     */
078    public static final Border DLU2_BORDER = createEmptyBorder(Sizes.DLUY2,
079            Sizes.DLUX2, Sizes.DLUY2, Sizes.DLUX2);
080
081    /**
082     * A prepared and reusable Border with 4dlu on all sides.
083     */
084    public static final Border DLU4_BORDER = createEmptyBorder(Sizes.DLUY4,
085            Sizes.DLUX4, Sizes.DLUY4, Sizes.DLUX4);
086
087    /**
088     * A prepared and reusable Border with 7dlu on all sides.
089     */
090    public static final Border DLU7_BORDER = createEmptyBorder(Sizes.DLUY7,
091            Sizes.DLUX7, Sizes.DLUY7, Sizes.DLUX7);
092
093    /**
094     * A prepared Border with 14dlu on all sides.
095     */
096    public static final Border DLU14_BORDER = createEmptyBorder(Sizes.DLUY14,
097            Sizes.DLUX14, Sizes.DLUY14, Sizes.DLUX14);
098
099    /**
100     * A standardized Border that describes the gap between a component
101     * and a button bar in its bottom.
102     */
103    public static final Border BUTTON_BAR_GAP_BORDER = createEmptyBorder(
104            LayoutStyle.getCurrent().getButtonBarPad(), Sizes.dluX(0),
105            Sizes.dluY(0), Sizes.dluX(0));
106
107    /**
108     * A standardized Border that describes the border around
109     * a dialog content that has no tabs.
110     *
111     * @see #TABBED_DIALOG_BORDER
112     */
113    public static final Border DIALOG_BORDER = createEmptyBorder(
114            LayoutStyle.getCurrent().getDialogMarginY(),
115            LayoutStyle.getCurrent().getDialogMarginX(),
116            LayoutStyle.getCurrent().getDialogMarginY(),
117            LayoutStyle.getCurrent().getDialogMarginX());
118
119    /**
120     * A standardized Border that describes the border around
121     * a dialog content that uses tabs.
122     *
123     * @see #DIALOG_BORDER
124     */
125    public static final Border TABBED_DIALOG_BORDER = createEmptyBorder(
126            LayoutStyle.getCurrent().getTabbedDialogMarginY(),
127            LayoutStyle.getCurrent().getTabbedDialogMarginX(),
128            LayoutStyle.getCurrent().getTabbedDialogMarginY(),
129            LayoutStyle.getCurrent().getTabbedDialogMarginX());
130
131    // Factory Methods ******************************************************
132
133    /**
134     * Creates and returns an <code>EmptyBorder</code> with the specified
135     * gaps.
136     *
137     * @param top                the top gap
138     * @param left                the left-hand side gap
139     * @param bottom        the bottom gap
140     * @param right        the right-hand side gap
141     * @return an <code>EmptyBorder</code> with the specified gaps
142     *
143     * @see #createEmptyBorder(String)
144     */
145    public static Border createEmptyBorder(ConstantSize top, ConstantSize left,
146            ConstantSize bottom, ConstantSize right) {
147        return new EmptyBorder(top, left, bottom, right);
148    }
149
150    /**
151     * Creates and returns a <code>Border</code> using sizes as specified by
152     * the given string. This string is a comma-separated encoding of
153     * 4 <code>ConstantSize</code>s.
154     *
155     * @param encodedSizes         top, left, bottom, right gap encoded as String
156     * @return an <code>EmptyBorder</code> with the specified gaps
157     *
158     * @see #createEmptyBorder(ConstantSize, ConstantSize, ConstantSize, ConstantSize)
159     */
160    public static Border createEmptyBorder(String encodedSizes) {
161        StringTokenizer tokenizer = new StringTokenizer(encodedSizes, ", ");
162        int tokenCount = tokenizer.countTokens();
163        if (tokenCount != 4) {
164            throw new IllegalArgumentException(
165                    "The border requires 4 sizes, but '" + encodedSizes
166                            + "' has " + tokenCount + ".");
167        }
168        ConstantSize top = Sizes.constant(tokenizer.nextToken(), false);
169        ConstantSize left = Sizes.constant(tokenizer.nextToken(), true);
170        ConstantSize bottom = Sizes.constant(tokenizer.nextToken(), false);
171        ConstantSize right = Sizes.constant(tokenizer.nextToken(), true);
172        return createEmptyBorder(top, left, bottom, right);
173    }
174
175    /**
176     * An empty border that uses 4 instances of {@link ConstantSize}
177     * to define the gaps on all sides.
178     */
179    public static final class EmptyBorder implements Border {
180
181        private final ConstantSize top;
182        private final ConstantSize left;
183        private final ConstantSize bottom;
184        private final ConstantSize right;
185
186        private EmptyBorder(ConstantSize top, ConstantSize left,
187                ConstantSize bottom, ConstantSize right) {
188            this.top = top;
189            this.left = left;
190            this.bottom = bottom;
191            this.right = right;
192        }
193
194        /**
195         * Returns this border's top size.
196         *
197         * @return this border's top size
198         */
199        public ConstantSize top() {
200            return top;
201        }
202
203        /**
204         * Returns this border's left size.
205         *
206         * @return this border's left size
207         */
208        public ConstantSize left() {
209            return left;
210        }
211
212        /**
213         * Returns this border's bottom size.
214         *
215         * @return this border's bottom size
216         */
217        public ConstantSize bottom() {
218            return bottom;
219        }
220
221        /**
222         * Returns this border's right size.
223         *
224         * @return this border's right size
225         */
226        public ConstantSize right() {
227            return right;
228        }
229
230        /**
231         * Paints the border for the specified component with the specified
232         * position and size.
233         *
234         * @param c the component for which this border is being painted
235         * @param g the paint graphics
236         * @param x the x position of the painted border
237         * @param y the y position of the painted border
238         * @param width the width of the painted border
239         * @param height the height of the painted border
240         */
241        @Override
242        public void paintBorder(Component c, Graphics g, int x, int y,
243                int width, int height) {
244            // An empty border doesn't paint.
245        }
246
247        /**
248         * Returns the insets of the border.
249         *
250         * @param c the component for which this border insets value applies
251         * @return the border's Insets
252         */
253        @Override
254        public Insets getBorderInsets(Component c) {
255            return new Insets(top.getPixelSize(c), left.getPixelSize(c),
256                    bottom.getPixelSize(c), right.getPixelSize(c));
257        }
258
259        /**
260         * Returns whether or not the border is opaque.  If the border
261         * is opaque, it is responsible for filling in it's own
262         * background when painting.
263         *
264         * @return false - because the empty border is not opaque
265         */
266        @Override
267        public boolean isBorderOpaque() {
268            return false;
269        }
270
271    }
272
273}