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 }