001: /*
002: * Copyright (C) 2004 NNL Technology AB
003: * Visit www.infonode.net for information about InfoNode(R)
004: * products and how to contact NNL Technology AB.
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
019: * MA 02111-1307, USA.
020: */
021:
022: // $Id: OpenContentBorder.java,v 1.29 2005/07/17 14:29:05 johan Exp $
023: package net.infonode.tabbedpanel.border;
024:
025: import net.infonode.gui.GraphicsUtil;
026: import net.infonode.gui.colorprovider.ColorProvider;
027: import net.infonode.gui.colorprovider.ColorProviderUtil;
028: import net.infonode.gui.colorprovider.FixedColorProvider;
029: import net.infonode.gui.colorprovider.UIManagerColorProvider;
030: import net.infonode.tabbedpanel.Tab;
031: import net.infonode.tabbedpanel.TabbedPanel;
032: import net.infonode.tabbedpanel.TabbedUtils;
033: import net.infonode.util.Direction;
034:
035: import javax.swing.*;
036: import javax.swing.border.Border;
037: import java.awt.*;
038: import java.awt.geom.PathIterator;
039: import java.io.Serializable;
040:
041: /**
042: * <p>
043: * OpenContentBorder is a border that draws a 1 pixel wide line border around a
044: * component that is used as content area component in a tabbed panel. The border
045: * also optionally draws a highlight inside the line on the top and left sides of the
046: * component. It is open, i.e. no content border will be drawn where the highlighted
047: * tab in the tabbed panel is located.
048: * </p>
049: *
050: * <p>
051: * If the highlighted tab has a {@link net.infonode.gui.shaped.border.ShapedBorder} its
052: * shape will be used to calculate where the OpenContentBorder should be open.
053: * </p>
054: *
055: * @author $Author: johan $
056: * @version $Revision: 1.29 $
057: * @see TabbedPanel
058: */
059: public class OpenContentBorder implements Border, Serializable {
060: private static final long serialVersionUID = 1;
061:
062: private ColorProvider topLeftLineColor;
063: private ColorProvider bottomRightLineColor;
064: private ColorProvider highlightColorProvider;
065: private int tabLeftInset = 1;
066:
067: /**
068: * Constructor.
069: *
070: * @param color the line color
071: * @param tabLeftInset the left border inset of the tab
072: */
073: public OpenContentBorder(Color color, int tabLeftInset) {
074: this (color);
075: this .tabLeftInset = tabLeftInset;
076: }
077:
078: /**
079: * Constructor. Uses the TabbedPane.darkShadow color from the UIManager as line color.
080: */
081: public OpenContentBorder() {
082: this (null);
083: }
084:
085: /**
086: * Constructs a OpenContentBorder without highlight and with the given color as line
087: * color.
088: *
089: * @param color the line color
090: */
091: public OpenContentBorder(Color color) {
092: this (color, null);
093: }
094:
095: /**
096: * Constructs a OpenContentBorder with highlight and with the given colors as line
097: * color and highlight color.
098: *
099: * @param color the line color
100: * @param highlightColor the highlight color
101: */
102: public OpenContentBorder(Color color, Color highlightColor) {
103: this (ColorProviderUtil.getColorProvider(color,
104: UIManagerColorProvider.TABBED_PANE_DARK_SHADOW),
105: highlightColor == null ? null : new FixedColorProvider(
106: highlightColor), 1);
107: }
108:
109: /**
110: * Constructs a OpenContentBorder with highlight and with the given colors as line
111: * color and highlight color.
112: *
113: * @param lineColor the line color provider
114: * @param highlightColorProvider the highlight color provider
115: * @param tabLeftInset the left border inset of the tab
116: */
117: public OpenContentBorder(ColorProvider lineColor,
118: ColorProvider highlightColorProvider, int tabLeftInset) {
119: this (lineColor, lineColor, highlightColorProvider, tabLeftInset);
120: }
121:
122: /**
123: * Constructs a OpenContentBorder with highlight and with the given colors as line
124: * color and highlight color.
125: *
126: * @param topLeftLineColor the line color provider for the top and left lines
127: * @param bottomRightLineColor the line color provider for the bottom and right lines
128: * @param highlightColorProvider the highlight color provider
129: * @param tabLeftInset the left border inset of the tab
130: */
131: public OpenContentBorder(ColorProvider topLeftLineColor,
132: ColorProvider bottomRightLineColor,
133: ColorProvider highlightColorProvider, int tabLeftInset) {
134: this .topLeftLineColor = topLeftLineColor;
135: this .bottomRightLineColor = bottomRightLineColor;
136: this .highlightColorProvider = highlightColorProvider;
137: this .tabLeftInset = tabLeftInset;
138: }
139:
140: private static int getLineIntersection(int edge, float x1,
141: float y1, float x2, float y2, Direction orientation) {
142: return (orientation.isHorizontal() ?
143:
144: ((x1 <= edge && x2 >= edge) || (x1 >= edge && x2 <= edge) ? Math
145: .round(x2 == x1 ? y2 : y1 + (edge - x1) * (y2 - y1)
146: / (x2 - x1))
147: : Integer.MAX_VALUE)
148: :
149:
150: ((y1 <= edge && y2 >= edge)
151: || (y1 >= edge && y2 <= edge) ? Math
152: .round(y2 == y1 ? x2 : x1 + (edge - y1)
153: * (x2 - x1) / (y2 - y1))
154: : Integer.MAX_VALUE));
155: }
156:
157: private static Point getTabBounds(Component c, Tab tab,
158: Direction orientation, int x, int y, int width, int height) {
159: Rectangle r = tab.getVisibleRect();
160: r = SwingUtilities.convertRectangle(tab, r, c);
161: int start = orientation.isHorizontal() ? Math.max(y, r.y)
162: : Math.max(x, r.x);
163: int end = start
164: + (orientation.isHorizontal() ? r.height : r.width) - 1;
165: Shape shape = tab.getShape();
166:
167: if (shape != null) {
168: int edge = orientation == Direction.UP ? tab.getHeight()
169: : orientation == Direction.RIGHT ? -1
170: : orientation == Direction.DOWN ? -1 : tab
171: .getWidth();
172:
173: float[] coords = new float[6];
174: PathIterator it = shape.getPathIterator(null);
175: it.currentSegment(coords);
176: it.next();
177: float x1 = coords[0];
178: float y1 = coords[1];
179: int min = Integer.MAX_VALUE;
180: int max = Integer.MIN_VALUE;
181:
182: for (; !it.isDone(); it.next()) {
183: float lastX = coords[0];
184: float lastY = coords[1];
185: int type = it.currentSegment(coords);
186: int li = getLineIntersection(edge, lastX, lastY,
187: coords[0], coords[1], orientation);
188:
189: if (li != Integer.MAX_VALUE) {
190: if (li < min)
191: min = li;
192:
193: if (li > max)
194: max = li;
195: }
196: }
197:
198: int li = getLineIntersection(edge, coords[0], coords[1],
199: x1, y1, orientation);
200:
201: if (li != Integer.MAX_VALUE) {
202: if (li < min)
203: min = li;
204:
205: if (li > max)
206: max = li;
207: }
208:
209: Point p0 = SwingUtilities.convertPoint(tab, 0, 0, c);
210:
211: if (orientation.isHorizontal()) {
212: min += p0.y;
213: max += p0.y;
214: } else {
215: min += p0.x;
216: max += p0.x;
217: }
218:
219: start = Math.max(start, min);
220: end = Math.min(end, max);
221: }
222:
223: return new Point(start, end);
224: }
225:
226: public void paintBorder(Component c, Graphics g, int x, int y,
227: int width, int height) {
228: TabbedPanel tabbedPanel = TabbedUtils
229: .getParentTabbedPanelContentPanel(c).getTabbedPanel();
230:
231: if (c != null && tabbedPanel != null) {
232: Tab tab = tabbedPanel.getHighlightedTab();
233: int tabStart = -1;
234: int tabEnd = -1;
235: int clipOffset = 0;
236: Direction orientation = tabbedPanel.getProperties()
237: .getTabAreaOrientation();
238:
239: if (tab != null) {
240: Point p = getTabBounds(c, tab, orientation, x, y,
241: width, height);
242: tabStart = p.x;
243: tabEnd = p.y;
244:
245: Rectangle visible = tab.getVisibleRect();
246: int tabWidth = (int) visible.getWidth();
247: int tabHeight = (int) visible.getHeight();
248: clipOffset = (orientation.isHorizontal() ? tab
249: .getHeight() > tabHeight
250: : tab.getWidth() > tabWidth) ? -1 : 0;
251: }
252:
253: Color topLeftColor = topLeftLineColor != null ? topLeftLineColor
254: .getColor(c)
255: : null;
256: Color bottomRightColor = bottomRightLineColor != null ? bottomRightLineColor
257: .getColor(c)
258: : null;
259: Color hc1 = highlightColorProvider == null ? null
260: : highlightColorProvider.getColor(c);
261:
262: if (orientation == Direction.UP && tab != null) {
263: if (topLeftColor != null) {
264: g.setColor(topLeftColor);
265: drawLine(g, x, y, tabStart - 1 + tabLeftInset, y);
266: drawLine(g, tabEnd - clipOffset, y, x + width - 1,
267: y);
268: }
269:
270: if (highlightColorProvider != null) {
271: g.setColor(hc1);
272: drawLine(g, x + 1, y + 1, tabStart + tabLeftInset
273: - 1, y + 1);
274:
275: if (tabEnd > tabStart)
276: drawLine(g, tabStart + tabLeftInset, y,
277: tabStart + tabLeftInset, y + 1);
278:
279: drawLine(g, tabEnd, y + 1, x + width - 3, y + 1);
280: }
281: } else {
282: if (topLeftColor != null) {
283: g.setColor(topLeftColor);
284: drawLine(g, x, y, x + width - 1, y);
285: }
286:
287: if (highlightColorProvider != null) {
288: g.setColor(hc1);
289: drawLine(g, x + 1, y + 1, x
290: + width
291: - (orientation == Direction.RIGHT
292: && tabStart == 0 ? 1 : 3), y + 1);
293: }
294: }
295:
296: if (orientation == Direction.LEFT && tab != null) {
297: if (topLeftColor != null) {
298: g.setColor(topLeftColor);
299: drawLine(g, x, y + 1, x, tabStart - 1
300: + tabLeftInset);
301: drawLine(g, x, tabEnd - clipOffset, x, y + height
302: - 1);
303: }
304:
305: if (highlightColorProvider != null) {
306: g.setColor(hc1);
307: drawLine(g, x + 1, y + 2, x + 1, tabStart
308: + tabLeftInset - 1);
309:
310: if (tabEnd > tabStart)
311: drawLine(g, x, tabStart + tabLeftInset, x + 1,
312: tabStart + tabLeftInset);
313:
314: drawLine(g, x + 1, tabEnd, x + 1, y + height - 3);
315: }
316: } else {
317: if (topLeftColor != null) {
318: g.setColor(topLeftColor);
319: drawLine(g, x, y + 1, x, y + height - 1);
320: }
321:
322: if (highlightColorProvider != null) {
323: g.setColor(hc1);
324: drawLine(g, x + 1, y + 2, x + 1, y
325: + height
326: - (orientation == Direction.DOWN
327: && tabStart == 0 ? 1 : 3));
328: }
329: }
330:
331: if (bottomRightColor != null) {
332: g.setColor(bottomRightColor);
333:
334: if (orientation == Direction.RIGHT && tab != null) {
335: drawLine(g, x + width - 1, y + 1, x + width - 1,
336: tabStart - 1 + tabLeftInset);
337: drawLine(g, x + width - 1, tabEnd - clipOffset, x
338: + width - 1, y + height - 1);
339: } else {
340: drawLine(g, x + width - 1, y + 1, x + width - 1, y
341: + height - 1);
342: }
343:
344: if (orientation == Direction.DOWN && tab != null) {
345: g.setColor(bottomRightColor);
346: drawLine(g, x + 1, y + height - 1, tabStart - 1
347: + tabLeftInset, y + height - 1);
348: drawLine(g, tabEnd - clipOffset, y + height - 1, x
349: + width - 2, y + height - 1);
350: } else {
351: drawLine(g, x + 1, y + height - 1, x + width - 2, y
352: + height - 1);
353: }
354: }
355: }
356: }
357:
358: private static void drawLine(Graphics graphics, int x1, int y1,
359: int x2, int y2) {
360: if (x2 < x1 || y2 < y1)
361: return;
362:
363: GraphicsUtil.drawOptimizedLine(graphics, x1, y1, x2, y2);
364: //graphics.drawLine(x1, y1, x2, y2);
365: }
366:
367: public Insets getBorderInsets(Component c) {
368: int hInset = highlightColorProvider != null ? 1 : 0;
369: int tlInset = (topLeftLineColor != null ? 1 : 0) + hInset;
370: int brInset = bottomRightLineColor != null ? 1 : 0;
371: return new Insets(tlInset, tlInset, brInset, brInset);
372: }
373:
374: public boolean isBorderOpaque() {
375: return true;
376: }
377:
378: }
|