001: /*
002: * Copyright (c) 2004 JETA Software, Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without modification,
005: * are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JETA Software nor the names of its contributors may
015: * be used to endorse or promote products derived from this software without
016: * specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
021: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
022: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
023: * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
024: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
025: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026: * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: */
029:
030: package com.jeta.forms.components.border;
031:
032: import java.awt.Color;
033: import java.awt.Dimension;
034: import java.awt.Font;
035: import java.awt.FontMetrics;
036: import java.awt.Graphics;
037: import java.awt.Insets;
038: import java.awt.Rectangle;
039:
040: import javax.swing.JComponent;
041: import javax.swing.UIManager;
042: import javax.swing.border.Border;
043: import javax.swing.border.TitledBorder;
044: import javax.swing.plaf.ComponentUI;
045:
046: /**
047: * The UI for a component that simulates the top part of a TitledBorder. This
048: * component is useful when flattening layouts. It allows a titled border to be
049: * used to separate components, while allowing those components to stay in the
050: * same row or column of the form. This allows components to have the same x,y,
051: * width, or height, yet have differnt title borders. This is not possible when
052: * using standard TitledBorder.
053: *
054: * @author Jeff Tassin
055: */
056: public class TitledBorderLabelUI extends ComponentUI {
057: static protected final int VERTICAL_PADDING = 2;
058:
059: /**
060: * Determines the intersection of two rectangles. The first rectangle is
061: * specified by a Rectangle object. The second rectangle is specified by x,
062: * y, width, and height parameters. The first rectangle is set to the
063: * resulting intersection if any.
064: *
065: * @return true if the rectangles intersect.
066: */
067: private boolean calcIntersection(Rectangle rect, int x, int y,
068: int width, int height) {
069: int x1 = Math.max(x, rect.x);
070: int y1 = Math.max(y, rect.y);
071:
072: int x2 = Math.min(x + width, rect.x + rect.width);
073: int y2 = Math.min(y + height, rect.y + rect.height);
074:
075: rect.setBounds(x1, y1, x2 - x1, y2 - y1);
076:
077: if (rect.width <= 0 || rect.height <= 0)
078: return false;
079: else
080: return true;
081: }
082:
083: /**
084: * Calculates the preferred size for a TitledBorderLabel
085: */
086: public Dimension getPreferredSize(JComponent c) {
087: if (c instanceof TitledBorderLabel) {
088: TitledBorderLabel label = (TitledBorderLabel) c;
089: String title = label.getText();
090: if (title != null) {
091: Font font = label.getFont();
092: FontMetrics metrics = label.getFontMetrics(font);
093: /** add 4 pixels to line height for padding */
094: int line_height = metrics.getHeight() + 4;
095: /** add 10 pixels to label width for padding */
096: int line_width = metrics.stringWidth(title) + 10;
097: return new Dimension(line_width, line_height);
098: }
099: }
100: return new Dimension(10, 10);
101: }
102:
103: /**
104: * Renders the border and label using the current look and feel.
105: *
106: * @param g
107: * the <code>Graphics</code> context in which to paint
108: * @param c
109: * the component being painted;
110: */
111: public void paint(Graphics g, JComponent c) {
112: Border border = UIManager.getBorder("TitledBorder.border");
113: if (c instanceof TitledBorderLabel && border != null) {
114: TitledBorderLabel bordercomp = (TitledBorderLabel) c;
115: String title = bordercomp.getText();
116: if (title == null)
117: title = "";
118:
119: int width = c.getWidth();
120: int height = c.getHeight();
121:
122: Font oldfont = g.getFont();
123: Color oldcolor = g.getColor();
124: Insets insets = border.getBorderInsets(c);
125:
126: g.setFont(bordercomp.getFont());
127: FontMetrics fm = g.getFontMetrics();
128: int stringWidth = fm.stringWidth(title);
129:
130: int border_y = fm.getAscent() / 2 + VERTICAL_PADDING;
131: int text_y = (border_y - fm.getDescent())
132: + (insets.top + fm.getAscent() + fm.getDescent())
133: / 2;
134: int text_x = 0;
135:
136: int justification = bordercomp.getTitleJustification();
137: if (c.getComponentOrientation().isLeftToRight()) {
138: if (justification == TitledBorder.TRAILING)
139: justification = TitledBorder.RIGHT;
140: } else {
141: if (justification == TitledBorder.LEADING
142: || justification == TitledBorder.DEFAULT_JUSTIFICATION)
143: justification = TitledBorder.RIGHT;
144: }
145:
146: if (justification == TitledBorder.RIGHT)
147: text_x = width
148: - (stringWidth + insets.right + insets.left);
149: else if (justification == TitledBorder.CENTER)
150: text_x = (width - stringWidth) / 2;
151: else
152: text_x = insets.left;
153:
154: Rectangle clip = new Rectangle();
155: Rectangle oldclip = g.getClipBounds();
156:
157: if (title.length() == 0) {
158: /**
159: * paint the border at offsets of 12 pixels so we don't include
160: * the corners.
161: */
162: border.paintBorder(c, g, -12, border_y, width + 24,
163: height + 12);
164: } else {
165: clip.setBounds(oldclip);
166: /** horizontal line to the left of title */
167: if (calcIntersection(clip, 0, 0, text_x - 1, height)) {
168: g.setClip(clip);
169: /**
170: * paint the border at offsets of 12 pixels so we don't
171: * include the corners
172: */
173: border.paintBorder(c, g, -12, border_y, width,
174: height + 12);
175: }
176:
177: clip.setBounds(oldclip);
178: /** horizontal line to the right of title */
179: if (calcIntersection(clip, text_x + stringWidth + 1, 0,
180: width - (text_x + stringWidth + 1), height)) {
181: g.setClip(clip);
182: /**
183: * paint the border at offsets of 12 pixels so we don't
184: * include the corners
185: */
186: border.paintBorder(c, g, 0, border_y, width + 12,
187: height + 12);
188: }
189:
190: /** restore the original clipping rectangle */
191: g.setClip(oldclip);
192:
193: g.setColor(bordercomp.getTitleColor());
194: g.drawString(title, text_x, text_y);
195: }
196:
197: /** restore original font and color */
198: g.setFont(oldfont);
199: g.setColor(oldcolor);
200:
201: }
202: }
203:
204: }
|