001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexander T. Simbirtsev
019: * @version $Revision$
020: */package javax.swing.border;
021:
022: import java.awt.Color;
023: import java.awt.Component;
024: import java.awt.Dimension;
025: import java.awt.Font;
026: import java.awt.FontMetrics;
027: import java.awt.Graphics;
028: import java.awt.Insets;
029: import java.awt.Rectangle;
030: import java.awt.Shape;
031:
032: import javax.swing.SwingUtilities;
033: import javax.swing.UIManager;
034:
035: import org.apache.harmony.awt.gl.MultiRectArea;
036: import org.apache.harmony.x.swing.Utilities;
037:
038: import org.apache.harmony.x.swing.internal.nls.Messages;
039:
040: public class TitledBorder extends AbstractBorder {
041:
042: public static final int DEFAULT_POSITION = 0;
043: public static final int ABOVE_TOP = 1;
044: public static final int TOP = 2;
045: public static final int BELOW_TOP = 3;
046: public static final int ABOVE_BOTTOM = 4;
047: public static final int BOTTOM = 5;
048: public static final int BELOW_BOTTOM = 6;
049:
050: public static final int DEFAULT_JUSTIFICATION = 0;
051: public static final int LEFT = 1;
052: public static final int CENTER = 2;
053: public static final int RIGHT = 3;
054: public static final int LEADING = 4;
055: public static final int TRAILING = 5;
056:
057: protected static final int EDGE_SPACING = 2;
058: protected static final int TEXT_SPACING = 2;
059: protected static final int TEXT_INSET_H = 5;
060:
061: protected String title;
062: protected int titlePosition;
063: protected int titleJustification;
064:
065: protected Border border;
066: protected Font titleFont;
067: protected Color titleColor;
068:
069: private static final String PROPERTY_PREFIX = "TitledBorder.";
070:
071: private static Border defaultBorder;
072: private static Font defaultTitleFont;
073: private static Color defaultTitleColor;
074:
075: public TitledBorder(final Border border, final String title,
076: final int titleJustification, final int titlePosition,
077: final Font titleFont, final Color titleColor) {
078: setTitleJustification(titleJustification);
079: setTitlePosition(titlePosition);
080: this .title = title;
081:
082: setBorder(border);
083: setTitleFont(titleFont);
084: setTitleColor(titleColor);
085: }
086:
087: public TitledBorder(final Border border, final String title,
088: final int titleJustification, final int titlePosition,
089: final Font titleFont) {
090: this (border, title, titleJustification, titlePosition,
091: titleFont, null);
092: }
093:
094: public TitledBorder(final Border border, final String title,
095: final int titleJustification, final int titlePosition) {
096: this (border, title, titleJustification, titlePosition, null,
097: null);
098: }
099:
100: public TitledBorder(final Border border, final String title) {
101: this (border, title, LEADING, TOP, null, null);
102: }
103:
104: public TitledBorder(final Border border) {
105: this (border, "", LEADING, TOP, null, null);
106: }
107:
108: public TitledBorder(final String title) {
109: this (null, title, LEADING, TOP, null, null);
110: }
111:
112: public Insets getBorderInsets(final Component c, final Insets insets) {
113: int spacing = EDGE_SPACING + TEXT_SPACING;
114: insets.set(spacing, spacing, spacing, spacing);
115:
116: Insets insideInsets = getBorder().getBorderInsets(c);
117: Utilities.addInsets(insets, insideInsets);
118:
119: if (!Utilities.isEmptyString(title) && c != null) {
120: FontMetrics metrics = c.getFontMetrics(getTitleFont());
121: switch (titlePosition) {
122: case DEFAULT_POSITION:
123: case TOP:
124: insets.top += metrics.getHeight() - TEXT_SPACING;
125: break;
126: case ABOVE_TOP:
127: case BELOW_TOP:
128: insets.top += metrics.getHeight();
129: break;
130: case ABOVE_BOTTOM:
131: case BELOW_BOTTOM:
132: insets.bottom += metrics.getHeight();
133: break;
134: case BOTTOM:
135: insets.bottom += metrics.getHeight() - TEXT_SPACING;
136: }
137: }
138:
139: return insets;
140: }
141:
142: public Insets getBorderInsets(final Component c) {
143: return getBorderInsets(c, new Insets(0, 0, 0, 0));
144: }
145:
146: public void paintBorder(final Component c, final Graphics g,
147: final int x, final int y, final int width, final int height) {
148: Color oldColor = g.getColor();
149: Font oldFont = g.getFont();
150: Border innerBorder = getBorder();
151: Insets borderInsets = innerBorder.getBorderInsets(c);
152:
153: Font font = getTitleFont();
154: FontMetrics metrics = c.getFontMetrics(font);
155: int stringWidth = metrics.stringWidth(title);
156: int stringHeight = metrics.getHeight();
157: int borderTopInset = 0;
158: int borderHeight = height;
159: int titleTopInset = (metrics.getAscent() - metrics.getDescent()) / 2;
160: int titleLeftInset = 0;
161: boolean titleOverBorder = false;
162: Shape oldClip = g.getClip();
163:
164: if (!Utilities.isEmptyString(title)) {
165: switch (convertLeadTrail(titleJustification, c)) {
166: case DEFAULT_JUSTIFICATION:
167: case LEFT:
168: titleLeftInset = EDGE_SPACING + 2 * TEXT_SPACING
169: + borderInsets.left;
170: break;
171: case CENTER:
172: titleLeftInset = (width - stringWidth) / 2;
173: break;
174: case RIGHT:
175: titleLeftInset = width - stringWidth
176: - borderInsets.right - 2 * TEXT_SPACING
177: - EDGE_SPACING;
178: break;
179: }
180:
181: switch (titlePosition) {
182: case ABOVE_TOP:
183: borderTopInset = stringHeight;
184: titleTopInset += stringHeight / 2 + EDGE_SPACING;
185: borderHeight -= borderTopInset;
186: break;
187: case DEFAULT_POSITION:
188: case TOP:
189: borderTopInset = metrics.getAscent() / 2;
190: titleTopInset += borderTopInset + borderInsets.top / 2
191: + EDGE_SPACING;
192: borderHeight -= borderTopInset;
193: titleOverBorder = (stringHeight > borderInsets.top);
194: break;
195: case BELOW_TOP:
196: titleTopInset += borderInsets.top + stringHeight / 2
197: + EDGE_SPACING + TEXT_SPACING;
198: break;
199: case ABOVE_BOTTOM:
200: titleTopInset += height - borderInsets.bottom
201: - stringHeight / 2 - EDGE_SPACING
202: - TEXT_SPACING;
203: break;
204: case BOTTOM:
205: titleTopInset += height - borderInsets.bottom / 2
206: - stringHeight / 2 - EDGE_SPACING;
207: borderHeight -= metrics.getAscent() / 2 + EDGE_SPACING
208: + 1;
209: titleOverBorder = (stringHeight > borderInsets.bottom);
210: break;
211: case BELOW_BOTTOM:
212: titleTopInset += height - stringHeight / 2 - 1;
213: borderHeight -= stringHeight + 1;
214: break;
215: }
216:
217: if (titleOverBorder) {
218: Rectangle titleRect = new Rectangle(x + titleLeftInset
219: - 1, y - stringHeight + titleTopInset
220: - TEXT_SPACING, stringWidth + TEXT_SPACING,
221: stringHeight + 2 * TEXT_SPACING);
222:
223: if (titleRect.intersects(g.getClipBounds())) {
224: Rectangle[] difference = SwingUtilities
225: .computeDifference(g.getClipBounds(),
226: titleRect);
227: MultiRectArea clipArea = new MultiRectArea(
228: difference);
229: g.setClip(clipArea);
230: }
231: }
232: }
233:
234: innerBorder.paintBorder(c, g, x + EDGE_SPACING, y
235: + EDGE_SPACING + borderTopInset, width - 2
236: * EDGE_SPACING, borderHeight - 2 * EDGE_SPACING);
237:
238: g.setClip(oldClip);
239: if (!Utilities.isEmptyString(title)) {
240: g.setColor(getTitleColor());
241: g.setFont(font);
242: g.drawString(title, x + titleLeftInset, y + titleTopInset);
243: }
244:
245: g.setColor(oldColor);
246: g.setFont(oldFont);
247: }
248:
249: public Dimension getMinimumSize(final Component c) {
250: int width = 0;
251: if (!Utilities.isEmptyString(title)) {
252: FontMetrics metrics = c.getFontMetrics(getTitleFont());
253: if (titlePosition != ABOVE_BOTTOM
254: && titlePosition != ABOVE_TOP) {
255: width += metrics.stringWidth(title);
256: } else {
257: width = Math.max(width, metrics.stringWidth(title));
258: }
259: }
260:
261: return Utilities.addInsets(new Dimension(width, 0),
262: getBorderInsets(c));
263: }
264:
265: public void setTitle(final String title) {
266: this .title = title;
267: }
268:
269: public String getTitle() {
270: return title;
271: }
272:
273: public void setBorder(final Border border) {
274: this .border = border;
275: }
276:
277: public Border getBorder() {
278: return (border != null) ? border : getDefaultBorder();
279: }
280:
281: public void setTitleFont(final Font font) {
282: titleFont = font;
283: }
284:
285: public Font getTitleFont() {
286: return (titleFont != null) ? titleFont : getDefaultTitleFont();
287: }
288:
289: public void setTitleColor(final Color color) {
290: titleColor = color;
291: }
292:
293: public Color getTitleColor() {
294: return (titleColor != null) ? titleColor
295: : getDefaultTitleColor();
296: }
297:
298: public void setTitlePosition(final int pos) {
299: if (pos < DEFAULT_POSITION || BELOW_BOTTOM < pos) {
300: throw new IllegalArgumentException(Messages.getString(
301: "swing.24", pos)); //$NON-NLS-1$
302: }
303: titlePosition = pos;
304: }
305:
306: public int getTitlePosition() {
307: return titlePosition;
308: }
309:
310: public void setTitleJustification(final int justification) {
311: if (justification < DEFAULT_JUSTIFICATION
312: || TRAILING < justification) {
313: throw new IllegalArgumentException(Messages.getString(
314: "swing.23", justification)); //$NON-NLS-1$
315: }
316: titleJustification = justification;
317: }
318:
319: public int getTitleJustification() {
320: return titleJustification;
321: }
322:
323: public boolean isBorderOpaque() {
324: return false;
325: }
326:
327: protected Font getFont(final Component c) {
328: return getTitleFont();
329: }
330:
331: private static Font getDefaultTitleFont() {
332: return (defaultTitleFont != null) ? defaultTitleFont
333: : UIManager.getDefaults().getFont(
334: PROPERTY_PREFIX + "font");
335: }
336:
337: private static Color getDefaultTitleColor() {
338: return (defaultTitleColor != null) ? defaultTitleColor
339: : UIManager.getDefaults().getColor(
340: PROPERTY_PREFIX + "titleColor");
341: }
342:
343: private Border getDefaultBorder() {
344: return (defaultBorder != null) ? defaultBorder : UIManager
345: .getDefaults().getBorder(PROPERTY_PREFIX + "border");
346: }
347:
348: private static int convertLeadTrail(final int pos, final Component c) {
349: final boolean isLTR = (c == null)
350: || c.getComponentOrientation().isLeftToRight();
351: if (pos == LEADING) {
352: return isLTR ? LEFT : RIGHT;
353: }
354: if (pos == TRAILING) {
355: return isLTR ? RIGHT : LEFT;
356: }
357: return pos;
358: }
359: }
|