001    /*
002     * Copyright 2002-2004 the original author or authors.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     * 
008     * http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     */
015    package org.springframework.richclient.util;
016    
017    import java.awt.Color;
018    import java.awt.Dimension;
019    import java.awt.Insets;
020    
021    import javax.swing.BorderFactory;
022    import javax.swing.JButton;
023    import javax.swing.JComponent;
024    import javax.swing.JLabel;
025    import javax.swing.JTabbedPane;
026    import javax.swing.JTextArea;
027    import javax.swing.UIManager;
028    import javax.swing.border.Border;
029    import javax.swing.text.JTextComponent;
030    
031    import org.springframework.richclient.core.UIConstants;
032    
033    import com.jgoodies.forms.builder.ButtonStackBuilder;
034    import com.jgoodies.forms.factories.Borders;
035    import com.jgoodies.forms.factories.ButtonBarFactory;
036    import com.jgoodies.forms.layout.ConstantSize;
037    import com.jgoodies.forms.layout.Sizes;
038    
039    /**
040     * Utility functions that help enforce a standard look and feel in accordance
041     * with the Java Look and Feel Design Guidelines.
042     * 
043     * @author Keith Donald
044     */
045    public class GuiStandardUtils {
046    
047        private GuiStandardUtils() {
048        }
049    
050        public static JComponent attachBorder(JComponent c, Border border) {
051            c.setBorder(border);
052            return c;
053        }
054    
055        public static JComponent attachBorder(JComponent c) {
056            return attachDialogBorder(c);
057        }
058    
059        public static JComponent attachDialogBorder(JComponent c) {
060            if (c instanceof JTabbedPane) {
061                c.setBorder(Borders.TABBED_DIALOG_BORDER);
062            }
063            else {
064                c.setBorder(Borders.DIALOG_BORDER);
065            }
066            return c;
067        }
068    
069        public static Border getStandardDialogBorder() {
070            return Borders.DIALOG_BORDER;
071        }
072    
073        public static Border createEvenlySpacedBorder(int spacePx) {
074            return createEvenlySpacedBorder(Sizes.pixel(spacePx));
075        }
076    
077        public static Border createEvenlySpacedBorder(ConstantSize space) {
078            return Borders.createEmptyBorder(space, space, space, space);
079        }
080    
081        public static Border createLeftAndRightBorder(int spacePx) {
082            return createLeftAndRightBorder(Sizes.pixel(spacePx));
083        }
084    
085        public static Border createLeftAndRightBorder(ConstantSize space) {
086            return Borders.createEmptyBorder(Sizes.ZERO, space, Sizes.ZERO, space);
087        }
088    
089        public static Border createTopAndBottomBorder(int spacePx) {
090            return createTopAndBottomBorder(Sizes.pixel(spacePx));
091        }
092    
093        public static Border createTopAndBottomBorder(ConstantSize space) {
094            return Borders.createEmptyBorder(space, Sizes.ZERO, space, Sizes.ZERO);
095        }
096    
097        /**
098         * Return text which conforms to the Look and Feel Design Guidelines for the
099         * title of a dialog : the application name, a colon, then the name of the
100         * specific dialog.
101         * 
102         * @param dialogName
103         *            the short name of the dialog.
104         */
105        public static String createDialogTitle(String appName, String dialogName) {
106            if (appName != null) {
107                StringBuffer buf = new StringBuffer(appName);
108                buf.append(": ");
109                buf.append(dialogName);
110                return buf.toString();
111            }
112    
113            return dialogName;
114        }
115    
116        /**
117         * Make a horizontal row of buttons of equal size, whch are equally spaced,
118         * and aligned on the right.
119         * 
120         * <P>
121         * The returned component has border spacing only on the top (of the size
122         * recommended by the Look and Feel Design Guidelines). All other spacing
123         * must be applied elsewhere ; usually, this will only mean that the
124         * dialog's top-level panel should use {@link #buildStandardBorder}.
125         * 
126         * @param buttons
127         *            contains <code>JButton</code> objects.
128         * @return A row displaying the buttons horizontally.
129         */
130        public static JComponent createCommandButtonRow(JButton[] buttons) {
131            return ButtonBarFactory.buildRightAlignedBar(buttons);
132        }
133    
134        /**
135         * Make a vertical row of buttons of equal size, whch are equally spaced,
136         * and aligned on the right.
137         * 
138         * <P>
139         * The returned component has border spacing only on the left (of the size
140         * recommended by the Look and Feel Design Guidelines). All other spacing
141         * must be applied elsewhere ; usually, this will only mean that the
142         * dialog's top-level panel should use {@link #buildStandardBorder}.
143         * 
144         * @param buttons
145         *            contains <code>JButton</code> objects.
146         * @return A column displaying the buttons vertically.
147         */
148        public static JComponent createCommandButtonColumn(JButton[] buttons) {
149            ButtonStackBuilder builder = new ButtonStackBuilder();
150    
151            for (int i = 0; i < buttons.length; i++) {
152                if (i > 0) {
153                    builder.addRelatedGap();
154                }
155                builder.addGridded(buttons[i]);
156            }
157            return builder.getPanel();
158        }
159    
160        /**
161         * Sets the items in <code>aComponents</code> to the same size.
162         * 
163         * Sets each component's preferred and maximum sizes. The actual size is
164         * determined by the layout manager, which adjusts for locale-specific
165         * strings and customized fonts. (See this <a
166         * href="http://java.sun.com/products/jlf/ed2/samcode/prefere.html">Sun doc
167         * </a> for more information.)
168         * 
169         * @param components
170         *            contains <code>JComponent</code> objects.
171         */
172        public static void equalizeSizes(JComponent[] components) {
173            Dimension targetSize = new Dimension(0, 0);
174            for (int i = 0; i < components.length; i++) {
175                JComponent comp = components[i];
176                Dimension compSize = comp.getPreferredSize();
177                double width = Math.max(targetSize.getWidth(), compSize.getWidth());
178                double height = Math.max(targetSize.getHeight(), compSize.getHeight());
179                targetSize.setSize(width, height);
180            }
181            setSizes(components, targetSize);
182        }
183    
184        private static void setSizes(JComponent[] components, final Dimension dimension) {
185            for (int i = 0; i < components.length; i++) {
186                JComponent comp = components[i];
187                // shouldn't have to clone these (hopefully awt does it for us)
188                comp.setPreferredSize(dimension);
189                comp.setMaximumSize(dimension);
190            }
191        }
192    
193        public static JTextArea createStandardTextArea(int rows, int columns) {
194            JTextArea area = createStandardTextArea("");
195            area.setRows(rows);
196            area.setColumns(columns);
197            return area;
198        }
199    
200        /**
201         * An alternative to multi-line labels, for the presentation of several
202         * lines of text, and for which the line breaks are determined solely by the
203         * control.
204         * 
205         * @param text
206         *            text that does not contain newline characters or html.
207         * @return <code>JTextArea</code> which is not editable, has improved
208         *         spacing over the supplied default (placing
209         *         {@link UIConstants#ONE_SPACE}on the left and right), and which
210         *         wraps lines on word boundarie.
211         */
212        public static JTextArea createStandardTextArea(String text) {
213            JTextArea result = new JTextArea(text);
214            return configureStandardTextArea(result);
215        }
216    
217        public static JTextArea configureStandardTextArea(JTextArea textArea) {
218            textArea.setEditable(false);
219            textArea.setWrapStyleWord(true);
220            textArea.setLineWrap(true);
221            textArea.setMargin(new Insets(0, UIConstants.ONE_SPACE, 0, UIConstants.ONE_SPACE));
222            return textArea;
223        }
224    
225        /**
226         * An alternative to multi-line labels, for the presentation of several
227         * lines of text, and for which line breaks are determined solely by
228         * <code>aText</code>, and not by the control.
229         * 
230         * @param text
231         *            the text to be placed in the text area.
232         * @return <code>JTextArea</code> which is not editable and has improved
233         *         spacing over the supplied default (placing
234         *         {@link UIConstants#ONE_SPACE}on the left and right).
235         */
236        public static JTextArea createStandardTextAreaHardNewLines(String text) {
237            JTextArea result = new JTextArea(text);
238            result.setEditable(false);
239            result.setMargin(new Insets(0, UIConstants.ONE_SPACE, 0, UIConstants.ONE_SPACE));
240            return result;
241        }
242    
243        /**
244         * If aLabel has text which is longer than MAX_LABEL_LENGTH, then truncate
245         * the label text and place an ellipsis at the end; the original text is
246         * placed in a tooltip.
247         * 
248         * This is particularly useful for displaying file names, whose length can
249         * vary widely between deployments.
250         * 
251         * @param label
252         *            The label to truncate if length() > MAX_LABEL_LENGTH.
253         */
254        public static void truncateLabelIfLong(JLabel label) {
255            String originalText = label.getText();
256            if (originalText.length() > UIConstants.MAX_LABEL_LENGTH) {
257                label.setToolTipText(originalText);
258                String truncatedText = originalText.substring(0, UIConstants.MAX_LABEL_LENGTH) + "...";
259                label.setText(truncatedText);
260            }
261        }
262    
263        /**
264         * This will allow selection and copy to work but still retain the label
265         * look
266         */
267        public static JTextArea textAreaAsLabel(JTextArea textArea) {
268            //  Turn on word wrap
269            textArea.setLineWrap(true);
270            textArea.setWrapStyleWord(true);
271            // Perform the other changes to complete the look
272            textComponentAsLabel(textArea);
273            return textArea;
274        }
275    
276        /**
277         * This will allow selection and copy to work but still retain the label
278         * look
279         */
280        public static JTextComponent textComponentAsLabel(JTextComponent textcomponent) {
281            //  Make the text component non editable
282            textcomponent.setEditable(false);
283            // Make the text area look like a label
284            textcomponent.setBackground((Color)UIManager.get("Label.background"));
285            textcomponent.setForeground((Color)UIManager.get("Label.foreground"));
286            textcomponent.setBorder(null);
287            return textcomponent;
288        }
289    
290        /**
291         * Useful debug function to place a colored, line border around a component
292         * for layout management debugging.
293         * 
294         * @param c
295         *            the component
296         * @param color
297         *            the border color
298         */
299        public static void createDebugBorder(JComponent c, Color color) {
300            if (color == null) {
301                color = Color.BLACK;
302            }
303            c.setBorder(BorderFactory.createLineBorder(color));
304        }
305    
306    }