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 }