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 }