001 /* 002 * $Id: JXTitledSeparator.java 3235 2009-02-01 15:01:07Z rah003 $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022 package org.jdesktop.swingx; 023 024 import java.awt.Color; 025 import java.awt.ComponentOrientation; 026 import java.awt.Font; 027 import java.awt.GridBagConstraints; 028 import java.awt.GridBagLayout; 029 import java.awt.Insets; 030 import javax.swing.Box; 031 import javax.swing.Icon; 032 import javax.swing.JLabel; 033 import javax.swing.JSeparator; 034 import javax.swing.SwingConstants; 035 import javax.swing.UIManager; 036 import javax.swing.plaf.ColorUIResource; 037 import javax.swing.plaf.FontUIResource; 038 039 /** 040 * <p>A simple horizontal separator that contains a title.<br/> 041 * 042 * <p>JXTitledSeparator allows you to specify the title via the {@link #setTitle} method. 043 * The title alignment may be specified by using the {@link #setHorizontalAlignment} 044 * method, and accepts all the same arguments as the {@link javax.swing.JLabel#setHorizontalAlignment} 045 * method.</p> 046 * 047 * <p>In addition, you may specify an Icon to use with this separator. The icon 048 * will appear "leading" the title (on the left in left-to-right languages, 049 * on the right in right-to-left languages). To change the position of the 050 * title with respect to the icon, call {@link #setHorizontalTextPosition}.</p> 051 * 052 * <p>The default font and color of the title comes from the <code>LookAndFeel</code>, mimicking 053 * the font and color of the {@link javax.swing.border.TitledBorder}</p> 054 * 055 * <p>Here are a few example code snippets: 056 * <pre><code> 057 * //create a plain separator 058 * JXTitledSeparator sep = new JXTitledSeparator(); 059 * sep.setTitle("Customer Info"); 060 * 061 * //create a separator with an icon 062 * sep = new JXTitledSeparator(); 063 * sep.setTitle("Customer Info"); 064 * sep.setIcon(new ImageIcon("myimage.png")); 065 * 066 * //create a separator with an icon to the right of the title, 067 * //center justified 068 * sep = new JXTitledSeparator(); 069 * sep.setTitle("Customer Info"); 070 * sep.setIcon(new ImageIcon("myimage.png")); 071 * sep.setHorizontalAlignment(SwingConstants.CENTER); 072 * sep.setHorizontalTextPosition(SwingConstants.TRAILING); 073 * </code></pre> 074 * 075 * @status REVIEWED 076 * @author rbair 077 */ 078 public class JXTitledSeparator extends JXPanel { 079 /** 080 * Implementation detail: the label used to display the title 081 */ 082 private JLabel label; 083 /** 084 * Implementation detail: a separator to use on the left of the 085 * title if alignment is centered or right justified 086 */ 087 private JSeparator leftSeparator; 088 /** 089 * Implementation detail: a separator to use on the right of the 090 * title if alignment is centered or left justified 091 */ 092 private JSeparator rightSeparator; 093 094 /** 095 * Creates a new instance of <code>JXTitledSeparator</code>. The default title is simply 096 * an empty string. Default justification is <code>LEADING</code>, and the default 097 * horizontal text position is <code>TRAILING</code> (title follows icon) 098 */ 099 public JXTitledSeparator() { 100 this("Untitled"); 101 } 102 103 /** 104 * Creates a new instance of <code>JXTitledSeparator</code> with the specified 105 * title. Default horizontal alignment is <code>LEADING</code>, and the default 106 * horizontal text position is <code>TRAILING</code> (title follows icon) 107 */ 108 public JXTitledSeparator(String title) { 109 this(title, SwingConstants.LEADING, null); 110 } 111 112 /** 113 * Creates a new instance of <code>JXTitledSeparator</code> with the specified 114 * title and horizontal alignment. The default 115 * horizontal text position is <code>TRAILING</code> (title follows icon) 116 */ 117 public JXTitledSeparator(String title, int horizontalAlignment) { 118 this(title, horizontalAlignment, null); 119 } 120 121 /** 122 * Creates a new instance of <code>JXTitledSeparator</code> with the specified 123 * title, icon, and horizontal alignment. The default 124 * horizontal text position is <code>TRAILING</code> (title follows icon) 125 */ 126 public JXTitledSeparator(String title, int horizontalAlignment, Icon icon) { 127 setLayout(new GridBagLayout()); 128 129 label = new JLabel(title) { 130 @Override 131 public void updateUI(){ 132 super.updateUI(); 133 updateTitle(); 134 } 135 }; 136 label.setIcon(icon); 137 label.setHorizontalAlignment(horizontalAlignment); 138 leftSeparator = new JSeparator(); 139 rightSeparator = new JSeparator(); 140 141 layoutSeparator(); 142 143 updateTitle(); 144 setOpaque(false); 145 } 146 147 /** 148 * Implementation detail. Handles updates of title color and font on LAF change. For more 149 * details see swingx#451. 150 */ 151 //TODO remove this method in favor of UI delegate -- kgs 152 protected void updateTitle() 153 { 154 if (label == null) return; 155 156 Color c = label.getForeground(); 157 if (c == null || c instanceof ColorUIResource) 158 setForeground(UIManager.getColor("TitledBorder.titleColor")); 159 160 Font f = label.getFont(); 161 if (f == null || f instanceof FontUIResource) 162 setFont(UIManager.getFont("TitledBorder.font")); 163 } 164 165 /** 166 * Implementation detail. lays out this component, showing/hiding components 167 * as necessary. Actually changes the containment (removes and adds components). 168 * <code>JXTitledSeparator</code> is treated as a single component rather than 169 * a container. 170 */ 171 private void layoutSeparator() { 172 removeAll(); 173 174 //SwingX #304 fix alignment issues 175 //this is really a hacky fix, but a fix nonetheless 176 //we need a better layout approach for this class 177 int alignment = getHorizontalAlignment(); 178 179 if (!getComponentOrientation().isLeftToRight()) { 180 switch (alignment) { 181 case SwingConstants.LEFT: 182 alignment = SwingConstants.RIGHT; 183 break; 184 case SwingConstants.RIGHT: 185 alignment = SwingConstants.LEFT; 186 break; 187 case SwingConstants.EAST: 188 alignment = SwingConstants.WEST; 189 break; 190 case SwingConstants.WEST: 191 alignment = SwingConstants.EAST; 192 break; 193 default: 194 break; 195 } 196 } 197 198 switch (alignment) { 199 case SwingConstants.LEFT: 200 case SwingConstants.LEADING: 201 case SwingConstants.WEST: 202 add(label, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0,0,0,0), 0, 0)); 203 add(Box.createHorizontalStrut(3), new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0,0,0,0), 0, 0)); 204 add(rightSeparator, new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0,0,0,0), 0, 0)); 205 break; 206 case SwingConstants.RIGHT: 207 case SwingConstants.TRAILING: 208 case SwingConstants.EAST: 209 add(rightSeparator, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0,0,0,0), 0, 0)); 210 add(Box.createHorizontalStrut(3), new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0,0,0,0), 0, 0)); 211 add(label, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0,0,0,0), 0, 0)); 212 break; 213 case SwingConstants.CENTER: 214 default: 215 add(leftSeparator, new GridBagConstraints(0, 0, 1, 1, 0.5, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0,0,0,0), 0, 0)); 216 add(Box.createHorizontalStrut(3), new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0,0,0,0), 0, 0)); 217 add(label, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0,0,0,0), 0, 0)); 218 add(Box.createHorizontalStrut(3), new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0,0,0,0), 0, 0)); 219 add(rightSeparator, new GridBagConstraints(4, 0, 1, 1, 0.5, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0,0,0,0), 0, 0)); 220 } 221 } 222 223 /** 224 * Sets the title for the separator. This may be simple html, or plain 225 * text. 226 * 227 * @param title the new title. Any string input is acceptable 228 */ 229 public void setTitle(String title) { 230 String old = getTitle(); 231 label.setText(title); 232 firePropertyChange("title", old, getTitle()); 233 } 234 235 /** 236 * Gets the title. 237 * 238 * @return the title being used for this <code>JXTitledSeparator</code>. 239 * This will be the raw title text, and so may include html tags etc 240 * if they were so specified in #setTitle. 241 */ 242 public String getTitle() { 243 return label.getText(); 244 } 245 246 /** 247 * <p>Sets the alignment of the title along the X axis. If leading, then 248 * the title will lead the separator (in left-to-right languages, 249 * the title will be to the left and the separator to the right). If centered, 250 * then a separator will be to the left, followed by the title (centered), 251 * followed by a separator to the right. Trailing will have the title 252 * on the right with a separator to its left, in left-to-right languages.</p> 253 * 254 * <p>LEFT and RIGHT always position the text left or right of the separator, 255 * respectively, regardless of the language orientation.</p> 256 * 257 * @param alignment One of the following constants 258 * defined in <code>SwingConstants</code>: 259 * <code>LEFT</code>, 260 * <code>CENTER</code>, 261 * <code>RIGHT</code>, 262 * <code>LEADING</code> (the default) or 263 * <code>TRAILING</code>. 264 * 265 * @throws IllegalArgumentException if the alignment does not match one of 266 * the accepted inputs. 267 * @see SwingConstants 268 * @see #getHorizontalAlignment 269 */ 270 public void setHorizontalAlignment(int alignment) { 271 int old = getHorizontalAlignment(); 272 label.setHorizontalAlignment(alignment); 273 if (old != getHorizontalAlignment()) { 274 layoutSeparator(); 275 } 276 firePropertyChange("horizontalAlignment", old, getHorizontalAlignment()); 277 } 278 279 /** 280 * Returns the alignment of the title contents along the X axis. 281 * 282 * @return The value of the horizontalAlignment property, one of the 283 * following constants defined in <code>SwingConstants</code>: 284 * <code>LEFT</code>, 285 * <code>CENTER</code>, 286 * <code>RIGHT</code>, 287 * <code>LEADING</code> or 288 * <code>TRAILING</code>. 289 * 290 * @see #setHorizontalAlignment 291 * @see SwingConstants 292 */ 293 public int getHorizontalAlignment() { 294 return label.getHorizontalAlignment(); 295 } 296 297 /** 298 * Sets the horizontal position of the title's text, 299 * relative to the icon. 300 * 301 * @param position One of the following constants 302 * defined in <code>SwingConstants</code>: 303 * <code>LEFT</code>, 304 * <code>CENTER</code>, 305 * <code>RIGHT</code>, 306 * <code>LEADING</code>, or 307 * <code>TRAILING</code> (the default). 308 * @throws IllegalArgumentException if the position does not match one of 309 * the accepted inputs. 310 */ 311 public void setHorizontalTextPosition(int position) { 312 int old = getHorizontalTextPosition(); 313 label.setHorizontalTextPosition(position); 314 firePropertyChange("horizontalTextPosition", old, getHorizontalTextPosition()); 315 } 316 317 /** 318 * Returns the horizontal position of the title's text, 319 * relative to the icon. 320 * 321 * @return One of the following constants 322 * defined in <code>SwingConstants</code>: 323 * <code>LEFT</code>, 324 * <code>CENTER</code>, 325 * <code>RIGHT</code>, 326 * <code>LEADING</code> or 327 * <code>TRAILING</code>. 328 * 329 * @see SwingConstants 330 */ 331 public int getHorizontalTextPosition() { 332 return label.getHorizontalTextPosition(); 333 } 334 335 /** 336 * {@inheritDoc} 337 */ 338 @Override 339 public ComponentOrientation getComponentOrientation() { 340 return label.getComponentOrientation(); 341 } 342 343 /** 344 * {@inheritDoc} 345 */ 346 @Override 347 public void setComponentOrientation(ComponentOrientation o) { 348 ComponentOrientation old = label.getComponentOrientation(); 349 label.setComponentOrientation(o); 350 firePropertyChange("componentOrientation", old, label.getComponentOrientation()); 351 } 352 353 /** 354 * Defines the icon this component will display. If 355 * the value of icon is null, nothing is displayed. 356 * <p> 357 * The default value of this property is null. 358 * 359 * @see #setHorizontalTextPosition 360 * @see #getIcon 361 */ 362 public void setIcon(Icon icon) { 363 Icon old = getIcon(); 364 label.setIcon(icon); 365 firePropertyChange("icon", old, getIcon()); 366 } 367 368 /** 369 * Returns the graphic image (glyph, icon) that the 370 * <code>JXTitledSeparator</code> displays. 371 * 372 * @return an Icon 373 * @see #setIcon 374 */ 375 public Icon getIcon() { 376 return label.getIcon(); 377 } 378 379 /** 380 * {@inheritDoc} 381 */ 382 @Override 383 public void setForeground(Color foreground) { 384 if (label != null) { 385 label.setForeground(foreground); 386 } 387 super.setForeground(foreground); 388 } 389 390 /** 391 * {@inheritDoc} 392 */ 393 @Override 394 public void setFont(Font font) { 395 if (label != null) { 396 label.setFont(font); 397 } 398 super.setFont(font); 399 } 400 }