0001: /*
0002: * Copyright (C) 2004 NNL Technology AB
0003: * Visit www.infonode.net for information about InfoNode(R)
0004: * products and how to contact NNL Technology AB.
0005: *
0006: * This program is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU General Public License
0008: * as published by the Free Software Foundation; either version 2
0009: * of the License, or (at your option) any later version.
0010: *
0011: * This program is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0014: * GNU General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU General Public License
0017: * along with this program; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
0019: * MA 02111-1307, USA.
0020: */
0021:
0022: // $Id: PaneUI.java,v 1.20 2005/12/04 13:46:05 jesper Exp $
0023: package net.infonode.tabbedpanel.theme.internal.laftheme;
0024:
0025: import net.infonode.gui.InsetsUtil;
0026: import net.infonode.gui.draggable.DraggableComponentBox;
0027: import net.infonode.tabbedpanel.Tab;
0028: import net.infonode.tabbedpanel.TabbedPanel;
0029: import net.infonode.tabbedpanel.TabbedPanelContentPanel;
0030: import net.infonode.util.Direction;
0031:
0032: import javax.swing.*;
0033: import java.awt.*;
0034: import java.awt.image.BufferedImage;
0035: import java.awt.image.FilteredImageSource;
0036: import java.awt.image.RGBImageFilter;
0037:
0038: public class PaneUI {
0039: private static final boolean PAINT_TAB_AREA = true;
0040:
0041: private static final boolean PAINT_CONTENT_AREA = true;
0042:
0043: private static final boolean PAINT_TAB = true;
0044:
0045: private static final boolean TEXT_ICON_GAP_COMPENSATE = true;
0046:
0047: private static final int DEFAULT_SELECTED_INDEX = 3;
0048:
0049: private static final int DEFAULT_TAB_COUNT = 7;
0050:
0051: private static final int EXTRA_SIZE = 2;
0052:
0053: private static final String EMPTY_STRING = "";
0054:
0055: // Order is IMPORTANT!!!
0056: private static final Direction[] DIRECTIONS = new Direction[] {
0057: Direction.UP, Direction.LEFT, Direction.DOWN,
0058: Direction.RIGHT };
0059:
0060: private Insets[] areaInsets = new Insets[DIRECTIONS.length];
0061:
0062: private Insets[] normalInsets = new Insets[DIRECTIONS.length];
0063:
0064: private Insets[] selectedInsets = new Insets[DIRECTIONS.length];
0065:
0066: private Insets[] adjustedContentInsets = new Insets[DIRECTIONS.length];
0067:
0068: private Insets[] adjustedContentInsetsTabAreaHidden = new Insets[DIRECTIONS.length];
0069:
0070: private Insets[] contentInsets = new Insets[DIRECTIONS.length];
0071:
0072: private Dimension[] minimumSizes = new Dimension[DIRECTIONS.length];
0073:
0074: private Dimension[] tabMinimumSizes = new Dimension[DIRECTIONS.length];
0075:
0076: private int[] spacings = new int[DIRECTIONS.length];
0077:
0078: private int[] raiseds = new int[DIRECTIONS.length];
0079:
0080: private Insets[] tabInsets = new Insets[DIRECTIONS.length];
0081:
0082: private Color[] contentTabAreaBorderColors = new Color[DIRECTIONS.length];
0083:
0084: private boolean[] swapWidthHeights = new boolean[DIRECTIONS.length];
0085:
0086: private boolean tabAreaNotVisibleFix = false;
0087:
0088: private int scrollOffset = 0;
0089:
0090: private int textIconGap;
0091:
0092: private PaneUIListener listener;
0093:
0094: private static ComponentCache componentCache = new ComponentCache();
0095:
0096: private PaneHandler paneHandler = new PaneHandler(
0097: new PaneHandlerListener() {
0098: public void updating() {
0099: setEnabled(false);
0100: listener.updating();
0101: }
0102:
0103: public void updated() {
0104: doInit();
0105: setEnabled(true);
0106: listener.updated();
0107: }
0108: });
0109:
0110: private Tab hoveredTab;
0111:
0112: private TabData tabData = new TabData();
0113:
0114: private boolean tabAreaOpaque;
0115:
0116: private boolean contentOpaque;
0117:
0118: private boolean opaque;
0119:
0120: private boolean tabAreaComponentsOpaque;
0121:
0122: private boolean enabled = true;
0123:
0124: public PaneUI(final PaneUIListener listener) {
0125: this .listener = listener;
0126: }
0127:
0128: public void init() {
0129: paneHandler.update();
0130: }
0131:
0132: private void doInit() {
0133: initPreCommonValues();
0134:
0135: for (int i = 0; i < DIRECTIONS.length; i++) {
0136: PanePainter pane = paneHandler.getPainter(DIRECTIONS[i]);
0137: initValues(pane, i, DIRECTIONS[i]);
0138: reset(pane);
0139: }
0140:
0141: initPostCommonValues();
0142: }
0143:
0144: public void dispose() {
0145: enabled = false;
0146: paneHandler.dispose();
0147: }
0148:
0149: public void setEnabled(final boolean enabled) {
0150: this .enabled = enabled;
0151: }
0152:
0153: private void initPreCommonValues() {
0154: {
0155: // Hack for some look and feels
0156: tabAreaNotVisibleFix = UIManager.getLookAndFeel()
0157: .getClass().getName()
0158: .indexOf(".WindowsLookAndFeel") > -1;
0159: }
0160:
0161: {
0162: // Icon text gap
0163: textIconGap = UIManager.getInt("TabbedPane.textIconGap");
0164: if (textIconGap <= 0)
0165: textIconGap = 4;
0166: }
0167:
0168: {
0169: // Opaque
0170: opaque = paneHandler.getPainter(Direction.UP).isOpaque();
0171:
0172: Boolean contentOp = (Boolean) UIManager
0173: .get("TabbedPane.contentOpaque");
0174: if (contentOp == null)
0175: contentOpaque = opaque;
0176: else
0177: contentOpaque = contentOp.booleanValue();
0178:
0179: tabAreaOpaque = opaque;
0180:
0181: tabAreaComponentsOpaque = false;
0182: }
0183: }
0184:
0185: private void initPostCommonValues() {
0186: {
0187: // Scroll offset
0188: for (int i = 0; i < DIRECTIONS.length; i++)
0189: scrollOffset = Math.max(scrollOffset, Math.max(
0190: minimumSizes[i].width, minimumSizes[i].height));
0191: }
0192: }
0193:
0194: private void initValues(PanePainter pane, int index,
0195: Direction direction) {
0196: estimateSwappedTabDirection(pane, index, direction);
0197:
0198: reset(pane);
0199:
0200: pane.setSize(1000, 1000);
0201:
0202: boolean upDown = !direction.isHorizontal();
0203:
0204: for (int i = 0; i < DEFAULT_TAB_COUNT; i++) {
0205: pane.addTab(EMPTY_STRING, getComponent());
0206: }
0207:
0208: pane.setSelectedIndex(DEFAULT_SELECTED_INDEX);
0209:
0210: pane.doValidation();
0211:
0212: {
0213: // Tab insets if any from UImanager
0214: Insets insets = UIManager.getInsets("TabbedPane.tabInsets");
0215: if (insets == null)
0216: insets = new Insets(0, 0, 0, 0);
0217:
0218: if (!upDown)
0219: tabInsets[index] = new Insets(0, insets.left, 0,
0220: insets.right);
0221: else
0222: tabInsets[index] = InsetsUtil.EMPTY_INSETS;
0223: }
0224:
0225: {
0226: // Raised
0227: Rectangle bounds = pane.getBoundsAt(0);
0228: Rectangle bounds2 = pane.getBoundsAt(pane
0229: .getSelectedIndex());
0230:
0231: if (direction == Direction.UP)
0232: raiseds[index] = Math.max(0, bounds.y - bounds2.y);
0233: else if (direction == Direction.LEFT)
0234: raiseds[index] = Math.max(0, bounds.x - bounds2.x);
0235: else if (direction == Direction.DOWN)
0236: raiseds[index] = raiseds[getDirectionIndex(Direction.UP)];
0237: else
0238: raiseds[index] = raiseds[getDirectionIndex(Direction.LEFT)];
0239: }
0240:
0241: {
0242: // Spacing
0243: Insets normal = getCalculatedInsets(pane, 0, false,
0244: direction);
0245: Insets selected = getCalculatedInsets(pane, 0, true,
0246: direction);
0247:
0248: if (upDown)
0249: spacings[index] = normal.left + normal.right
0250: - selected.left - selected.right;
0251: else
0252: spacings[index] = normal.top + normal.bottom
0253: - selected.top - selected.bottom;
0254: }
0255:
0256: {
0257: // Normal insets
0258: normalInsets[index] = getCalculatedInsets(pane, 0, false,
0259: direction);
0260: }
0261:
0262: {
0263: // Selected insets
0264: Insets insets = getCalculatedInsets(pane, 0, true,
0265: direction);
0266: int spacing = spacings[index];
0267: int spaceFirst = spacing / 2;
0268: int spaceAfter = spacing / 2 + spacing % 2;
0269:
0270: if (direction == Direction.UP) {
0271: insets.bottom = normalInsets[index].bottom;
0272: insets.top = normalInsets[index].top;
0273: insets.left += spaceFirst;
0274: insets.right += spaceAfter;
0275: } else if (direction == Direction.LEFT) {
0276: insets.right = normalInsets[index].right;
0277: insets.left = normalInsets[index].left;
0278: insets.top += spaceFirst;
0279: insets.bottom += spaceAfter;
0280: } else if (direction == Direction.RIGHT) {
0281: insets.right = normalInsets[index].right;
0282: insets.left = normalInsets[index].left;
0283: insets.top += spaceFirst;
0284: insets.bottom += spaceAfter;
0285: } else {
0286: insets.bottom = normalInsets[index].bottom;
0287: insets.top = normalInsets[index].top;
0288: insets.left += spaceFirst;
0289: insets.right += spaceAfter;
0290: }
0291:
0292: selectedInsets[index] = insets;
0293: }
0294:
0295: {
0296: // Content insets
0297: JPanel c = new JPanel();
0298: pane.addTab(EMPTY_STRING, c);
0299: pane.setSelectedIndex(pane.getTabCount() - 1);
0300: pane.doValidation();
0301:
0302: Point l = SwingUtilities.convertPoint(c.getParent(), c
0303: .getLocation(), pane);
0304:
0305: Rectangle bounds = pane.getBoundsAt(0);
0306: int top = 0;
0307: int left = 0;
0308: int bottom = 0;
0309: int right = 0;
0310:
0311: if (direction == Direction.UP) {
0312: top = l.y - bounds.height - bounds.y;
0313: left = l.x;
0314: bottom = pane.getHeight() - l.y - c.getHeight();
0315: right = pane.getWidth() - l.x - c.getWidth();
0316: } else if (direction == Direction.DOWN) {
0317: top = l.y;
0318: left = l.x;
0319: bottom = pane.getHeight() - c.getHeight() - l.y
0320: - (pane.getHeight() - bounds.y);
0321: right = pane.getWidth() - l.x - c.getWidth();
0322: } else if (direction == Direction.LEFT) {
0323: top = l.y;
0324: left = l.x - bounds.width - bounds.x;
0325: bottom = pane.getHeight() - l.y - c.getHeight();
0326: right = pane.getWidth() - l.x - c.getWidth();
0327: } else {
0328: top = l.y;
0329: left = l.x;
0330: bottom = pane.getHeight() - l.y - c.getHeight();
0331: right = pane.getWidth() - c.getWidth() - l.x
0332: - (pane.getWidth() - bounds.x);
0333: }
0334:
0335: contentInsets[index] = new Insets(top, left, bottom, right);
0336:
0337: Insets i = contentInsets[0];
0338: Insets i2 = InsetsUtil.rotate(direction.getNextCW(), i);
0339: Insets adjustedInsets = InsetsUtil.max(i, i2);
0340: adjustedContentInsets[index] = adjustedInsets;
0341: adjustedContentInsetsTabAreaHidden[index] = new Insets(
0342: direction == Direction.UP ? adjustedInsets.left
0343: : adjustedInsets.top,
0344: direction == Direction.LEFT ? adjustedInsets.top
0345: : adjustedInsets.left,
0346: direction == Direction.DOWN ? adjustedInsets.right
0347: : adjustedInsets.bottom,
0348: direction == Direction.RIGHT ? adjustedInsets.bottom
0349: : adjustedInsets.right);
0350:
0351: pane.removeTabAt(pane.getTabCount() - 1);
0352: pane.setSelectedIndex(DEFAULT_SELECTED_INDEX);
0353:
0354: pane.doValidation();
0355: }
0356:
0357: {
0358: // Minimum sizes
0359: Rectangle bounds = pane.getBoundsAt(DEFAULT_SELECTED_INDEX);
0360: tabMinimumSizes[index] = new Dimension(bounds.width,
0361: bounds.height);
0362: minimumSizes[index] = new Dimension(bounds.width
0363: - tabInsets[index].left - tabInsets[index].right,
0364: bounds.height - tabInsets[index].top
0365: - tabInsets[index].bottom);
0366: }
0367:
0368: calculateAreaInsets(pane, index, direction);
0369:
0370: estimateContentTabAreaBorderColor(pane, index, direction);
0371: }
0372:
0373: private void calculateAreaInsets(PanePainter pane, int index,
0374: Direction direction) {
0375: {
0376: // Area insets
0377: pane.setSelectedIndex(0);
0378: Rectangle selectedBounds = pane.getBoundsAt(0);
0379: pane.setSelectedIndex(DEFAULT_SELECTED_INDEX);
0380:
0381: Rectangle normalBounds = pane.getBoundsAt(0);
0382: int left = 0;
0383: int top = 0;
0384: int bottom = 0;
0385: int right = 0;
0386:
0387: if (direction == Direction.UP) {
0388: left = Math.min(selectedBounds.x, normalBounds.x);
0389: top = Math.min(selectedBounds.y, normalBounds.y);
0390: bottom = 0;
0391: // right = left;
0392: } else if (direction == Direction.DOWN) {
0393: left = Math.min(selectedBounds.x, normalBounds.x);
0394: top = 0;
0395: bottom = pane.getHeight()
0396: - Math.max(selectedBounds.y
0397: + selectedBounds.height, normalBounds.y
0398: + normalBounds.height);
0399: // right = left;
0400: } else if (direction == Direction.LEFT) {
0401: top = Math.min(selectedBounds.y, normalBounds.y);
0402: left = Math.min(selectedBounds.x, normalBounds.x);
0403: right = 0;
0404: // bottom = top;
0405: } else {
0406: top = Math.min(selectedBounds.y, normalBounds.y);
0407: left = 0;
0408: right = pane.getWidth()
0409: - Math.max(selectedBounds.x
0410: + selectedBounds.width, normalBounds.x
0411: + normalBounds.width);
0412: // bottom = top;
0413: }
0414:
0415: Dimension size = pane.getSize();
0416:
0417: reset(pane);
0418:
0419: for (int i = 0; i < 4; i++)
0420: pane.addTab(EMPTY_STRING, SizeIcon.EMPTY,
0421: getComponent());
0422:
0423: pane.setSelectedIndex(-1);
0424:
0425: pane.setSize(pane.getMinimumSize());
0426: pane.doValidation();
0427:
0428: if (!direction.isHorizontal()) {
0429: int width = pane.getWidth() - 1;
0430:
0431: boolean found = false;
0432:
0433: while (!found) {
0434: width++;
0435: pane.setSize(width, pane.getHeight());
0436:
0437: pane.doValidation();
0438: found = pane.getBoundsAt(0).y == pane
0439: .getBoundsAt(3).y;
0440: }
0441:
0442: Rectangle endBounds = pane.getBoundsAt(3);
0443: right = pane.getWidth() - endBounds.x - endBounds.width
0444: - spacings[index];
0445: } else {
0446: int height = pane.getHeight() - 1;
0447:
0448: boolean found = false;
0449:
0450: while (!found) {
0451: height++;
0452: pane.setSize(pane.getWidth(), height);
0453:
0454: pane.doValidation();
0455: found = pane.getBoundsAt(0).x == pane
0456: .getBoundsAt(3).x;
0457: }
0458:
0459: Rectangle endBounds = pane.getBoundsAt(3);
0460: bottom = pane.getHeight() - endBounds.y
0461: - endBounds.height - spacings[index];
0462: }
0463:
0464: areaInsets[index] = new Insets(top, left, bottom, right);
0465:
0466: pane.setSize(size);
0467:
0468: pane.doValidation();
0469: }
0470: }
0471:
0472: private void estimateContentTabAreaBorderColor(PanePainter pane,
0473: int index, final Direction direction) {
0474: Dimension preSize = pane.getSize();
0475:
0476: reset(pane);
0477:
0478: pane.addTab(EMPTY_STRING, SizeIcon.EMPTY, getComponent());
0479:
0480: pane.setSelectedIndex(-1);
0481:
0482: Dimension size = pane.getMinimumSize();
0483:
0484: if (direction.isHorizontal())
0485: pane.setSize(size.width, size.height * 2);
0486: else
0487: pane.setSize(size.width * 2, size.height);
0488:
0489: pane.doValidation();
0490:
0491: Rectangle tabBounds = pane.getBoundsAt(0);
0492:
0493: BufferedImage img = new BufferedImage(pane.getWidth(), pane
0494: .getHeight(), BufferedImage.TYPE_INT_ARGB);
0495:
0496: int x = 0;
0497: int y = 0;
0498:
0499: if (direction == Direction.UP) {
0500: x = tabBounds.x + (tabBounds.width / 2);
0501: y = pane.getHeight() - contentInsets[index].top
0502: - contentInsets[index].bottom - 1;
0503: } else if (direction == Direction.DOWN) {
0504: x = tabBounds.x + (tabBounds.width / 2);
0505: y = contentInsets[index].top + contentInsets[index].bottom;
0506: } else if (direction == Direction.LEFT) {
0507: x = pane.getWidth() - contentInsets[index].left
0508: - contentInsets[index].right - 1;
0509: y = tabBounds.y + (tabBounds.height / 2);
0510: } else {
0511: x += contentInsets[index].left + contentInsets[index].right;
0512: y = tabBounds.y + (tabBounds.height / 2);
0513: }
0514:
0515: final int px = x;
0516: final int py = y;
0517:
0518: RGBImageFilter colorFilter = new RGBImageFilter() {
0519: public int filterRGB(int x, int y, int rgb) {
0520: if (px == x && py == y) {
0521: int r = (rgb >> 16) & 0xff;
0522: int g = (rgb >> 8) & 0xff;
0523: int b = (rgb) & 0xff;
0524: int a = (rgb >> 24) & 0xff;
0525: contentTabAreaBorderColors[getDirectionIndex(direction
0526: .getOpposite())] = new Color(r, g, b, a);
0527: }
0528:
0529: return rgb;
0530: }
0531: };
0532:
0533: FilteredImageSource source = new FilteredImageSource(img
0534: .getSource(), colorFilter);
0535: pane.paint(img.getGraphics());
0536:
0537: BufferedImage img2 = new BufferedImage(pane.getWidth(), pane
0538: .getHeight(), BufferedImage.TYPE_INT_ARGB);
0539: img2.getGraphics().drawImage(
0540: Toolkit.getDefaultToolkit().createImage(source), 0, 0,
0541: null);
0542:
0543: pane.setSize(preSize);
0544:
0545: pane.doValidation();
0546: }
0547:
0548: private void estimateSwappedTabDirection(PanePainter pane,
0549: int index, final Direction direction) {
0550: reset(pane);
0551:
0552: SizeIcon icon = new SizeIcon(80, 80);
0553: SizeIcon icon2 = new SizeIcon(160, 80);
0554:
0555: pane.addTab(EMPTY_STRING, icon, getComponent());
0556: pane.doValidation();
0557:
0558: Rectangle bounds = pane.getBoundsAt(0);
0559: pane.setIconAt(0, icon2);
0560: pane.doValidation();
0561: Rectangle bounds2 = pane.getBoundsAt(0);
0562:
0563: swapWidthHeights[index] = bounds2.height > 1.5 * bounds.height;
0564: }
0565:
0566: public boolean isContentOpaque() {
0567: return contentOpaque;
0568: }
0569:
0570: public boolean isOpaque() {
0571: return opaque;
0572: }
0573:
0574: public boolean isTabAreaComponentsOpaque() {
0575: return tabAreaComponentsOpaque;
0576: }
0577:
0578: public boolean isTabAreaOpaque() {
0579: return tabAreaOpaque;
0580: }
0581:
0582: public Font getFont() {
0583: return paneHandler.getPainter(Direction.UP).getFont();
0584: }
0585:
0586: public boolean isSwapWidthHeight(Direction d) {
0587: return swapWidthHeights[getDirectionIndex(d)];
0588: }
0589:
0590: public Insets getNormalInsets(Direction d) {
0591: return normalInsets[getDirectionIndex(d)];
0592: }
0593:
0594: public Insets getSelectedInsets(Direction d) {
0595: return selectedInsets[getDirectionIndex(d)];
0596: }
0597:
0598: public Insets getNormalTabInsets(Direction areaOrientation,
0599: Direction tabDirection) {
0600: return getRealTabInsets(areaOrientation, tabDirection,
0601: getNormalInsets(areaOrientation));
0602: }
0603:
0604: public Insets getSelectedTabInsets(Direction areaOrientation,
0605: Direction tabDirection) {
0606: return getRealTabInsets(areaOrientation, tabDirection,
0607: getSelectedInsets(areaOrientation));
0608: }
0609:
0610: private Insets getRealTabInsets(Direction areaOrientation,
0611: Direction tabDirection, Insets insets) {
0612: insets = InsetsUtil.rotate(tabDirection, insets);
0613:
0614: if (swapWidthHeights[getDirectionIndex(areaOrientation)]) {
0615: insets = InsetsUtil.rotate(areaOrientation.getNextCCW(),
0616: insets);
0617: }
0618:
0619: return insets;
0620: }
0621:
0622: public Insets getContentInsets(Direction d, boolean tabAreaVisible) {
0623: return tabAreaVisible ? adjustedContentInsets[getDirectionIndex(d)]
0624: : adjustedContentInsetsTabAreaHidden[getDirectionIndex(d)];
0625: }
0626:
0627: public Insets getTabAreaInsets(Direction d) {
0628: return areaInsets[getDirectionIndex(d)];
0629: }
0630:
0631: public Dimension getTabExternalMinSize(Direction d) {
0632: return minimumSizes[getDirectionIndex(d)];
0633: }
0634:
0635: public Insets getTabInsets(Direction d) {
0636: return tabInsets[getDirectionIndex(d)];
0637: }
0638:
0639: public int getTabSpacing(Direction d) {
0640: return spacings[getDirectionIndex(d)];
0641: }
0642:
0643: public int getSelectedRaised(Direction d) {
0644: return raiseds[getDirectionIndex(d)];
0645: }
0646:
0647: public Color getContentTabAreaBorderColor(Direction d) {
0648: return contentTabAreaBorderColors[getDirectionIndex(d)];
0649: }
0650:
0651: public int getTabSpacing() {
0652: return 0;
0653: }
0654:
0655: public int getTextIconGap() {
0656: return textIconGap;
0657: }
0658:
0659: public int getScrollOffset() {
0660: return scrollOffset;
0661: }
0662:
0663: private int getWidthCompensate(Direction d) {
0664: if (swapWidthHeights[getDirectionIndex(d)])
0665: return 0;
0666:
0667: return TEXT_ICON_GAP_COMPENSATE ? getTextIconGap() : 0;
0668: }
0669:
0670: private int getHeightCompensate(Direction d) {
0671: if (!swapWidthHeights[getDirectionIndex(d)])
0672: return 0;
0673:
0674: return TEXT_ICON_GAP_COMPENSATE ? getTextIconGap() : 0;
0675: }
0676:
0677: private int getDirectionIndex(Direction d) {
0678: for (int i = 0; i < DIRECTIONS.length; i++)
0679: if (DIRECTIONS[i] == d)
0680: return i;
0681:
0682: return 0;
0683: }
0684:
0685: private Insets getCalculatedInsets(PanePainter pane, int index,
0686: boolean selected, Direction direction) {
0687: Rectangle b = pane.getBoundsAt(index);
0688: final int sizer = b.height + b.width;
0689:
0690: Icon icon = pane.getIconAt(index);
0691:
0692: pane.setIconAt(index, new SizeIcon(sizer, sizer));
0693:
0694: if (selected)
0695: pane.setSelectedIndex(index);
0696:
0697: Rectangle bounds = pane.getBoundsAt(index);
0698:
0699: pane.setIconAt(index, icon);
0700: pane.setSelectedIndex(DEFAULT_SELECTED_INDEX);
0701:
0702: int height = bounds.height - sizer
0703: - getHeightCompensate(direction);
0704: int width = bounds.width - sizer
0705: - getWidthCompensate(direction);
0706: int top = height / 2;
0707: int left = width / 2 + width % 2;
0708: int bottom = height / 2 + height % 2;
0709: int right = width / 2;
0710:
0711: return new Insets(top, left, bottom, right);
0712: }
0713:
0714: public void setHoveredTab(Tab tab) {
0715: if (enabled) {
0716: if (tab != hoveredTab) {
0717: if (hoveredTab != null
0718: && hoveredTab.getTabbedPanel() != null)
0719: findDraggableComponentBox(hoveredTab).getParent()
0720: .repaint();
0721:
0722: hoveredTab = tab;
0723:
0724: if (hoveredTab != null
0725: && hoveredTab.getTabbedPanel() != null)
0726: findDraggableComponentBox(hoveredTab).getParent()
0727: .repaint();
0728: }
0729: }
0730: }
0731:
0732: public void paintTabArea(TabbedPanel tp, Graphics g, int x, int y,
0733: int width, int height) {
0734: if (enabled) {
0735: if (tp.isTabAreaVisible()) {
0736: tabData.initialize(tp);
0737:
0738: PanePainter pane = paneHandler.getPainter(tabData
0739: .getAreaOrientation());
0740:
0741: initTabLocations(pane);
0742: Insets aInsets = getTabAreaInsets(tabData
0743: .getAreaOrientation());
0744:
0745: if (tp.getTabCount() > 0) {
0746: // Adjust x, y
0747: if (tabData.getAreaOrientation() == Direction.DOWN) {
0748: y += tabData.getTabbedPanelHeight() - height;
0749: } else if (tabData.getAreaOrientation() == Direction.RIGHT) {
0750: x += tabData.getTabbedPanelWidth() - width;
0751: }
0752:
0753: width = x < 0 ? width + x : width;
0754: height = y < 0 ? height + y : height;
0755:
0756: x = Math.max(0, x);
0757: y = Math.max(0, y);
0758:
0759: if (tabData.isHorizontalLayout())
0760: pane.setSize(
0761: tabData.getTabbedPanelSize().width,
0762: getTabbedPanelExtraSize());
0763: else
0764: pane.setSize(getTabbedPanelExtraSize(), tabData
0765: .getTabbedPanelHeight());
0766:
0767: if (PAINT_TAB_AREA
0768: && !(pane.getTabCount() == 0 && tabData
0769: .getTabCount() > 0)) {
0770: Shape originalClip = g.getClip();
0771:
0772: int tx = -x
0773: - (tabData.getAreaOrientation() == Direction.RIGHT ? -tabData
0774: .getTabbedPanelWidth()
0775: + getTabbedPanelExtraSize()
0776: : 0);
0777: int ty = -y
0778: - (tabData.getAreaOrientation() == Direction.DOWN ? -tabData
0779: .getTabbedPanelHeight()
0780: + getTabbedPanelExtraSize()
0781: : 0);
0782:
0783: Rectangle firstVisibleRect = (Rectangle) tabData
0784: .getVisibleTabRects().get(0);
0785: Rectangle lastVisibleRect = (Rectangle) tabData
0786: .getVisibleTabRects().get(
0787: tabData.getTabCount() - 1);
0788: Tab lastTab = (Tab) tabData.getTabList().get(
0789: tabData.getTabCount() - 1);
0790:
0791: if (tabData.isHorizontalLayout()) {
0792: int extraWidth = lastTab.getWidth() == lastVisibleRect.width ? 0
0793: : 2
0794: * tabData
0795: .getTabbedPanelSize().width
0796: - tabData.getTabAreaWidth();
0797: pane.setSize(pane.getWidth() + extraWidth,
0798: pane.getHeight());
0799:
0800: pane.doValidation();
0801:
0802: // Before tabs
0803: g
0804: .clipRect(
0805: 0,
0806: 0,
0807: aInsets.left
0808: + (firstVisibleRect.width > 0
0809: && firstVisibleRect.x == 0 ? 1
0810: : 0),
0811: height);
0812: pane.paint(g, tx, ty);
0813: g.setClip(originalClip);
0814:
0815: // After tabs
0816: tx -= extraWidth;
0817:
0818: int clipExtraWidth = extraWidth == 0 ? 1
0819: : 0;
0820: g.clipRect(aInsets.left
0821: + tabData.getTabAreaWidth()
0822: - clipExtraWidth, 0, width
0823: - aInsets.left
0824: - tabData.getTabAreaWidth()
0825: + clipExtraWidth, height);
0826: pane.paint(g, tx, ty);
0827: g.setClip(originalClip);
0828: } else {
0829: int extraHeight = lastTab.getHeight() == lastVisibleRect.height ? 0
0830: : 2
0831: * tabData
0832: .getTabbedPanelSize().height
0833: - tabData
0834: .getTabAreaHeight();
0835: pane.setSize(pane.getWidth(), pane
0836: .getHeight()
0837: + extraHeight);
0838:
0839: pane.doValidation();
0840:
0841: // Before tabs
0842: g
0843: .clipRect(
0844: 0,
0845: 0,
0846: width,
0847: aInsets.top
0848: + (firstVisibleRect.height > 0
0849: && firstVisibleRect.y == 0 ? 1
0850: : 0));
0851: pane.paint(g, tx, ty);
0852: g.setClip(originalClip);
0853:
0854: // After tabs
0855: ty -= extraHeight;
0856:
0857: int clipExtraHeight = extraHeight == 0 ? 1
0858: : 0;
0859: g.clipRect(0, aInsets.top
0860: + tabData.getTabAreaHeight()
0861: - clipExtraHeight, width, height
0862: - aInsets.top
0863: - tabData.getTabAreaHeight()
0864: + clipExtraHeight);
0865: pane.paint(g, tx, ty);
0866: g.setClip(originalClip);
0867: }
0868: }
0869:
0870: // First and last tab
0871: paintTabs(pane, tabData, g, x, y, width, height,
0872: true);
0873:
0874: tabData.reset();
0875:
0876: reset(pane);
0877: }
0878: }
0879: }
0880: }
0881:
0882: private void paintTabs(PanePainter pane, TabData tabData,
0883: Graphics g, int x, int y, int width, int height,
0884: boolean first) {
0885: if (enabled) {
0886: if (PAINT_TAB) {
0887: Tab lastTab = (Tab) tabData.getTabList().get(
0888: tabData.getTabList().size() - 1);
0889: Rectangle lastVisibleRect = (Rectangle) tabData
0890: .getVisibleTabRects().get(
0891: tabData.getTabCount() - 1);
0892:
0893: // Fix post/pre tabs
0894: initPaintableTabLocations(pane);
0895:
0896: Insets aInsets = getTabAreaInsets(tabData
0897: .getAreaOrientation());
0898:
0899: Point l = getLocationInTabbedPanel(lastTab, tabData
0900: .getTabbedPanel());
0901:
0902: if (tabData.isHorizontalLayout()) {
0903: int w = aInsets.left
0904: + aInsets.right
0905: + Math.max(0, tabData.getTabAreaWidth()
0906: - l.x - lastVisibleRect.width)
0907: + EXTRA_SIZE;
0908:
0909: for (int i = 0; i < tabData.getTabList().size(); i++)
0910: w += ((Tab) tabData.getTabList().get(i))
0911: .getWidth();
0912:
0913: pane.setSize(w, getTabbedPanelExtraSize());
0914: } else {
0915: int h = aInsets.top
0916: + aInsets.bottom
0917: + Math.max(0, tabData.getTabAreaHeight()
0918: - l.y - lastVisibleRect.height)
0919: + EXTRA_SIZE;
0920:
0921: for (int i = 0; i < tabData.getTabList().size(); i++)
0922: h += ((Tab) tabData.getTabList().get(i))
0923: .getHeight();
0924:
0925: pane.setSize(getTabbedPanelExtraSize(), h);
0926: }
0927:
0928: pane.doValidation();
0929:
0930: int index = tabData.getPreTab() == null ? 0 : tabData
0931: .getTabCount() > 1 ? 1 : 0;
0932:
0933: Shape originalClip = g.getClip();
0934:
0935: int tx = -x
0936: - (tabData.getAreaOrientation() == Direction.RIGHT ? -tabData
0937: .getTabbedPanelWidth()
0938: + getTabbedPanelExtraSize()
0939: : 0);
0940: int ty = -y
0941: - (tabData.getAreaOrientation() == Direction.DOWN ? -tabData
0942: .getTabbedPanelHeight()
0943: + getTabbedPanelExtraSize()
0944: : 0);
0945:
0946: Rectangle visibleRect = (Rectangle) tabData
0947: .getVisibleTabRects().get(index);
0948: Tab tab = (Tab) tabData.getTabList().get(index);
0949:
0950: if (tabData.isHorizontalLayout()) {
0951: tx -= (tabData.getPreTab() != null ? tab.getX()
0952: - tabData.getPreTab().getX()
0953: + visibleRect.x : visibleRect.x);
0954: g.clipRect(aInsets.left, 0, tabData
0955: .getTabAreaWidth(), height);
0956: } else {
0957: ty -= (tabData.getPreTab() != null ? tab.getY()
0958: - tabData.getPreTab().getY()
0959: + visibleRect.y : visibleRect.y);
0960: g.clipRect(0, aInsets.top, width, tabData
0961: .getTabAreaHeight());
0962: }
0963:
0964: applyFocusAndHover(pane, true);
0965: pane.paint(g, tx, ty);
0966: applyFocusAndHover(pane, false);
0967:
0968: g.setClip(originalClip);
0969: }
0970: }
0971: }
0972:
0973: private int getTabbedPanelExtraSize() {
0974: Insets insets = getContentInsets(tabData.getAreaOrientation(),
0975: tabData.getTabbedPanel().isTabAreaVisible());
0976:
0977: if (tabData.isHorizontalLayout())
0978: return tabData.getTabAreaHeight() + insets.top
0979: + insets.bottom + EXTRA_SIZE;
0980: else
0981: return tabData.getTabAreaWidth() + insets.left
0982: + insets.right + EXTRA_SIZE;
0983: }
0984:
0985: public void paintContentArea(TabbedPanelContentPanel p, Graphics g,
0986: int x, int y, int width, int height) {
0987: if (enabled) {
0988: if (PAINT_CONTENT_AREA) {
0989: tabData.initialize(p.getTabbedPanel());
0990: PanePainter pane = paneHandler.getPainter(tabData
0991: .getAreaOrientation());
0992:
0993: initTabLocations(pane);
0994:
0995: int tx = 0;
0996: int ty = 0;
0997:
0998: if (tabData.getTabbedPanel().hasContentArea()) {
0999: Point l = getLocationInTabbedPanel(p, tabData
1000: .getTabbedPanel());
1001:
1002: int yComp = 0;
1003: int xComp = 0;
1004:
1005: if (/* !tabData.getTabbedPanel().hasContentArea() || */(pane
1006: .getTabCount() == 0 && tabData
1007: .getTabCount() > 0)) {
1008: if (tabData.getAreaOrientation() == Direction.UP) {
1009: yComp = tabData.getTabAreaHeight();
1010: } else if (tabData.getAreaOrientation() == Direction.DOWN) {
1011: yComp = -tabData.getTabAreaHeight();
1012: } else if (tabData.getAreaOrientation() == Direction.LEFT) {
1013: xComp = tabData.getTabAreaWidth();
1014: } else {
1015: xComp = -tabData.getTabAreaWidth();
1016: }
1017: }
1018:
1019: tx = -l.x + (xComp > 0 ? xComp : 0);
1020: ty = -l.y + (yComp > 0 ? yComp : 0);
1021:
1022: int extraWidth = 0;
1023: int extraHeight = 0;
1024:
1025: if (tabAreaNotVisibleFix
1026: && !tabData.getTabbedPanel()
1027: .isTabAreaVisible()) {
1028: extraWidth = !tabData.isHorizontalLayout() ? tabMinimumSizes[getDirectionIndex(tabData
1029: .getAreaOrientation())].width
1030: - raiseds[getDirectionIndex(tabData
1031: .getAreaOrientation())]
1032: + (tabData.getAreaOrientation() == Direction.LEFT ? areaInsets[getDirectionIndex(Direction.LEFT)].left
1033: : areaInsets[getDirectionIndex(Direction.RIGHT)].right)
1034: : 0;
1035: extraHeight = tabData.isHorizontalLayout() ? tabMinimumSizes[getDirectionIndex(tabData
1036: .getAreaOrientation())].height
1037: - raiseds[getDirectionIndex(tabData
1038: .getAreaOrientation())]
1039: + (tabData.getAreaOrientation() == Direction.UP ? areaInsets[getDirectionIndex(Direction.UP)].top
1040: : areaInsets[getDirectionIndex(Direction.DOWN)].bottom)
1041: : 0;
1042: }
1043:
1044: tx -= tabData.getAreaOrientation() == Direction.LEFT ? extraWidth
1045: : 0;
1046: ty -= tabData.getAreaOrientation() == Direction.UP ? extraHeight
1047: : 0;
1048:
1049: pane.setSize(tabData.getTabbedPanelSize().width
1050: - Math.abs(xComp) + extraWidth, tabData
1051: .getTabbedPanelSize().height
1052: - Math.abs(yComp) + extraHeight);
1053:
1054: pane.doValidation();
1055: } else {
1056: if (tabData.isHorizontalLayout()) {
1057: pane.setSize(p.getWidth(), p.getHeight()
1058: + tabData.getTabAreaHeight());
1059: } else {
1060: pane.setSize(p.getWidth()
1061: + tabData.getTabAreaWidth(), p
1062: .getHeight());
1063: }
1064:
1065: pane.doValidation();
1066:
1067: if (tabData.getAreaOrientation() == Direction.UP)
1068: ty -= tabData.getTabAreaHeight();
1069: else if (tabData.getAreaOrientation() == Direction.LEFT)
1070: tx -= tabData.getTabAreaWidth();
1071: }
1072:
1073: pane.paint(g, tx, ty);
1074:
1075: tabData.reset();
1076:
1077: reset(pane);
1078: }
1079: }
1080: }
1081:
1082: private Component getComponent() {
1083: return componentCache.getComponent();
1084: }
1085:
1086: private void reset(PanePainter pane) {
1087: pane.removeAllTabs();
1088: componentCache.reset();
1089: }
1090:
1091: private Point getLocationInTabbedPanel(Component c, TabbedPanel tp) {
1092: Point l = SwingUtilities.convertPoint(c.getParent(), c
1093: .getLocation(), tp);
1094: Insets tpInsets = tp.getInsets();
1095: l.x -= tpInsets.left;
1096: l.y -= tpInsets.top;
1097:
1098: return l;
1099: }
1100:
1101: private void initPaintableTabLocations(PanePainter pane) {
1102: reset(pane);
1103:
1104: if (tabData.getPreTab() != null) {
1105: tabData.getTabList().add(0, tabData.getPreTab());
1106: tabData.getVisibleTabRects().add(0,
1107: new Rectangle(0, 0, 0, 0));
1108: }
1109:
1110: if (tabData.getPostTab() != null) {
1111: tabData.getTabList().add(tabData.getPostTab());
1112: tabData.getVisibleTabRects().add(new Rectangle(0, 0, 0, 0));
1113: }
1114:
1115: int size = 0;
1116: int selectedIndex = -1;
1117:
1118: for (int i = 0; i < tabData.getTabCount(); i++) {
1119: final Tab tab = (Tab) tabData.getTabList().get(i);
1120:
1121: SizeIcon icon = new SizeIcon(getInternalTabWidth(tab)
1122: - getWidthCompensate(tabData.getAreaOrientation()),
1123: getInternalTabHeight(tab)
1124: - getHeightCompensate(tabData
1125: .getAreaOrientation()),
1126: isSwapWidthHeight(tabData.getAreaOrientation()));
1127:
1128: pane.addTab(EMPTY_STRING, icon, getComponent());
1129:
1130: if (tab.isHighlighted())
1131: selectedIndex = pane.getTabCount() - 1;
1132:
1133: if (!tab.isEnabled()) {
1134: pane.setEnabledAt(i, false);
1135: pane.setDisabledIconAt(i, icon);
1136: }
1137:
1138: size += tabData.isHorizontalLayout() ? tab.getWidth() : tab
1139: .getHeight();
1140: }
1141:
1142: pane.setSelectedIndex(selectedIndex);
1143: pane.doValidation();
1144: }
1145:
1146: private void applyFocusAndHover(PanePainter pane, boolean active) {
1147: if (active) {
1148: for (int i = 0; i < tabData.getTabCount(); i++) {
1149: Tab tab = (Tab) tabData.getTabList().get(i);
1150:
1151: if (tab.getFocusableComponent() != null
1152: && tab.getFocusableComponent().hasFocus()) {
1153: pane.setMouseEntered(true);
1154: pane.setFocusActive(true);
1155: break;
1156: }
1157: }
1158:
1159: if (hoveredTab != null) {
1160: for (int i = 0; i < tabData.getTabCount(); i++) {
1161: Tab tab = (Tab) tabData.getTabList().get(i);
1162:
1163: if (tab == hoveredTab) {
1164: pane.setMouseEntered(true);
1165: pane.setHoveredTab(i);
1166: break;
1167: }
1168: }
1169: }
1170: } else {
1171: pane.setFocusActive(false);
1172: pane.setMouseEntered(false);
1173: }
1174: }
1175:
1176: private int getInternalTabWidth(Tab tab) {
1177: Direction areaOrientation = tab.getTabbedPanel()
1178: .getProperties().getTabAreaOrientation();
1179: Insets insets = tab.isHighlighted() ? getSelectedInsets(areaOrientation)
1180: : getNormalInsets(areaOrientation);
1181: int width = tab.getWidth();
1182:
1183: width -= insets.left + insets.right;
1184:
1185: if (areaOrientation == Direction.LEFT
1186: || areaOrientation == Direction.RIGHT)
1187: width -= getSelectedRaised(areaOrientation);
1188:
1189: return width;
1190: }
1191:
1192: private int getInternalTabHeight(Tab tab) {
1193: Direction areaOrientation = tab.getTabbedPanel()
1194: .getProperties().getTabAreaOrientation();
1195: Insets insets = tab.isHighlighted() ? getSelectedInsets(areaOrientation)
1196: : getNormalInsets(areaOrientation);
1197: int height = tab.getHeight();
1198:
1199: height -= insets.top + insets.bottom;
1200:
1201: if (areaOrientation == Direction.UP
1202: || areaOrientation == Direction.DOWN)
1203: height -= getSelectedRaised(areaOrientation);
1204:
1205: return height;
1206: }
1207:
1208: private void initTabLocations(PanePainter pane) {
1209: findPaintableTabs();
1210:
1211: Dimension minSize = getTabExternalMinSize(tabData
1212: .getAreaOrientation());
1213: Insets aInsets = getTabAreaInsets(tabData.getAreaOrientation());
1214:
1215: int selectedIndex = -1;
1216:
1217: if (tabData.getTabbedPanel().isTabAreaVisible()) {
1218: for (int i = 0; i < tabData.getTabCount(); i++) {
1219: final Tab tab = (Tab) tabData.getTabList().get(i);
1220: final Rectangle visibleRect = (Rectangle) tabData
1221: .getVisibleTabRects().get(i);
1222: Insets insets = getTabInsets(tabData
1223: .getAreaOrientation());
1224: int iconWidth = Math.max(-insets.left - insets.right,
1225: getInternalTabWidth(tab)
1226: - (tab.getWidth() - visibleRect.width));
1227: int iconHeight = Math
1228: .max(
1229: -insets.top - insets.bottom,
1230: getInternalTabHeight(tab)
1231: - (tab.getHeight() - visibleRect.height));
1232:
1233: Point l = getLocationInTabbedPanel(tab, tabData
1234: .getTabbedPanel());
1235:
1236: if ((tabData.isHorizontalLayout() && (visibleRect.width >= minSize.width || minSize.width < tabData
1237: .getTabbedPanelWidth()
1238: - l.x - aInsets.right))
1239: || (!tabData.isHorizontalLayout() && (visibleRect.height >= minSize.height || minSize.height < tabData
1240: .getTabbedPanelHeight()
1241: - l.y - aInsets.bottom))) {
1242: final int iWidth = iconWidth;
1243: final int iHeight = iconHeight;
1244:
1245: SizeIcon icon = new SizeIcon(iWidth
1246: - getWidthCompensate(tabData
1247: .getAreaOrientation()), iHeight
1248: - getHeightCompensate(tabData
1249: .getAreaOrientation()),
1250: isSwapWidthHeight(tabData
1251: .getAreaOrientation()));
1252: pane.addTab(EMPTY_STRING, icon, getComponent());
1253:
1254: if (i == tabData.getSelectedTabPainterIndex()) {
1255: selectedIndex = i;
1256: }
1257:
1258: if (!tab.isEnabled()) {
1259: pane.setEnabledAt(i, false);
1260: pane.setDisabledIconAt(i, icon);
1261: }
1262: }
1263: }
1264: } else if (tabAreaNotVisibleFix) {
1265: pane.addTab(EMPTY_STRING, componentCache.getComponent());
1266: }
1267:
1268: if (pane.getTabCount() > 0)
1269: pane.setSelectedIndex(selectedIndex);
1270: pane.doValidation();
1271: }
1272:
1273: private void findPaintableTabs() {
1274: Tab firstTab = null;
1275: Rectangle firstVisibleRect = null;
1276: Tab previousTab = null;
1277:
1278: int i = 0;
1279: boolean tabsFound = false;
1280:
1281: if (tabData.getTabbedPanel().isTabAreaVisible()) {
1282: while (i < tabData.getTabbedPanel().getTabCount()) {
1283: Tab tab = tabData.getTabbedPanel().getTabAt(i);
1284: Rectangle r = tab.getVisibleRect();
1285:
1286: if (i == 0) {
1287: firstTab = tab;
1288: firstVisibleRect = r;
1289: }
1290:
1291: i++;
1292:
1293: if (r.width > 0 && r.height > 0) {
1294: tabsFound = true;
1295: tabData.getTabList().add(tab);
1296: tabData.getVisibleTabRects().add(r);
1297:
1298: if (tabData.getTabCount() == 1)
1299: tabData.setPreTab(previousTab);
1300:
1301: if (tab.isHighlighted()) {
1302: tabData.setSelectedTabPainterIndex(tabData
1303: .getTabCount() - 1);
1304: }
1305: } else if (tabData.getTabList().size() > 0
1306: && (r.width == 0 || r.height == 0))
1307: tabData.setPostTab(tab);
1308:
1309: if (tabsFound
1310: && r.x == 0
1311: && r.y == 0
1312: && ((tabData.isHorizontalLayout() && r.width < tab
1313: .getWidth()) || (!tabData
1314: .isHorizontalLayout() && r.height < tab
1315: .getHeight()))) {
1316: break;
1317: }
1318:
1319: previousTab = tab;
1320: }
1321:
1322: if (firstTab != null) {
1323: // TODO: Ugly!
1324: Component box = findDraggableComponentBox(firstTab);
1325:
1326: if (box != null) {
1327: if (tabData.isHorizontalLayout()) {
1328: tabData.setTabAreaWidth(box.getWidth());
1329: tabData.setTabAreaHeight(box.getParent()
1330: .getHeight());
1331: } else {
1332: tabData.setTabAreaWidth(box.getParent()
1333: .getWidth());
1334: tabData.setTabAreaHeight(box.getHeight());
1335: }
1336: }
1337:
1338: if (tabData.getTabCount() == 0) {
1339: tabData.getTabList().add(firstTab);
1340: tabData.getVisibleTabRects().add(firstVisibleRect);
1341: }
1342: }
1343: }
1344: }
1345:
1346: private Component findDraggableComponentBox(Component c) {
1347: if (c == null || c instanceof DraggableComponentBox)
1348: return c;
1349:
1350: return findDraggableComponentBox(c.getParent());
1351: }
1352: }
|