Source Code Cross Referenced for FlatTabbedPaneUI.java in  » Database-Client » executequery » org » underworldlabs » swing » plaf » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database Client » executequery » org.underworldlabs.swing.plaf 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * FlatTabbedPaneUI.java
0003:         *
0004:         * Copyright (C) 2002, 2003, 2004, 2005, 2006 Takis Diakoumis
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 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, MA  02111-1307, USA.
0019:         *
0020:         */
0021:
0022:        package org.underworldlabs.swing.plaf;
0023:
0024:        import java.awt.Color;
0025:        import java.awt.Component;
0026:        import java.awt.Container;
0027:        import java.awt.Dimension;
0028:        import java.awt.Event;
0029:        import java.awt.Font;
0030:        import java.awt.FontMetrics;
0031:        import java.awt.Graphics;
0032:        import java.awt.Graphics2D;
0033:        import java.awt.Insets;
0034:        import java.awt.LayoutManager;
0035:        import java.awt.Point;
0036:        import java.awt.Polygon;
0037:        import java.awt.Rectangle;
0038:        import java.awt.Shape; //import java.awt.Toolkit;
0039:
0040:        import java.awt.event.ActionEvent;
0041:        import java.awt.event.ActionListener;
0042:        import java.awt.event.ContainerEvent;
0043:        import java.awt.event.ContainerListener;
0044:        import java.awt.event.FocusAdapter;
0045:        import java.awt.event.FocusEvent;
0046:        import java.awt.event.FocusListener;
0047:        import java.awt.event.MouseAdapter;
0048:        import java.awt.event.MouseEvent;
0049:        import java.awt.event.MouseListener;
0050:
0051:        import java.beans.PropertyChangeEvent;
0052:        import java.beans.PropertyChangeListener;
0053:
0054:        import java.util.Hashtable;
0055:        import java.util.Vector;
0056:
0057:        import javax.swing.AbstractAction;
0058:        import javax.swing.ActionMap;
0059:        import javax.swing.Icon;
0060:        import javax.swing.InputMap;
0061:        import javax.swing.JComponent;
0062:        import javax.swing.JPanel;
0063:        import javax.swing.JTabbedPane;
0064:        import javax.swing.JViewport;
0065:        import javax.swing.KeyStroke;
0066:        import javax.swing.LookAndFeel;
0067:        import javax.swing.SwingConstants;
0068:        import javax.swing.SwingUtilities;
0069:        import javax.swing.UIManager;
0070:
0071:        import javax.swing.event.ChangeEvent;
0072:        import javax.swing.event.ChangeListener;
0073:
0074:        import javax.swing.plaf.ActionMapUIResource;
0075:        import javax.swing.plaf.ComponentUI;
0076:        import javax.swing.plaf.InputMapUIResource;
0077:        import javax.swing.plaf.TabbedPaneUI;
0078:        import javax.swing.plaf.UIResource;
0079:
0080:        import javax.swing.plaf.basic.BasicArrowButton;
0081:        import javax.swing.plaf.basic.BasicGraphicsUtils;
0082:        import javax.swing.plaf.basic.BasicHTML;
0083:
0084:        import javax.swing.text.View;
0085:
0086:        /*
0087:         * @(#)FlatTabbedPaneUI.java	1.126 03/01/23
0088:         *
0089:         * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
0090:         * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
0091:         */
0092:
0093:        /* ----------------------------------------------------------
0094:         * CVS NOTE: Changes to the CVS repository prior to the 
0095:         *           release of version 3.0.0beta1 has meant a 
0096:         *           resetting of CVS revision numbers.
0097:         * ----------------------------------------------------------
0098:         */
0099:
0100:        /** This is a slight modification to the original BasicTabbedPaneUI.
0101:         *  It removes the heavy border and makes the selected tab bg white.
0102:         *  This is the beginning of a larger modification - at the moment it
0103:         *  really is purpose built for the nav panel and its white content panels
0104:         *  and gray lines.
0105:         */
0106:        /**
0107:         *
0108:         * @author   Takis Diakoumis
0109:         * @version  $Revision: 1.4 $
0110:         * @date     $Date: 2006/05/14 06:56:07 $
0111:         */
0112:        public class FlatTabbedPaneUI extends TabbedPaneUI implements 
0113:                SwingConstants {
0114:
0115:            // Instance variables initialized at installation
0116:
0117:            protected JTabbedPane tabPane;
0118:
0119:            protected Color highlight;
0120:            protected Color lightHighlight;
0121:            protected Color shadow;
0122:            protected Color darkShadow;
0123:            protected Color focus;
0124:            private Color selectedColor;
0125:            private Color controlShadow;
0126:
0127:            protected int textIconGap;
0128:
0129:            protected int tabRunOverlay;
0130:
0131:            protected Insets tabInsets;
0132:            protected Insets selectedTabPadInsets;
0133:            protected Insets tabAreaInsets;
0134:            protected Insets contentBorderInsets;
0135:
0136:            // Transient variables (recalculated each time TabbedPane is layed out)
0137:
0138:            protected int tabRuns[] = new int[10];
0139:            protected int runCount = 0;
0140:            protected int selectedRun = -1;
0141:            protected Rectangle rects[] = new Rectangle[0];
0142:            protected int maxTabHeight;
0143:            protected int maxTabWidth;
0144:
0145:            // Listeners
0146:
0147:            protected ChangeListener tabChangeListener;
0148:            protected PropertyChangeListener propertyChangeListener;
0149:            protected MouseListener mouseListener;
0150:            protected FocusListener focusListener;
0151:            // PENDING(api): See comment for ContainerHandler
0152:            private ContainerListener containerListener;
0153:
0154:            // Private instance data
0155:
0156:            private Insets currentPadInsets = new Insets(0, 0, 0, 0);
0157:            private Insets currentTabAreaInsets = new Insets(0, 0, 0, 0);
0158:
0159:            private Component visibleComponent;
0160:            // PENDING(api): See comment for ContainerHandler
0161:            private Vector htmlViews;
0162:
0163:            private Hashtable mnemonicToIndexMap;
0164:
0165:            /**
0166:             * InputMap used for mnemonics. Only non-null if the JTabbedPane has
0167:             * mnemonics associated with it. Lazily created in initMnemonics.
0168:             */
0169:            private InputMap mnemonicInputMap;
0170:
0171:            // For use when tabLayoutPolicy = SCROLL_TAB_LAYOUT
0172:            private ScrollableTabSupport tabScroller;
0173:
0174:            /**
0175:             * A rectangle used for general layout calculations in order
0176:             * to avoid constructing many new Rectangles on the fly.
0177:             */
0178:            protected transient Rectangle calcRect = new Rectangle(0, 0, 0, 0);
0179:
0180:            /**
0181:             * Number of tabs. When the count differs, the mnemonics are updated.
0182:             */
0183:            // PENDING: This wouldn't be necessary if JTabbedPane had a better
0184:            // way of notifying listeners when the count changed.
0185:            private int tabCount;
0186:
0187:            // UI creation
0188:
0189:            public static ComponentUI createUI(JComponent c) {
0190:                return new FlatTabbedPaneUI();
0191:            }
0192:
0193:            // UI Installation/De-installation
0194:
0195:            public void installUI(JComponent c) {
0196:                this .tabPane = (JTabbedPane) c;
0197:
0198:                c.setLayout(createLayoutManager());
0199:                installComponents();
0200:                installDefaults();
0201:                installListeners();
0202:                installKeyboardActions();
0203:            }
0204:
0205:            public void uninstallUI(JComponent c) {
0206:                uninstallKeyboardActions();
0207:                uninstallListeners();
0208:                uninstallDefaults();
0209:                uninstallComponents();
0210:                c.setLayout(null);
0211:
0212:                this .tabPane = null;
0213:            }
0214:
0215:            /**
0216:             * Invoked by <code>installUI</code> to create
0217:             * a layout manager object to manage
0218:             * the <code>JTabbedPane</code>.
0219:             *
0220:             * @return a layout manager object
0221:             *
0222:             * @see TabbedPaneLayout
0223:             * @see javax.swing.JTabbedPane#getTabLayoutPolicy
0224:             */
0225:            protected LayoutManager createLayoutManager() {
0226:                if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) {
0227:                    return new TabbedPaneScrollLayout();
0228:                } else { /* WRAP_TAB_LAYOUT */
0229:                    return new TabbedPaneLayout();
0230:                }
0231:            }
0232:
0233:            /* In an attempt to preserve backward compatibility for programs
0234:             * which have extended FlatTabbedPaneUI to do their own layout, the
0235:             * UI uses the installed layoutManager (and not tabLayoutPolicy) to
0236:             * determine if scrollTabLayout is enabled.
0237:             */
0238:            private boolean scrollableTabLayoutEnabled() {
0239:                return (tabPane.getLayout() instanceof  TabbedPaneScrollLayout);
0240:            }
0241:
0242:            /**
0243:             * Creates and installs any required subcomponents for the JTabbedPane.
0244:             * Invoked by installUI.
0245:             *
0246:             * @since 1.4
0247:             */
0248:            protected void installComponents() {
0249:                if (scrollableTabLayoutEnabled()) {
0250:                    if (tabScroller == null) {
0251:                        tabScroller = new ScrollableTabSupport(tabPane
0252:                                .getTabPlacement());
0253:                        tabPane.add(tabScroller.viewport);
0254:                        tabPane.add(tabScroller.scrollForwardButton);
0255:                        tabPane.add(tabScroller.scrollBackwardButton);
0256:                    }
0257:                }
0258:            }
0259:
0260:            /**
0261:             * Removes any installed subcomponents from the JTabbedPane.
0262:             * Invoked by uninstallUI.
0263:             *
0264:             * @since 1.4
0265:             */
0266:            protected void uninstallComponents() {
0267:                if (scrollableTabLayoutEnabled()) {
0268:                    tabPane.remove(tabScroller.viewport);
0269:                    tabPane.remove(tabScroller.scrollForwardButton);
0270:                    tabPane.remove(tabScroller.scrollBackwardButton);
0271:                    tabScroller = null;
0272:                }
0273:            }
0274:
0275:            protected void installDefaults() {
0276:                LookAndFeel.installColorsAndFont(tabPane,
0277:                        "TabbedPane.background", "TabbedPane.foreground",
0278:                        "TabbedPane.font");
0279:                highlight = UIManager.getColor("TabbedPane.light");
0280:                lightHighlight = UIManager.getColor("TabbedPane.highlight");
0281:                shadow = UIManager.getColor("TabbedPane.shadow");
0282:                darkShadow = UIManager.getColor("TabbedPane.darkShadow");
0283:                focus = UIManager.getColor("TabbedPane.focus");
0284:                selectedColor = UIManager.getColor("TabbedPane.selected");
0285:
0286:                if (selectedColor == null) {
0287:                    selectedColor = UIManager
0288:                            .getColor("TabbedPane.unselectedTabBackground");
0289:
0290:                    if (selectedColor == null) { // if still null (some l&f)
0291:                        selectedColor = UIManager.getColor("control");
0292:                    }
0293:
0294:                }
0295:
0296:                controlShadow = UIManager.getColor("controlShadow");
0297:
0298:                contentBorderInsets = new Insets(1, 1, 1, 1);
0299:                tabInsets = new Insets(0, 1, 0, 6);
0300:                tabAreaInsets = new Insets(4, 0, 0, 6);
0301:                textIconGap = 1;
0302:
0303:                //        textIconGap = UIManager.getInt("TabbedPane.textIconGap");
0304:                //        tabInsets = UIManager.getInsets("TabbedPane.tabInsets");
0305:
0306:                selectedTabPadInsets = UIManager
0307:                        .getInsets("TabbedPane.selectedTabPadInsets");
0308:                //      tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
0309:
0310:                //        contentBorderInsets = UIManager.getInsets("TabbedPane.contentBorderInsets");
0311:                tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay");
0312:
0313:            }
0314:
0315:            protected void uninstallDefaults() {
0316:                highlight = null;
0317:                lightHighlight = null;
0318:                shadow = null;
0319:                darkShadow = null;
0320:                focus = null;
0321:                tabInsets = null;
0322:                selectedTabPadInsets = null;
0323:                tabAreaInsets = null;
0324:                contentBorderInsets = null;
0325:            }
0326:
0327:            protected void installListeners() {
0328:                if ((propertyChangeListener = createPropertyChangeListener()) != null) {
0329:                    tabPane.addPropertyChangeListener(propertyChangeListener);
0330:                }
0331:                if ((tabChangeListener = createChangeListener()) != null) {
0332:                    tabPane.addChangeListener(tabChangeListener);
0333:                }
0334:                if ((mouseListener = createMouseListener()) != null) {
0335:                    if (scrollableTabLayoutEnabled()) {
0336:                        tabScroller.tabPanel.addMouseListener(mouseListener);
0337:
0338:                    } else { // WRAP_TAB_LAYOUT
0339:                        tabPane.addMouseListener(mouseListener);
0340:                    }
0341:                }
0342:                if ((focusListener = createFocusListener()) != null) {
0343:                    tabPane.addFocusListener(focusListener);
0344:                }
0345:                // PENDING(api) : See comment for ContainerHandler
0346:                if ((containerListener = new ContainerHandler()) != null) {
0347:                    tabPane.addContainerListener(containerListener);
0348:                    if (tabPane.getTabCount() > 0) {
0349:                        htmlViews = createHTMLVector();
0350:                    }
0351:                }
0352:            }
0353:
0354:            protected void uninstallListeners() {
0355:                if (mouseListener != null) {
0356:                    if (scrollableTabLayoutEnabled()) { // SCROLL_TAB_LAYOUT
0357:                        tabScroller.tabPanel.removeMouseListener(mouseListener);
0358:
0359:                    } else { // WRAP_TAB_LAYOUT
0360:                        tabPane.removeMouseListener(mouseListener);
0361:                    }
0362:                    mouseListener = null;
0363:                }
0364:                if (focusListener != null) {
0365:                    tabPane.removeFocusListener(focusListener);
0366:                    focusListener = null;
0367:                }
0368:
0369:                // PENDING(api): See comment for ContainerHandler
0370:                if (containerListener != null) {
0371:                    tabPane.removeContainerListener(containerListener);
0372:                    containerListener = null;
0373:                    if (htmlViews != null) {
0374:                        htmlViews.removeAllElements();
0375:                        htmlViews = null;
0376:                    }
0377:                }
0378:                if (tabChangeListener != null) {
0379:                    tabPane.removeChangeListener(tabChangeListener);
0380:                    tabChangeListener = null;
0381:                }
0382:                if (propertyChangeListener != null) {
0383:                    tabPane
0384:                            .removePropertyChangeListener(propertyChangeListener);
0385:                    propertyChangeListener = null;
0386:                }
0387:            }
0388:
0389:            protected MouseListener createMouseListener() {
0390:                return new MouseHandler();
0391:            }
0392:
0393:            protected FocusListener createFocusListener() {
0394:                return new FocusHandler();
0395:            }
0396:
0397:            protected ChangeListener createChangeListener() {
0398:                return new TabSelectionHandler();
0399:            }
0400:
0401:            protected PropertyChangeListener createPropertyChangeListener() {
0402:                return new PropertyChangeHandler();
0403:            }
0404:
0405:            protected void installKeyboardActions() {
0406:                InputMap km = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0407:
0408:                SwingUtilities.replaceUIInputMap(tabPane,
0409:                        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, km);
0410:                km = getInputMap(JComponent.WHEN_FOCUSED);
0411:                SwingUtilities.replaceUIInputMap(tabPane,
0412:                        JComponent.WHEN_FOCUSED, km);
0413:                ActionMap am = getActionMap();
0414:
0415:                SwingUtilities.replaceUIActionMap(tabPane, am);
0416:                /*
0417:                if (scrollableTabLayoutEnabled()) {
0418:                    tabScroller.scrollForwardButton.setAction(am.get("scrollTabsForwardAction"));
0419:                    tabScroller.scrollBackwardButton.setAction(am.get("scrollTabsBackwardAction"));
0420:                }
0421:                 */
0422:            }
0423:
0424:            InputMap getInputMap(int condition) {
0425:                if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
0426:                    return (InputMap) UIManager
0427:                            .get("TabbedPane.ancestorInputMap");
0428:                } else if (condition == JComponent.WHEN_FOCUSED) {
0429:                    return (InputMap) UIManager.get("TabbedPane.focusInputMap");
0430:                }
0431:                return null;
0432:            }
0433:
0434:            ActionMap getActionMap() {
0435:                ActionMap map = (ActionMap) UIManager
0436:                        .get("TabbedPane.actionMap");
0437:
0438:                if (map == null) {
0439:                    map = createActionMap();
0440:                    if (map != null) {
0441:                        UIManager.getLookAndFeelDefaults().put(
0442:                                "TabbedPane.actionMap", map);
0443:                    }
0444:                }
0445:                return map;
0446:            }
0447:
0448:            ActionMap createActionMap() {
0449:                ActionMap map = new ActionMapUIResource();
0450:                map.put("navigateNext", new NextAction());
0451:                map.put("navigatePrevious", new PreviousAction());
0452:                map.put("navigateRight", new RightAction());
0453:                map.put("navigateLeft", new LeftAction());
0454:                map.put("navigateUp", new UpAction());
0455:                map.put("navigateDown", new DownAction());
0456:                map.put("navigatePageUp", new PageUpAction());
0457:                map.put("navigatePageDown", new PageDownAction());
0458:                map.put("requestFocus", new RequestFocusAction());
0459:                map.put("requestFocusForVisibleComponent",
0460:                        new RequestFocusForVisibleAction());
0461:                map.put("setSelectedIndex", new SetSelectedIndexAction());
0462:                //        map.put("scrollTabsForwardAction", new FlatScrollTabsForwardAction());
0463:                //        map.put("scrollTabsBackwardAction",new FlatScrollTabsBackwardAction());
0464:                return map;
0465:            }
0466:
0467:            protected void uninstallKeyboardActions() {
0468:                SwingUtilities.replaceUIActionMap(tabPane, null);
0469:                SwingUtilities.replaceUIInputMap(tabPane,
0470:                        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
0471:                SwingUtilities.replaceUIInputMap(tabPane,
0472:                        JComponent.WHEN_FOCUSED, null);
0473:            }
0474:
0475:            /**
0476:             * Reloads the mnemonics. This should be invoked when a memonic changes,
0477:             * when the title of a mnemonic changes, or when tabs are added/removed.
0478:             */
0479:            private void updateMnemonics() {
0480:                resetMnemonics();
0481:                for (int counter = tabPane.getTabCount() - 1; counter >= 0; counter--) {
0482:                    int mnemonic = tabPane.getMnemonicAt(counter);
0483:
0484:                    if (mnemonic > 0) {
0485:                        addMnemonic(counter, mnemonic);
0486:                    }
0487:                }
0488:            }
0489:
0490:            /**
0491:             * Resets the mnemonics bindings to an empty state.
0492:             */
0493:            private void resetMnemonics() {
0494:                if (mnemonicToIndexMap != null) {
0495:                    mnemonicToIndexMap.clear();
0496:                    mnemonicInputMap.clear();
0497:                }
0498:            }
0499:
0500:            /**
0501:             * Adds the specified mnemonic at the specified index.
0502:             */
0503:            private void addMnemonic(int index, int mnemonic) {
0504:                if (mnemonicToIndexMap == null) {
0505:                    initMnemonics();
0506:                }
0507:                mnemonicInputMap.put(KeyStroke.getKeyStroke(mnemonic,
0508:                        Event.ALT_MASK), "setSelectedIndex");
0509:                mnemonicToIndexMap.put(new Integer(mnemonic),
0510:                        new Integer(index));
0511:            }
0512:
0513:            /**
0514:             * Installs the state needed for mnemonics.
0515:             */
0516:            private void initMnemonics() {
0517:                mnemonicToIndexMap = new Hashtable();
0518:                mnemonicInputMap = new InputMapUIResource();
0519:                mnemonicInputMap
0520:                        .setParent(SwingUtilities.getUIInputMap(tabPane,
0521:                                JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
0522:                SwingUtilities.replaceUIInputMap(tabPane,
0523:                        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
0524:                        mnemonicInputMap);
0525:            }
0526:
0527:            // Geometry
0528:
0529:            public Dimension getPreferredSize(JComponent c) {
0530:                // Default to LayoutManager's preferredLayoutSize
0531:                return null;
0532:            }
0533:
0534:            public Dimension getMinimumSize(JComponent c) {
0535:                // Default to LayoutManager's minimumLayoutSize
0536:                return null;
0537:            }
0538:
0539:            public Dimension getMaximumSize(JComponent c) {
0540:                // Default to LayoutManager's maximumLayoutSize
0541:                return null;
0542:            }
0543:
0544:            // UI Rendering
0545:
0546:            public void paint(Graphics g, JComponent c) {
0547:                int tc = tabPane.getTabCount();
0548:
0549:                if (tabCount != tc) {
0550:                    tabCount = tc;
0551:                    updateMnemonics();
0552:                }
0553:
0554:                int selectedIndex = tabPane.getSelectedIndex();
0555:                int tabPlacement = tabPane.getTabPlacement();
0556:
0557:                ensureCurrentLayout();
0558:
0559:                // Paint tab area
0560:                // If scrollable tabs are enabled, the tab area will be
0561:                // painted by the scrollable tab panel instead.
0562:                //
0563:                if (!scrollableTabLayoutEnabled()) { // WRAP_TAB_LAYOUT
0564:                    paintTabArea(g, tabPlacement, selectedIndex);
0565:                }
0566:
0567:                // Paint content border
0568:                paintContentBorder(g, tabPlacement, selectedIndex);
0569:
0570:            }
0571:
0572:            /**
0573:             * Paints the tabs in the tab area.
0574:             * Invoked by paint().
0575:             * The graphics parameter must be a valid <code>Graphics</code>
0576:             * object.  Tab placement may be either:
0577:             * <code>JTabbedPane.TOP</code>, <code>JTabbedPane.BOTTOM</code>,
0578:             * <code>JTabbedPane.LEFT</code>, or <code>JTabbedPane.RIGHT</code>.
0579:             * The selected index must be a valid tabbed pane tab index (0 to
0580:             * tab count - 1, inclusive) or -1 if no tab is currently selected.
0581:             * The handling of invalid parameters is unspecified.
0582:             *
0583:             * @param g the graphics object to use for rendering
0584:             * @param tabPlacement the placement for the tabs within the JTabbedPane
0585:             * @param selectedIndex the tab index of the selected component
0586:             *
0587:             * @since 1.4
0588:             */
0589:            protected void paintTabArea(Graphics g, int tabPlacement,
0590:                    int selectedIndex) {
0591:                int tabCount = tabPane.getTabCount();
0592:
0593:                Rectangle iconRect = new Rectangle(), textRect = new Rectangle();
0594:                Rectangle clipRect = g.getClipBounds();
0595:
0596:                // Paint tabRuns of tabs from back to front
0597:                for (int i = runCount - 1; i >= 0; i--) {
0598:                    int start = tabRuns[i];
0599:                    int next = tabRuns[(i == runCount - 1) ? 0 : i + 1];
0600:                    int end = (next != 0 ? next - 1 : tabCount - 1);
0601:
0602:                    for (int j = start; j <= end; j++) {
0603:
0604:                        // stupid hack - remove all causes index exception
0605:                        try {
0606:                            if (rects[j].intersects(clipRect)) {
0607:                                paintTab(g, tabPlacement, rects, j, iconRect,
0608:                                        textRect);
0609:                            }
0610:                        } catch (ArrayIndexOutOfBoundsException e) {
0611:                            break;
0612:                        }
0613:
0614:                    }
0615:
0616:                }
0617:
0618:                // Paint selected tab if its in the front run
0619:                // since it may overlap other tabs
0620:                if (selectedIndex >= 0
0621:                        && getRunForTab(tabCount, selectedIndex) == 0) {
0622:                    if (rects[selectedIndex].intersects(clipRect)) {
0623:                        paintTab(g, tabPlacement, rects, selectedIndex,
0624:                                iconRect, textRect);
0625:                    }
0626:                }
0627:            }
0628:
0629:            protected void paintTab(Graphics g, int tabPlacement,
0630:                    Rectangle[] rects, int tabIndex, Rectangle iconRect,
0631:                    Rectangle textRect) {
0632:
0633:                Rectangle tabRect = rects[tabIndex];
0634:                int selectedIndex = tabPane.getSelectedIndex();
0635:                boolean isSelected = selectedIndex == tabIndex;
0636:                Graphics2D g2 = null;
0637:                Polygon cropShape = null;
0638:                Shape save = null;
0639:                int cropx = 0;
0640:                int cropy = 0;
0641:
0642:                if (scrollableTabLayoutEnabled()) {
0643:                    if (g instanceof  Graphics2D) {
0644:                        g2 = (Graphics2D) g;
0645:
0646:                        // Render visual for cropped tab edge...
0647:                        Rectangle viewRect = tabScroller.viewport.getViewRect();
0648:                        int cropline;
0649:
0650:                        switch (tabPlacement) {
0651:                        case LEFT:
0652:                        case RIGHT:
0653:                            cropline = viewRect.y + viewRect.height;
0654:                            if ((tabRect.y < cropline)
0655:                                    && (tabRect.y + tabRect.height > cropline)) {
0656:                                cropShape = createCroppedTabClip(tabPlacement,
0657:                                        tabRect, cropline);
0658:                                cropx = tabRect.x;
0659:                                cropy = cropline - 1;
0660:                            }
0661:                            break;
0662:                        case TOP:
0663:                        case BOTTOM:
0664:                        default:
0665:                            cropline = viewRect.x + viewRect.width;
0666:
0667:                            if ((tabRect.x < cropline)
0668:                                    && (tabRect.x + tabRect.width > cropline)) {
0669:                                cropShape = createCroppedTabClip(tabPlacement,
0670:                                        tabRect, cropline);
0671:                                cropx = cropline - 1;
0672:                                cropy = tabRect.y;
0673:                            }
0674:
0675:                        }
0676:
0677:                        if (cropShape != null) {
0678:                            save = g2.getClip();
0679:                            g2.clip(cropShape);
0680:                        }
0681:
0682:                    }
0683:
0684:                }
0685:
0686:                paintTabBackground(g, tabPlacement, tabIndex, tabRect.x,
0687:                        tabRect.y, tabRect.width, tabRect.height + 1,
0688:                        isSelected);
0689:
0690:                paintTabBorder(g, tabPlacement, tabIndex, tabRect.x, tabRect.y,
0691:                        tabRect.width, tabRect.height + 1, isSelected);
0692:
0693:                String title = tabPane.getTitleAt(tabIndex);
0694:                Font font = tabPane.getFont();
0695:                FontMetrics metrics = g.getFontMetrics(font);
0696:                Icon icon = getIconForTab(tabIndex);
0697:
0698:                layoutLabel(tabPlacement, metrics, tabIndex, title, icon,
0699:                        tabRect, iconRect, textRect, isSelected);
0700:
0701:                paintText(g, tabPlacement, font, metrics, tabIndex, title,
0702:                        textRect, isSelected);
0703:
0704:                paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
0705:
0706:                //        paintFocusIndicator(g, tabPlacement, rects, tabIndex,
0707:                //                  iconRect, textRect, isSelected);
0708:
0709:                if (cropShape != null) {
0710:                    paintCroppedTabEdge(g, tabPlacement, tabIndex, isSelected,
0711:                            cropx, cropy);
0712:                    g2.setClip(save);
0713:                }
0714:
0715:            }
0716:
0717:            /* This method will create and return a polygon shape for the given tab rectangle
0718:             * which has been cropped at the specified cropline with a torn edge visual.
0719:             * e.g. A "File" tab which has cropped been cropped just after the "i":
0720:             *             -------------
0721:             *             |  .....     |
0722:             *             |  .          |
0723:             *             |  ...  .    |
0724:             *             |  .    .   |
0725:             *             |  .    .    |
0726:             *             |  .    .     |
0727:             *             --------------
0728:             *
0729:             * The x, y arrays below define the pattern used to create a "torn" edge
0730:             * segment which is repeated to fill the edge of the tab.
0731:             * For tabs placed on TOP and BOTTOM, this righthand torn edge is created by
0732:             * line segments which are defined by coordinates obtained by
0733:             * subtracting xCropLen[i] from (tab.x + tab.width) and adding yCroplen[i]
0734:             * to (tab.y).
0735:             * For tabs placed on LEFT or RIGHT, the bottom torn edge is created by
0736:             * subtracting xCropLen[i] from (tab.y + tab.height) and adding yCropLen[i]
0737:             * to (tab.x).
0738:             */
0739:            private int xCropLen[] = { 1, 1, 0, 0, 1, 1, 2, 2 };
0740:            private int yCropLen[] = { 0, 3, 3, 6, 6, 9, 9, 12 };
0741:            private static final int CROP_SEGMENT = 12;
0742:
0743:            private Polygon createCroppedTabClip(int tabPlacement,
0744:                    Rectangle tabRect, int cropline) {
0745:                int rlen = 0;
0746:                int start = 0;
0747:                int end = 0;
0748:                int ostart = 0;
0749:
0750:                switch (tabPlacement) {
0751:                case LEFT:
0752:                case RIGHT:
0753:                    rlen = tabRect.width;
0754:                    start = tabRect.x;
0755:                    end = tabRect.x + tabRect.width;
0756:                    ostart = tabRect.y;
0757:                    break;
0758:                case TOP:
0759:                case BOTTOM:
0760:                default:
0761:                    rlen = tabRect.height;
0762:                    start = tabRect.y;
0763:                    end = tabRect.y + tabRect.height + 1;
0764:                    ostart = tabRect.x;
0765:                }
0766:
0767:                int rcnt = rlen / CROP_SEGMENT;
0768:
0769:                if (rlen % CROP_SEGMENT > 0) {
0770:                    rcnt++;
0771:                }
0772:
0773:                int npts = 2 + (rcnt * 8);
0774:                int xp[] = new int[npts];
0775:                int yp[] = new int[npts];
0776:                int pcnt = 0;
0777:
0778:                xp[pcnt] = ostart;
0779:                yp[pcnt++] = end;
0780:                xp[pcnt] = ostart;
0781:                yp[pcnt++] = start;
0782:                for (int i = 0; i < rcnt; i++) {
0783:                    for (int j = 0; j < xCropLen.length; j++) {
0784:                        xp[pcnt] = cropline - xCropLen[j];
0785:                        yp[pcnt] = start + (i * CROP_SEGMENT) + yCropLen[j];
0786:                        if (yp[pcnt] >= end) {
0787:                            yp[pcnt] = end;
0788:                            pcnt++;
0789:                            break;
0790:                        }
0791:                        pcnt++;
0792:                    }
0793:                }
0794:                if (tabPlacement == JTabbedPane.TOP
0795:                        || tabPlacement == JTabbedPane.BOTTOM) {
0796:                    return new Polygon(xp, yp, pcnt);
0797:
0798:                } else { // LEFT or RIGHT
0799:                    return new Polygon(yp, xp, pcnt);
0800:                }
0801:            }
0802:
0803:            /* If tabLayoutPolicy == SCROLL_TAB_LAYOUT, this method will paint an edge
0804:             * indicating the tab is cropped in the viewport display
0805:             */
0806:            private void paintCroppedTabEdge(Graphics g, int tabPlacement,
0807:                    int tabIndex, boolean isSelected, int x, int y) {
0808:
0809:                switch (tabPlacement) {
0810:
0811:                case LEFT:
0812:                case RIGHT:
0813:                    int xx = x;
0814:                    g.setColor(shadow);
0815:
0816:                    while (xx <= x + rects[tabIndex].width) {
0817:
0818:                        for (int i = 0; i < xCropLen.length; i += 2) {
0819:                            g.drawLine(xx + yCropLen[i], y - xCropLen[i], xx
0820:                                    + yCropLen[i + 1] - 1, y - xCropLen[i + 1]);
0821:                        }
0822:
0823:                        xx += CROP_SEGMENT;
0824:
0825:                    }
0826:
0827:                    break;
0828:
0829:                case TOP:
0830:                case BOTTOM:
0831:                default:
0832:                    int yy = y;
0833:                    g.setColor(controlShadow);
0834:
0835:                    while (yy <= y + rects[tabIndex].height) {
0836:
0837:                        for (int i = 0; i < xCropLen.length; i += 2) {
0838:                            g
0839:                                    .drawLine(x - xCropLen[i],
0840:                                            yy + yCropLen[i], x
0841:                                                    - xCropLen[i + 1], yy
0842:                                                    + yCropLen[i + 1] - 1);
0843:                        }
0844:
0845:                        yy += CROP_SEGMENT;
0846:
0847:                    }
0848:
0849:                }
0850:
0851:            }
0852:
0853:            protected void layoutLabel(int tabPlacement, FontMetrics metrics,
0854:                    int tabIndex, String title, Icon icon, Rectangle tabRect,
0855:                    Rectangle iconRect, Rectangle textRect, boolean isSelected) {
0856:
0857:                textRect.x = textRect.y = iconRect.x = iconRect.y = 0;
0858:
0859:                View v = getTextViewForTab(tabIndex);
0860:
0861:                if (v != null) {
0862:                    tabPane.putClientProperty("html", v);
0863:                }
0864:
0865:                SwingUtilities.layoutCompoundLabel((JComponent) tabPane,
0866:                        metrics, title, icon, SwingUtilities.CENTER,
0867:                        SwingUtilities.CENTER, SwingUtilities.CENTER,
0868:                        SwingUtilities.TRAILING, tabRect, iconRect, textRect,
0869:                        textIconGap);
0870:
0871:                tabPane.putClientProperty("html", null);
0872:
0873:                int xNudge = getTabLabelShiftX(tabPlacement, tabIndex,
0874:                        isSelected);
0875:                int yNudge = getTabLabelShiftY(tabPlacement, tabIndex,
0876:                        isSelected);
0877:                iconRect.x += xNudge;
0878:                iconRect.y += yNudge;
0879:                textRect.x += xNudge;
0880:                textRect.y += yNudge;
0881:
0882:            }
0883:
0884:            protected void paintIcon(Graphics g, int tabPlacement,
0885:                    int tabIndex, Icon icon, Rectangle iconRect,
0886:                    boolean isSelected) {
0887:                if (icon != null) {
0888:
0889:                    int y = iconRect.y - 1;
0890:
0891:                    if (!isSelected)
0892:                        y += 2;
0893:
0894:                    icon.paintIcon(tabPane, g, iconRect.x, y);
0895:
0896:                }
0897:
0898:            }
0899:
0900:            protected void paintText(Graphics g, int tabPlacement, Font font,
0901:                    FontMetrics metrics, int tabIndex, String title,
0902:                    Rectangle textRect, boolean isSelected) {
0903:
0904:                g.setFont(font);
0905:
0906:                View v = getTextViewForTab(tabIndex);
0907:
0908:                if (v != null) {
0909:                    v.paint(g, textRect); // html
0910:                }
0911:
0912:                else { // plain text
0913:                    int mnemIndex = tabPane
0914:                            .getDisplayedMnemonicIndexAt(tabIndex);
0915:
0916:                    if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex)) {
0917:                        g.setColor(tabPane.getForegroundAt(tabIndex));
0918:                        int y = textRect.y + metrics.getAscent() - 1;
0919:
0920:                        if (!isSelected)
0921:                            y += 2;
0922:
0923:                        BasicGraphicsUtils.drawStringUnderlineCharAt(g, title,
0924:                                mnemIndex, textRect.x, y);
0925:
0926:                    }
0927:
0928:                    else { // tab disabled
0929:                        g
0930:                                .setColor(tabPane.getBackgroundAt(tabIndex)
0931:                                        .brighter());
0932:                        BasicGraphicsUtils.drawStringUnderlineCharAt(g, title,
0933:                                mnemIndex, textRect.x, textRect.y
0934:                                        + metrics.getAscent() - 1);
0935:                        g.setColor(tabPane.getBackgroundAt(tabIndex).darker());
0936:                        BasicGraphicsUtils.drawStringUnderlineCharAt(g, title,
0937:                                mnemIndex, textRect.x - 1, textRect.y
0938:                                        + metrics.getAscent() - 1);
0939:                    }
0940:
0941:                }
0942:
0943:            }
0944:
0945:            protected int getTabLabelShiftX(int tabPlacement, int tabIndex,
0946:                    boolean isSelected) {
0947:                Rectangle tabRect = rects[tabIndex];
0948:                int nudge = 0;
0949:                switch (tabPlacement) {
0950:                case LEFT:
0951:                    nudge = isSelected ? -1 : 1;
0952:                    break;
0953:                case RIGHT:
0954:                    nudge = isSelected ? 1 : -1;
0955:                    break;
0956:                case BOTTOM:
0957:                case TOP:
0958:                default:
0959:                    nudge = tabRect.width % 2;
0960:                }
0961:                return nudge;
0962:            }
0963:
0964:            protected int getTabLabelShiftY(int tabPlacement, int tabIndex,
0965:                    boolean isSelected) {
0966:                Rectangle tabRect = rects[tabIndex];
0967:                int nudge = 0;
0968:                switch (tabPlacement) {
0969:                case BOTTOM:
0970:                    nudge = isSelected ? 1 : -1;
0971:                    break;
0972:                case LEFT:
0973:                case RIGHT:
0974:                    nudge = tabRect.height % 2;
0975:                    break;
0976:                case TOP:
0977:                default:
0978:                    nudge = isSelected ? -1 : 1;
0979:                    ;
0980:                }
0981:                return nudge;
0982:            }
0983:
0984:            protected void paintFocusIndicator(Graphics g, int tabPlacement,
0985:                    Rectangle[] rects, int tabIndex, Rectangle iconRect,
0986:                    Rectangle textRect, boolean isSelected) {
0987:
0988:                Rectangle tabRect = rects[tabIndex];
0989:                if (tabPane.hasFocus() && isSelected) {
0990:                    int x, y, w, h;
0991:                    g.setColor(focus);
0992:                    switch (tabPlacement) {
0993:                    case LEFT:
0994:                        x = tabRect.x + 3;
0995:                        y = tabRect.y + 3;
0996:                        w = tabRect.width - 5;
0997:                        h = tabRect.height - 6;
0998:                        break;
0999:                    case RIGHT:
1000:                        x = tabRect.x + 2;
1001:                        y = tabRect.y + 3;
1002:                        w = tabRect.width - 5;
1003:                        h = tabRect.height - 6;
1004:                        break;
1005:                    case BOTTOM:
1006:                        x = tabRect.x + 3;
1007:                        y = tabRect.y + 2;
1008:                        w = tabRect.width - 6;
1009:                        h = tabRect.height - 5;
1010:                        break;
1011:                    case TOP:
1012:                    default:
1013:                        x = tabRect.x + 3;
1014:                        y = tabRect.y + 3;
1015:                        w = tabRect.width - 6;
1016:                        h = tabRect.height - 5;
1017:                    }
1018:                    BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
1019:                }
1020:            }
1021:
1022:            /**
1023:             * this function draws the border around each tab
1024:             * note that this function does now draw the background of the tab.
1025:             * that is done elsewhere
1026:             */
1027:            protected void paintTabBorder(Graphics g, int tabPlacement,
1028:                    int tabIndex, int x, int y, int w, int h, boolean isSelected) {
1029:                g.setColor(lightHighlight);
1030:
1031:                switch (tabPlacement) {
1032:                case LEFT:
1033:                    g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); // bottom-left highlight
1034:                    g.drawLine(x, y + 2, x, y + h - 3); // left highlight
1035:                    g.drawLine(x + 1, y + 1, x + 1, y + 1); // top-left highlight
1036:                    g.drawLine(x + 2, y, x + w - 1, y); // top highlight
1037:
1038:                    g.setColor(shadow);
1039:                    g.drawLine(x + 2, y + h - 2, x + w - 1, y + h - 2); // bottom shadow
1040:
1041:                    g.setColor(darkShadow);
1042:                    g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1); // bottom dark shadow
1043:                    break;
1044:                case RIGHT:
1045:                    g.drawLine(x, y, x + w - 3, y); // top highlight
1046:
1047:                    g.setColor(shadow);
1048:                    g.drawLine(x, y + h - 2, x + w - 3, y + h - 2); // bottom shadow
1049:                    g.drawLine(x + w - 2, y + 2, x + w - 2, y + h - 3); // right shadow
1050:
1051:                    g.setColor(darkShadow);
1052:                    g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); // top-right dark shadow
1053:                    g.drawLine(x + w - 2, y + h - 2, x + w - 2, y + h - 2); // bottom-right dark shadow
1054:                    g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 3); // right dark shadow
1055:                    g.drawLine(x, y + h - 1, x + w - 3, y + h - 1); // bottom dark shadow
1056:                    break;
1057:                case BOTTOM:
1058:                    g.setColor(controlShadow);
1059:                    g.drawLine(x, y, x, y + h - 3); // left highlight
1060:                    g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); // bottom-left highlight
1061:
1062:                    //              g.setColor(shadow);
1063:                    //              g.drawLine(x+2, y+h-2, x+w-3, y+h-2); // bottom shadow
1064:                    //              g.drawLine(x+w-2, y, x+w-2, y+h-3); // right shadow
1065:
1066:                    //              g.setColor(darkShadow);
1067:
1068:                    //                if (isSelected)
1069:                    g.drawLine(x + 2, y + h - 1, x + w - 3, y + h - 1); // bottom dark shadow
1070:                    //                else
1071:                    //                  g.drawLine(x+2, y+h, x+w-3, y+h); // bottom dark shadow
1072:
1073:                    g.drawLine(x + w - 2, y + h - 2, x + w - 2, y + h - 2); // bottom-right dark shadow
1074:                    g.drawLine(x + w - 1, y, x + w - 1, y + h - 3); // right dark shadow
1075:
1076:                    if (isSelected) {
1077:                        Shape _clip = g.getClip();
1078:                        Rectangle r = _clip.getBounds();
1079:                        g.setClip(r.x, r.y - 3, r.x + r.width, r.y - 3);
1080:                        g.setColor(Color.RED);
1081:                        g.drawLine(x + 1, y - 2, x + w - 2, y - 2);
1082:                        g.setClip(_clip);
1083:                    }
1084:
1085:                    break;
1086:                case TOP:
1087:                default:
1088:                    g.drawLine(x, y + 2, x, y + h - 1); // left highlight
1089:                    g.drawLine(x + 1, y + 1, x + 1, y + 1); // top-left highlight
1090:                    g.drawLine(x + 2, y, x + w - 3, y); // top highlight
1091:
1092:                    g.setColor(shadow);
1093:                    g.drawLine(x + w - 2, y + 2, x + w - 2, y + h - 1); // right shadow
1094:
1095:                    g.setColor(darkShadow);
1096:                    g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 1); // right dark-shadow
1097:                    g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); // top-right shadow
1098:                }
1099:
1100:            }
1101:
1102:            protected void paintTabBackground(Graphics g, int tabPlacement,
1103:                    int tabIndex, int x, int y, int w, int h, boolean isSelected) {
1104:
1105:                if (isSelected)
1106:                    g.setColor(Color.WHITE);
1107:                else
1108:                    g.setColor(selectedColor);
1109:
1110:                switch (tabPlacement) {
1111:
1112:                case LEFT:
1113:                    g.fillRect(x + 1, y + 1, w - 2, h - 3);
1114:                    break;
1115:                case RIGHT:
1116:                    g.fillRect(x, y + 1, w - 2, h - 3);
1117:                    break;
1118:                case BOTTOM:
1119:                    g.fillRect(x + 1, y, w - 3, h - 1);
1120:                    break;
1121:                case TOP:
1122:                default:
1123:                    g.fillRect(x + 1, y + 1, w - 3, h - 1);
1124:
1125:                }
1126:
1127:            }
1128:
1129:            protected void paintContentBorder(Graphics g, int tabPlacement,
1130:                    int selectedIndex) {
1131:                int width = tabPane.getWidth();
1132:                int height = tabPane.getHeight();
1133:                Insets insets = tabPane.getInsets();
1134:
1135:                int x = insets.left;
1136:                int y = insets.top;
1137:                int w = width - insets.right - insets.left;
1138:                int h = height - insets.top - insets.bottom;
1139:
1140:                switch (tabPlacement) {
1141:                case LEFT:
1142:                    x += calculateTabAreaWidth(tabPlacement, runCount,
1143:                            maxTabWidth);
1144:                    w -= (x - insets.left);
1145:                    break;
1146:                case RIGHT:
1147:                    w -= calculateTabAreaWidth(tabPlacement, runCount,
1148:                            maxTabWidth);
1149:                    break;
1150:                case BOTTOM:
1151:                    h -= calculateTabAreaHeight(tabPlacement, runCount,
1152:                            maxTabHeight);
1153:                    break;
1154:                case TOP:
1155:                default:
1156:                    y += calculateTabAreaHeight(tabPlacement, runCount,
1157:                            maxTabHeight);
1158:                    h -= (y - insets.top);
1159:                }
1160:                // Fill region behind content area
1161:                if (selectedColor == null) {
1162:                    g.setColor(tabPane.getBackground());
1163:                } else {
1164:                    g.setColor(selectedColor);
1165:                }
1166:                g.fillRect(x, y, w, h);
1167:
1168:                paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y,
1169:                        w, h);
1170:                paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x,
1171:                        y, w, h);
1172:                paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x,
1173:                        y, w, h);
1174:                paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x,
1175:                        y, w, h);
1176:
1177:            }
1178:
1179:            protected void paintContentBorderTopEdge(Graphics g,
1180:                    int tabPlacement, int selectedIndex, int x, int y, int w,
1181:                    int h) {
1182:                g.setColor(controlShadow);
1183:                g.drawLine(x, y, x + w - 2, y);
1184:            }
1185:
1186:            protected void paintContentBorderBottomEdge(Graphics g,
1187:                    int tabPlacement, int selectedIndex, int x, int y, int w,
1188:                    int h) {
1189:
1190:                g.setColor(controlShadow);
1191:                g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
1192:
1193:                g.setColor(Color.WHITE);
1194:                Rectangle r = getTabBounds(tabPane, selectedIndex);
1195:                g.drawLine(r.x + 1, y + h - 1, r.x + r.width - 2, y + h - 1);
1196:
1197:            }
1198:
1199:            protected void paintContentBorderLeftEdge(Graphics g,
1200:                    int tabPlacement, int selectedIndex, int x, int y, int w,
1201:                    int h) {
1202:
1203:                g.setColor(controlShadow);
1204:                g.drawLine(x, y, x, y + h - 2);
1205:            }
1206:
1207:            protected void paintContentBorderRightEdge(Graphics g,
1208:                    int tabPlacement, int selectedIndex, int x, int y, int w,
1209:                    int h) {
1210:
1211:                g.setColor(controlShadow);
1212:                g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
1213:
1214:            }
1215:
1216:            private boolean isLeftToRight(Component c) {
1217:                return c.getComponentOrientation().isLeftToRight();
1218:            }
1219:
1220:            private void ensureCurrentLayout() {
1221:                if (!tabPane.isValid()) {
1222:                    tabPane.validate();
1223:                }
1224:                /* If tabPane doesn't have a peer yet, the validate() call will
1225:                 * silently fail.  We handle that by forcing a layout if tabPane
1226:                 * is still invalid.  See bug 4237677.
1227:                 */
1228:                if (!tabPane.isValid()) {
1229:                    TabbedPaneLayout layout = (TabbedPaneLayout) tabPane
1230:                            .getLayout();
1231:                    layout.calculateLayoutInfo();
1232:                }
1233:            }
1234:
1235:            // TabbedPaneUI methods
1236:
1237:            /**
1238:             * Returns the bounds of the specified tab index.  The bounds are
1239:             * with respect to the JTabbedPane's coordinate space.
1240:             */
1241:            public Rectangle getTabBounds(JTabbedPane pane, int i) {
1242:                ensureCurrentLayout();
1243:                Rectangle tabRect = new Rectangle();
1244:                return getTabBounds(i, tabRect);
1245:            }
1246:
1247:            public int getTabRunCount(JTabbedPane pane) {
1248:                ensureCurrentLayout();
1249:                return runCount;
1250:            }
1251:
1252:            /**
1253:             * Returns the tab index which intersects the specified point
1254:             * in the JTabbedPane's coordinate space.
1255:             */
1256:            public int tabForCoordinate(JTabbedPane pane, int x, int y) {
1257:                ensureCurrentLayout();
1258:                Point p = new Point(x, y);
1259:
1260:                if (scrollableTabLayoutEnabled()) {
1261:                    translatePointToTabPanel(x, y, p);
1262:                }
1263:                int tabCount = tabPane.getTabCount();
1264:                for (int i = 0; i < tabCount; i++) {
1265:                    if (rects[i].contains(p.x, p.y)) {
1266:                        return i;
1267:                    }
1268:                }
1269:                return -1;
1270:            }
1271:
1272:            /**
1273:             * Returns the bounds of the specified tab in the coordinate space
1274:             * of the JTabbedPane component.  This is required because the tab rects
1275:             * are by default defined in the coordinate space of the component where
1276:             * they are rendered, which could be the JTabbedPane
1277:             * (for WRAP_TAB_LAYOUT) or a ScrollableTabPanel (SCROLL_TAB_LAYOUT).
1278:             * This method should be used whenever the tab rectangle must be relative
1279:             * to the JTabbedPane itself and the result should be placed in a
1280:             * designated Rectangle object (rather than instantiating and returning
1281:             * a new Rectangle each time). The tab index parameter must be a valid
1282:             * tabbed pane tab index (0 to tab count - 1, inclusive).  The destination
1283:             * rectangle parameter must be a valid <code>Rectangle</code> instance.
1284:             * The handling of invalid parameters is unspecified.
1285:             *
1286:             * @param tabIndex the index of the tab
1287:             * @param dest the rectangle where the result should be placed
1288:             * @return the resulting rectangle
1289:             *
1290:             * @since 1.4
1291:             */
1292:            protected Rectangle getTabBounds(int tabIndex, Rectangle dest) {
1293:                dest.width = rects[tabIndex].width;
1294:                dest.height = rects[tabIndex].height;
1295:
1296:                if (scrollableTabLayoutEnabled()) { // SCROLL_TAB_LAYOUT
1297:                    // Need to translate coordinates based on viewport location &
1298:                    // view position
1299:                    Point vpp = tabScroller.viewport.getLocation();
1300:                    Point viewp = tabScroller.viewport.getViewPosition();
1301:                    dest.x = rects[tabIndex].x + vpp.x - viewp.x;
1302:                    dest.y = rects[tabIndex].y + vpp.y - viewp.y;
1303:
1304:                } else { // WRAP_TAB_LAYOUT
1305:                    dest.x = rects[tabIndex].x;
1306:                    dest.y = rects[tabIndex].y;
1307:                }
1308:                return dest;
1309:            }
1310:
1311:            /**
1312:             * Returns the tab index which intersects the specified point
1313:             * in the coordinate space of the component where the
1314:             * tabs are actually rendered, which could be the JTabbedPane
1315:             * (for WRAP_TAB_LAYOUT) or a ScrollableTabPanel (SCROLL_TAB_LAYOUT).
1316:             */
1317:            private int getTabAtLocation(int x, int y) {
1318:                ensureCurrentLayout();
1319:
1320:                int tabCount = tabPane.getTabCount();
1321:                for (int i = 0; i < tabCount; i++) {
1322:                    if (rects[i].contains(x, y)) {
1323:                        return i;
1324:                    }
1325:                }
1326:                return -1;
1327:            }
1328:
1329:            /**
1330:             * Returns the index of the tab closest to the passed in location, note
1331:             * that the returned tab may not contain the location x,y.
1332:             */
1333:            private int getClosestTab(int x, int y) {
1334:                int min = 0;
1335:                int tabCount = Math.min(rects.length, tabPane.getTabCount());
1336:                int max = tabCount;
1337:                int tabPlacement = tabPane.getTabPlacement();
1338:                boolean useX = (tabPlacement == TOP || tabPlacement == BOTTOM);
1339:                int want = (useX) ? x : y;
1340:
1341:                while (min != max) {
1342:                    int current = (max + min) / 2;
1343:                    int minLoc;
1344:                    int maxLoc;
1345:
1346:                    if (useX) {
1347:                        minLoc = rects[current].x;
1348:                        maxLoc = minLoc + rects[current].width;
1349:                    } else {
1350:                        minLoc = rects[current].y;
1351:                        maxLoc = minLoc + rects[current].height;
1352:                    }
1353:                    if (want < minLoc) {
1354:                        max = current;
1355:                        if (min == max) {
1356:                            return Math.max(0, current - 1);
1357:                        }
1358:                    } else if (want >= maxLoc) {
1359:                        min = current;
1360:                        if (max - min <= 1) {
1361:                            return Math.max(current + 1, tabCount - 1);
1362:                        }
1363:                    } else {
1364:                        return current;
1365:                    }
1366:                }
1367:                return min;
1368:            }
1369:
1370:            /**
1371:             * Returns a point which is translated from the specified point in the
1372:             * JTabbedPane's coordinate space to the coordinate space of the
1373:             * ScrollableTabPanel.  This is used for SCROLL_TAB_LAYOUT ONLY.
1374:             */
1375:            private Point translatePointToTabPanel(int srcx, int srcy,
1376:                    Point dest) {
1377:                Point vpp = tabScroller.viewport.getLocation();
1378:                Point viewp = tabScroller.viewport.getViewPosition();
1379:                dest.x = srcx + vpp.x + viewp.x;
1380:                dest.y = srcy + vpp.y + viewp.y;
1381:                return dest;
1382:            }
1383:
1384:            // FlatTabbedPaneUI methods
1385:
1386:            protected Component getVisibleComponent() {
1387:                return visibleComponent;
1388:            }
1389:
1390:            protected void setVisibleComponent(Component component) {
1391:                if (visibleComponent != null && visibleComponent != component
1392:                        && visibleComponent.getParent() == tabPane) {
1393:                    visibleComponent.setVisible(false);
1394:                }
1395:                if (component != null && !component.isVisible()) {
1396:                    component.setVisible(true);
1397:                }
1398:                visibleComponent = component;
1399:            }
1400:
1401:            protected void assureRectsCreated(int tabCount) {
1402:                int rectArrayLen = rects.length;
1403:                if (tabCount != rectArrayLen) {
1404:                    Rectangle[] tempRectArray = new Rectangle[tabCount];
1405:                    System.arraycopy(rects, 0, tempRectArray, 0, Math.min(
1406:                            rectArrayLen, tabCount));
1407:                    rects = tempRectArray;
1408:                    for (int rectIndex = rectArrayLen; rectIndex < tabCount; rectIndex++) {
1409:                        rects[rectIndex] = new Rectangle();
1410:                    }
1411:                }
1412:
1413:            }
1414:
1415:            protected void expandTabRunsArray() {
1416:                int rectLen = tabRuns.length;
1417:                int[] newArray = new int[rectLen + 10];
1418:                System.arraycopy(tabRuns, 0, newArray, 0, runCount);
1419:                tabRuns = newArray;
1420:            }
1421:
1422:            protected int getRunForTab(int tabCount, int tabIndex) {
1423:                for (int i = 0; i < runCount; i++) {
1424:                    int first = tabRuns[i];
1425:                    int last = lastTabInRun(tabCount, i);
1426:                    if (tabIndex >= first && tabIndex <= last) {
1427:                        return i;
1428:                    }
1429:                }
1430:                return 0;
1431:            }
1432:
1433:            protected int lastTabInRun(int tabCount, int run) {
1434:                if (runCount == 1) {
1435:                    return tabCount - 1;
1436:                }
1437:                int nextRun = (run == runCount - 1 ? 0 : run + 1);
1438:                if (tabRuns[nextRun] == 0) {
1439:                    return tabCount - 1;
1440:                }
1441:                return tabRuns[nextRun] - 1;
1442:            }
1443:
1444:            protected int getTabRunOverlay(int tabPlacement) {
1445:                return tabRunOverlay;
1446:            }
1447:
1448:            protected int getTabRunIndent(int tabPlacement, int run) {
1449:                return 0;
1450:            }
1451:
1452:            protected boolean shouldPadTabRun(int tabPlacement, int run) {
1453:                return runCount > 1;
1454:            }
1455:
1456:            protected boolean shouldRotateTabRuns(int tabPlacement) {
1457:                return true;
1458:            }
1459:
1460:            protected Icon getIconForTab(int tabIndex) {
1461:                return (!tabPane.isEnabled() || !tabPane.isEnabledAt(tabIndex)) ? tabPane
1462:                        .getDisabledIconAt(tabIndex)
1463:                        : tabPane.getIconAt(tabIndex);
1464:            }
1465:
1466:            /**
1467:             * Returns the text View object required to render stylized text (HTML) for
1468:             * the specified tab or null if no specialized text rendering is needed
1469:             * for this tab. This is provided to support html rendering inside tabs.
1470:             *
1471:             * @param tabIndex the index of the tab
1472:             * @return the text view to render the tab's text or null if no
1473:             *         specialized rendering is required
1474:             *
1475:             * @since 1.4
1476:             */
1477:            protected View getTextViewForTab(int tabIndex) {
1478:                if (htmlViews != null) {
1479:                    return (View) htmlViews.elementAt(tabIndex);
1480:                }
1481:                return null;
1482:            }
1483:
1484:            protected int calculateTabHeight(int tabPlacement, int tabIndex,
1485:                    int fontHeight) {
1486:                int height = 0;
1487:                View v = getTextViewForTab(tabIndex);
1488:                if (v != null) {
1489:                    // html
1490:                    height += (int) v.getPreferredSpan(View.Y_AXIS);
1491:                } else {
1492:                    // plain text
1493:                    height += fontHeight;
1494:                }
1495:                Icon icon = getIconForTab(tabIndex);
1496:                Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
1497:
1498:                if (icon != null) {
1499:                    height = Math.max(height, icon.getIconHeight());
1500:                }
1501:                height += tabInsets.top + tabInsets.bottom + 2;
1502:
1503:                return height;
1504:            }
1505:
1506:            protected int calculateMaxTabHeight(int tabPlacement) {
1507:                FontMetrics metrics = getFontMetrics();
1508:                int tabCount = tabPane.getTabCount();
1509:                int result = 0;
1510:                int fontHeight = metrics.getHeight();
1511:                for (int i = 0; i < tabCount; i++) {
1512:                    result = Math.max(calculateTabHeight(tabPlacement, i,
1513:                            fontHeight), result);
1514:                }
1515:                return result;
1516:            }
1517:
1518:            protected int calculateTabWidth(int tabPlacement, int tabIndex,
1519:                    FontMetrics metrics) {
1520:                Icon icon = getIconForTab(tabIndex);
1521:                Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
1522:                int width = tabInsets.left + tabInsets.right + 3;
1523:
1524:                if (icon != null) {
1525:                    width += icon.getIconWidth() + textIconGap;
1526:                }
1527:                View v = getTextViewForTab(tabIndex);
1528:                if (v != null) {
1529:                    // html
1530:                    width += (int) v.getPreferredSpan(View.X_AXIS);
1531:                } else {
1532:                    // plain text
1533:                    String title = tabPane.getTitleAt(tabIndex);
1534:                    width += SwingUtilities.computeStringWidth(metrics, title);
1535:                }
1536:
1537:                return width;
1538:            }
1539:
1540:            protected int calculateMaxTabWidth(int tabPlacement) {
1541:                FontMetrics metrics = getFontMetrics();
1542:                int tabCount = tabPane.getTabCount();
1543:                int result = 0;
1544:                for (int i = 0; i < tabCount; i++) {
1545:                    result = Math.max(calculateTabWidth(tabPlacement, i,
1546:                            metrics), result);
1547:                }
1548:                return result;
1549:            }
1550:
1551:            protected int calculateTabAreaHeight(int tabPlacement,
1552:                    int horizRunCount, int maxTabHeight) {
1553:                Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
1554:                int tabRunOverlay = getTabRunOverlay(tabPlacement);
1555:                return (horizRunCount > 0 ? horizRunCount
1556:                        * (maxTabHeight - tabRunOverlay) + tabRunOverlay
1557:                        + tabAreaInsets.top + tabAreaInsets.bottom : 0);
1558:            }
1559:
1560:            protected int calculateTabAreaWidth(int tabPlacement,
1561:                    int vertRunCount, int maxTabWidth) {
1562:                Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
1563:                int tabRunOverlay = getTabRunOverlay(tabPlacement);
1564:                return (vertRunCount > 0 ? vertRunCount
1565:                        * (maxTabWidth - tabRunOverlay) + tabRunOverlay
1566:                        + tabAreaInsets.left + tabAreaInsets.right : 0);
1567:            }
1568:
1569:            protected Insets getTabInsets(int tabPlacement, int tabIndex) {
1570:                return tabInsets;
1571:            }
1572:
1573:            protected Insets getSelectedTabPadInsets(int tabPlacement) {
1574:                rotateInsets(selectedTabPadInsets, currentPadInsets,
1575:                        tabPlacement);
1576:                return currentPadInsets;
1577:            }
1578:
1579:            protected Insets getTabAreaInsets(int tabPlacement) {
1580:                rotateInsets(tabAreaInsets, currentTabAreaInsets, tabPlacement);
1581:                return currentTabAreaInsets;
1582:            }
1583:
1584:            protected Insets getContentBorderInsets(int tabPlacement) {
1585:                return contentBorderInsets;
1586:            }
1587:
1588:            protected FontMetrics getFontMetrics() {
1589:                Font font = tabPane.getFont();
1590:                return tabPane.getFontMetrics(font);// Toolkit.getDefaultToolkit().getFontMetrics(font);
1591:            }
1592:
1593:            // Tab Navigation methods
1594:
1595:            protected void navigateSelectedTab(int direction) {
1596:                int tabPlacement = tabPane.getTabPlacement();
1597:                int current = tabPane.getSelectedIndex();
1598:                int tabCount = tabPane.getTabCount();
1599:                boolean leftToRight = isLeftToRight(tabPane);
1600:
1601:                // If we have no tabs then don't navigate.
1602:                if (tabCount <= 0) {
1603:                    return;
1604:                }
1605:
1606:                int offset;
1607:                switch (tabPlacement) {
1608:                case NEXT:
1609:                    selectNextTab(current);
1610:                    break;
1611:                case PREVIOUS:
1612:                    selectPreviousTab(current);
1613:                    break;
1614:                case LEFT:
1615:                case RIGHT:
1616:                    switch (direction) {
1617:                    case NORTH:
1618:                        selectPreviousTabInRun(current);
1619:                        break;
1620:                    case SOUTH:
1621:                        selectNextTabInRun(current);
1622:                        break;
1623:                    case WEST:
1624:                        offset = getTabRunOffset(tabPlacement, tabCount,
1625:                                current, false);
1626:                        selectAdjacentRunTab(tabPlacement, current, offset);
1627:                        break;
1628:                    case EAST:
1629:                        offset = getTabRunOffset(tabPlacement, tabCount,
1630:                                current, true);
1631:                        selectAdjacentRunTab(tabPlacement, current, offset);
1632:                        break;
1633:                    default:
1634:                    }
1635:                    break;
1636:                case BOTTOM:
1637:                case TOP:
1638:                default:
1639:                    switch (direction) {
1640:                    case NORTH:
1641:                        offset = getTabRunOffset(tabPlacement, tabCount,
1642:                                current, false);
1643:                        selectAdjacentRunTab(tabPlacement, current, offset);
1644:                        break;
1645:                    case SOUTH:
1646:                        offset = getTabRunOffset(tabPlacement, tabCount,
1647:                                current, true);
1648:                        selectAdjacentRunTab(tabPlacement, current, offset);
1649:                        break;
1650:                    case EAST:
1651:                        if (leftToRight) {
1652:                            selectNextTabInRun(current);
1653:                        } else {
1654:                            selectPreviousTabInRun(current);
1655:                        }
1656:                        break;
1657:                    case WEST:
1658:                        if (leftToRight) {
1659:                            selectPreviousTabInRun(current);
1660:                        } else {
1661:                            selectNextTabInRun(current);
1662:                        }
1663:                        break;
1664:                    default:
1665:                    }
1666:                }
1667:            }
1668:
1669:            protected void selectNextTabInRun(int current) {
1670:                int tabCount = tabPane.getTabCount();
1671:                int tabIndex = getNextTabIndexInRun(tabCount, current);
1672:
1673:                while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
1674:                    tabIndex = getNextTabIndexInRun(tabCount, tabIndex);
1675:                }
1676:                tabPane.setSelectedIndex(tabIndex);
1677:            }
1678:
1679:            protected void selectPreviousTabInRun(int current) {
1680:                int tabCount = tabPane.getTabCount();
1681:                int tabIndex = getPreviousTabIndexInRun(tabCount, current);
1682:
1683:                while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
1684:                    tabIndex = getPreviousTabIndexInRun(tabCount, tabIndex);
1685:                }
1686:                tabPane.setSelectedIndex(tabIndex);
1687:            }
1688:
1689:            protected void selectNextTab(int current) {
1690:                int tabIndex = getNextTabIndex(current);
1691:
1692:                while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
1693:                    tabIndex = getNextTabIndex(tabIndex);
1694:                }
1695:                tabPane.setSelectedIndex(tabIndex);
1696:            }
1697:
1698:            protected void selectPreviousTab(int current) {
1699:                int tabIndex = getPreviousTabIndex(current);
1700:
1701:                while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
1702:                    tabIndex = getPreviousTabIndex(tabIndex);
1703:                }
1704:                tabPane.setSelectedIndex(tabIndex);
1705:            }
1706:
1707:            protected void selectAdjacentRunTab(int tabPlacement, int tabIndex,
1708:                    int offset) {
1709:                if (runCount < 2) {
1710:                    return;
1711:                }
1712:                int newIndex;
1713:                Rectangle r = rects[tabIndex];
1714:                switch (tabPlacement) {
1715:                case LEFT:
1716:                case RIGHT:
1717:                    newIndex = getTabAtLocation(r.x + r.width / 2 + offset, r.y
1718:                            + r.height / 2);
1719:                    break;
1720:                case BOTTOM:
1721:                case TOP:
1722:                default:
1723:                    newIndex = getTabAtLocation(r.x + r.width / 2, r.y
1724:                            + r.height / 2 + offset);
1725:                }
1726:                if (newIndex != -1) {
1727:                    while (!tabPane.isEnabledAt(newIndex)
1728:                            && newIndex != tabIndex) {
1729:                        newIndex = getNextTabIndex(newIndex);
1730:                    }
1731:                    tabPane.setSelectedIndex(newIndex);
1732:                }
1733:            }
1734:
1735:            protected int getTabRunOffset(int tabPlacement, int tabCount,
1736:                    int tabIndex, boolean forward) {
1737:                int run = getRunForTab(tabCount, tabIndex);
1738:                int offset;
1739:                switch (tabPlacement) {
1740:                case LEFT: {
1741:                    if (run == 0) {
1742:                        offset = (forward ? -(calculateTabAreaWidth(
1743:                                tabPlacement, runCount, maxTabWidth) - maxTabWidth)
1744:                                : -maxTabWidth);
1745:
1746:                    } else if (run == runCount - 1) {
1747:                        offset = (forward ? maxTabWidth
1748:                                : calculateTabAreaWidth(tabPlacement, runCount,
1749:                                        maxTabWidth)
1750:                                        - maxTabWidth);
1751:                    } else {
1752:                        offset = (forward ? maxTabWidth : -maxTabWidth);
1753:                    }
1754:                    break;
1755:                }
1756:                case RIGHT: {
1757:                    if (run == 0) {
1758:                        offset = (forward ? maxTabWidth
1759:                                : calculateTabAreaWidth(tabPlacement, runCount,
1760:                                        maxTabWidth)
1761:                                        - maxTabWidth);
1762:                    } else if (run == runCount - 1) {
1763:                        offset = (forward ? -(calculateTabAreaWidth(
1764:                                tabPlacement, runCount, maxTabWidth) - maxTabWidth)
1765:                                : -maxTabWidth);
1766:                    } else {
1767:                        offset = (forward ? maxTabWidth : -maxTabWidth);
1768:                    }
1769:                    break;
1770:                }
1771:                case BOTTOM: {
1772:                    if (run == 0) {
1773:                        offset = (forward ? maxTabHeight
1774:                                : calculateTabAreaHeight(tabPlacement,
1775:                                        runCount, maxTabHeight)
1776:                                        - maxTabHeight);
1777:                    } else if (run == runCount - 1) {
1778:                        offset = (forward ? -(calculateTabAreaHeight(
1779:                                tabPlacement, runCount, maxTabHeight) - maxTabHeight)
1780:                                : -maxTabHeight);
1781:                    } else {
1782:                        offset = (forward ? maxTabHeight : -maxTabHeight);
1783:                    }
1784:                    break;
1785:                }
1786:                case TOP:
1787:                default: {
1788:                    if (run == 0) {
1789:                        offset = (forward ? -(calculateTabAreaHeight(
1790:                                tabPlacement, runCount, maxTabHeight) - maxTabHeight)
1791:                                : -maxTabHeight);
1792:                    } else if (run == runCount - 1) {
1793:                        offset = (forward ? maxTabHeight
1794:                                : calculateTabAreaHeight(tabPlacement,
1795:                                        runCount, maxTabHeight)
1796:                                        - maxTabHeight);
1797:                    } else {
1798:                        offset = (forward ? maxTabHeight : -maxTabHeight);
1799:                    }
1800:                }
1801:                }
1802:                return offset;
1803:            }
1804:
1805:            protected int getPreviousTabIndex(int base) {
1806:                int tabIndex = (base - 1 >= 0 ? base - 1 : tabPane
1807:                        .getTabCount() - 1);
1808:                return (tabIndex >= 0 ? tabIndex : 0);
1809:            }
1810:
1811:            protected int getNextTabIndex(int base) {
1812:                return (base + 1) % tabPane.getTabCount();
1813:            }
1814:
1815:            protected int getNextTabIndexInRun(int tabCount, int base) {
1816:                if (runCount < 2) {
1817:                    return getNextTabIndex(base);
1818:                }
1819:                int currentRun = getRunForTab(tabCount, base);
1820:                int next = getNextTabIndex(base);
1821:                if (next == tabRuns[getNextTabRun(currentRun)]) {
1822:                    return tabRuns[currentRun];
1823:                }
1824:                return next;
1825:            }
1826:
1827:            protected int getPreviousTabIndexInRun(int tabCount, int base) {
1828:                if (runCount < 2) {
1829:                    return getPreviousTabIndex(base);
1830:                }
1831:                int currentRun = getRunForTab(tabCount, base);
1832:                if (base == tabRuns[currentRun]) {
1833:                    int previous = tabRuns[getNextTabRun(currentRun)] - 1;
1834:                    return (previous != -1 ? previous : tabCount - 1);
1835:                }
1836:                return getPreviousTabIndex(base);
1837:            }
1838:
1839:            protected int getPreviousTabRun(int baseRun) {
1840:                int runIndex = (baseRun - 1 >= 0 ? baseRun - 1 : runCount - 1);
1841:                return (runIndex >= 0 ? runIndex : 0);
1842:            }
1843:
1844:            protected int getNextTabRun(int baseRun) {
1845:                return (baseRun + 1) % runCount;
1846:            }
1847:
1848:            protected static void rotateInsets(Insets topInsets,
1849:                    Insets targetInsets, int targetPlacement) {
1850:
1851:                switch (targetPlacement) {
1852:                case LEFT:
1853:                    targetInsets.top = topInsets.left;
1854:                    targetInsets.left = topInsets.top;
1855:                    targetInsets.bottom = topInsets.right;
1856:                    targetInsets.right = topInsets.bottom;
1857:                    break;
1858:                case BOTTOM:
1859:                    targetInsets.top = topInsets.bottom;
1860:                    targetInsets.left = topInsets.left;
1861:                    targetInsets.bottom = topInsets.top;
1862:                    targetInsets.right = topInsets.right;
1863:                    break;
1864:                case RIGHT:
1865:                    targetInsets.top = topInsets.left;
1866:                    targetInsets.left = topInsets.bottom;
1867:                    targetInsets.bottom = topInsets.right;
1868:                    targetInsets.right = topInsets.top;
1869:                    break;
1870:                case TOP:
1871:                default:
1872:                    targetInsets.top = topInsets.top;
1873:                    targetInsets.left = topInsets.left;
1874:                    targetInsets.bottom = topInsets.bottom;
1875:                    targetInsets.right = topInsets.right;
1876:                }
1877:            }
1878:
1879:            // REMIND(aim,7/29/98): This method should be made
1880:            // protected in the next release where
1881:            // API changes are allowed
1882:            //
1883:            boolean requestFocusForVisibleComponent() {
1884:                Component visibleComponent = getVisibleComponent();
1885:
1886:                if (visibleComponent.isFocusable()) {
1887:                    visibleComponent.requestFocus();
1888:                    return true;
1889:                }
1890:
1891:                else if (visibleComponent instanceof  JComponent) {
1892:                    JComponent jComponent = (JComponent) visibleComponent;
1893:
1894:                    //************* CHECK THIS **********************************
1895:                    if (jComponent.getFocusTraversalPolicy()
1896:                            .getDefaultComponent(jComponent)
1897:                            .requestFocusInWindow()) {
1898:                        return true;
1899:                    }
1900:
1901:                    //             if (((JComponent)visibleComponent).requestDefaultFocus()) {
1902:                    //                 return true;
1903:                    //             }
1904:                }
1905:
1906:                return false;
1907:
1908:            }
1909:
1910:            private static class RightAction extends AbstractAction {
1911:                public void actionPerformed(ActionEvent e) {
1912:                    JTabbedPane pane = (JTabbedPane) e.getSource();
1913:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI) pane.getUI();
1914:                    ui.navigateSelectedTab(EAST);
1915:                }
1916:            };
1917:
1918:            private static class LeftAction extends AbstractAction {
1919:                public void actionPerformed(ActionEvent e) {
1920:                    JTabbedPane pane = (JTabbedPane) e.getSource();
1921:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI) pane.getUI();
1922:                    ui.navigateSelectedTab(WEST);
1923:                }
1924:            };
1925:
1926:            private static class UpAction extends AbstractAction {
1927:                public void actionPerformed(ActionEvent e) {
1928:                    JTabbedPane pane = (JTabbedPane) e.getSource();
1929:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI) pane.getUI();
1930:                    ui.navigateSelectedTab(NORTH);
1931:                }
1932:            };
1933:
1934:            private static class DownAction extends AbstractAction {
1935:                public void actionPerformed(ActionEvent e) {
1936:                    JTabbedPane pane = (JTabbedPane) e.getSource();
1937:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI) pane.getUI();
1938:                    ui.navigateSelectedTab(SOUTH);
1939:                }
1940:            };
1941:
1942:            private static class NextAction extends AbstractAction {
1943:                public void actionPerformed(ActionEvent e) {
1944:                    JTabbedPane pane = (JTabbedPane) e.getSource();
1945:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI) pane.getUI();
1946:                    ui.navigateSelectedTab(NEXT);
1947:                }
1948:            };
1949:
1950:            private static class PreviousAction extends AbstractAction {
1951:                public void actionPerformed(ActionEvent e) {
1952:                    JTabbedPane pane = (JTabbedPane) e.getSource();
1953:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI) pane.getUI();
1954:                    ui.navigateSelectedTab(PREVIOUS);
1955:                }
1956:            };
1957:
1958:            private static class PageUpAction extends AbstractAction {
1959:                public void actionPerformed(ActionEvent e) {
1960:                    JTabbedPane pane = (JTabbedPane) e.getSource();
1961:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI) pane.getUI();
1962:                    int tabPlacement = pane.getTabPlacement();
1963:                    if (tabPlacement == TOP || tabPlacement == BOTTOM) {
1964:                        ui.navigateSelectedTab(WEST);
1965:                    } else {
1966:                        ui.navigateSelectedTab(NORTH);
1967:                    }
1968:                }
1969:            };
1970:
1971:            private static class PageDownAction extends AbstractAction {
1972:                public void actionPerformed(ActionEvent e) {
1973:                    JTabbedPane pane = (JTabbedPane) e.getSource();
1974:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI) pane.getUI();
1975:                    int tabPlacement = pane.getTabPlacement();
1976:                    if (tabPlacement == TOP || tabPlacement == BOTTOM) {
1977:                        ui.navigateSelectedTab(EAST);
1978:                    } else {
1979:                        ui.navigateSelectedTab(SOUTH);
1980:                    }
1981:                }
1982:            };
1983:
1984:            private static class RequestFocusAction extends AbstractAction {
1985:                public void actionPerformed(ActionEvent e) {
1986:                    JTabbedPane pane = (JTabbedPane) e.getSource();
1987:                    pane.requestFocus();
1988:                }
1989:            };
1990:
1991:            private static class RequestFocusForVisibleAction extends
1992:                    AbstractAction {
1993:                public void actionPerformed(ActionEvent e) {
1994:                    JTabbedPane pane = (JTabbedPane) e.getSource();
1995:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI) pane.getUI();
1996:                    ui.requestFocusForVisibleComponent();
1997:                }
1998:            };
1999:
2000:            /**
2001:             * Selects a tab in the JTabbedPane based on the String of the
2002:             * action command. The tab selected is based on the first tab that
2003:             * has a mnemonic matching the first character of the action command.
2004:             */
2005:            private static class SetSelectedIndexAction extends AbstractAction {
2006:                public void actionPerformed(ActionEvent e) {
2007:                    JTabbedPane pane = (JTabbedPane) e.getSource();
2008:
2009:                    if (pane != null
2010:                            && (pane.getUI() instanceof  FlatTabbedPaneUI)) {
2011:                        FlatTabbedPaneUI ui = (FlatTabbedPaneUI) pane.getUI();
2012:                        String command = e.getActionCommand();
2013:
2014:                        if (command != null && command.length() > 0) {
2015:                            int mnemonic = (int) e.getActionCommand().charAt(0);
2016:                            if (mnemonic >= 'a' && mnemonic <= 'z') {
2017:                                mnemonic -= ('a' - 'A');
2018:                            }
2019:                            Integer index = (Integer) ui.mnemonicToIndexMap
2020:                                    .get(new Integer(mnemonic));
2021:                            if (index != null
2022:                                    && pane.isEnabledAt(index.intValue())) {
2023:                                pane.setSelectedIndex(index.intValue());
2024:                            }
2025:                        }
2026:                    }
2027:                }
2028:            };
2029:
2030:            /*
2031:            private static class FlatScrollTabsForwardAction extends AbstractAction {
2032:                public void actionPerformed(ActionEvent e) {
2033:                    JTabbedPane pane = null;
2034:                    Object src = e.getSource();
2035:                    if (src instanceof JTabbedPane) {
2036:                        pane = (JTabbedPane)src;
2037:                    } else if (src instanceof ScrollableTabButton) {
2038:                        pane = (JTabbedPane)((ScrollableTabButton)src).getParent();
2039:                    } else {
2040:                        return; // shouldn't happen
2041:                    }
2042:                    
2043:                    //System.out.println("pane: "+pane.getClass().getName());
2044:                    //System.out.println("ui: "+(pane.getUI()).getClass().getName());
2045:                    
2046:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI)pane.getUI();
2047:
2048:                    if (ui.scrollableTabLayoutEnabled()) {
2049:                        ui.tabScroller.scrollForward(pane.getTabPlacement());
2050:                    }
2051:                }
2052:            }
2053:            
2054:            private static class FlatScrollTabsBackwardAction extends AbstractAction {
2055:                public void actionPerformed(ActionEvent e) {
2056:                    JTabbedPane pane = null;
2057:                    Object src = e.getSource();
2058:                    if (src instanceof JTabbedPane) {
2059:                        pane = (JTabbedPane)src;
2060:                    } else if (src instanceof ScrollableTabButton) {
2061:                        pane = (JTabbedPane)((ScrollableTabButton)src).getParent();
2062:                    } else {
2063:                        return; // shouldn't happen
2064:                    }
2065:                    FlatTabbedPaneUI ui = (FlatTabbedPaneUI)pane.getUI();
2066:
2067:                    
2068:                    
2069:                    if (ui.scrollableTabLayoutEnabled()) {
2070:                        ui.tabScroller.scrollBackward(pane.getTabPlacement());
2071:                    }
2072:                }
2073:            }
2074:             */
2075:            /**
2076:             * This inner class is marked &quot;public&quot; due to a compiler bug.
2077:             * This class should be treated as a &quot;protected&quot; inner class.
2078:             * Instantiate it only within subclasses of FlatTabbedPaneUI.
2079:             */
2080:            public class TabbedPaneLayout implements  LayoutManager {
2081:
2082:                public void addLayoutComponent(String name, Component comp) {
2083:                }
2084:
2085:                public void removeLayoutComponent(Component comp) {
2086:                }
2087:
2088:                public Dimension preferredLayoutSize(Container parent) {
2089:                    return calculateSize(false);
2090:                }
2091:
2092:                public Dimension minimumLayoutSize(Container parent) {
2093:                    return calculateSize(true);
2094:                }
2095:
2096:                protected Dimension calculateSize(boolean minimum) {
2097:                    int tabPlacement = tabPane.getTabPlacement();
2098:                    Insets insets = tabPane.getInsets();
2099:                    Insets contentInsets = getContentBorderInsets(tabPlacement);
2100:                    Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
2101:
2102:                    Dimension zeroSize = new Dimension(0, 0);
2103:                    int height = contentInsets.top + contentInsets.bottom;
2104:                    int width = contentInsets.left + contentInsets.right;
2105:                    int cWidth = 0;
2106:                    int cHeight = 0;
2107:
2108:                    // Determine minimum size required to display largest
2109:                    // child in each dimension
2110:                    //
2111:                    for (int i = 0; i < tabPane.getTabCount(); i++) {
2112:                        Component component = tabPane.getComponentAt(i);
2113:                        if (component != null) {
2114:                            Dimension size = zeroSize;
2115:                            size = minimum ? component.getMinimumSize()
2116:                                    : component.getPreferredSize();
2117:
2118:                            if (size != null) {
2119:                                cHeight = Math.max(size.height, cHeight);
2120:                                cWidth = Math.max(size.width, cWidth);
2121:                            }
2122:                        }
2123:                    }
2124:                    // Add content border insets to minimum size
2125:                    width += cWidth;
2126:                    height += cHeight;
2127:                    int tabExtent = 0;
2128:
2129:                    // Calculate how much space the tabs will need, based on the
2130:                    // minimum size required to display largest child + content border
2131:                    //
2132:                    switch (tabPlacement) {
2133:                    case LEFT:
2134:                    case RIGHT:
2135:                        height = Math.max(height,
2136:                                calculateMaxTabHeight(tabPlacement)
2137:                                        + tabAreaInsets.top
2138:                                        + tabAreaInsets.bottom);
2139:                        tabExtent = preferredTabAreaWidth(tabPlacement, height);
2140:                        width += tabExtent;
2141:                        break;
2142:                    case TOP:
2143:                    case BOTTOM:
2144:                    default:
2145:                        width = Math.max(width,
2146:                                calculateMaxTabWidth(tabPlacement)
2147:                                        + tabAreaInsets.left
2148:                                        + tabAreaInsets.right);
2149:                        tabExtent = preferredTabAreaHeight(tabPlacement, width);
2150:                        height += tabExtent;
2151:                    }
2152:                    return new Dimension(width + insets.left + insets.right,
2153:                            height + insets.bottom + insets.top);
2154:
2155:                }
2156:
2157:                protected int preferredTabAreaHeight(int tabPlacement, int width) {
2158:                    FontMetrics metrics = getFontMetrics();
2159:                    int tabCount = tabPane.getTabCount();
2160:                    int total = 0;
2161:                    if (tabCount > 0) {
2162:                        int rows = 1;
2163:                        int x = 0;
2164:
2165:                        int maxTabHeight = calculateMaxTabHeight(tabPlacement);
2166:
2167:                        for (int i = 0; i < tabCount; i++) {
2168:                            int tabWidth = calculateTabWidth(tabPlacement, i,
2169:                                    metrics);
2170:
2171:                            if (x != 0 && x + tabWidth > width) {
2172:                                rows++;
2173:                                x = 0;
2174:                            }
2175:                            x += tabWidth;
2176:                        }
2177:                        total = calculateTabAreaHeight(tabPlacement, rows,
2178:                                maxTabHeight);
2179:                    }
2180:                    return total;
2181:                }
2182:
2183:                protected int preferredTabAreaWidth(int tabPlacement, int height) {
2184:                    FontMetrics metrics = getFontMetrics();
2185:                    int tabCount = tabPane.getTabCount();
2186:                    int total = 0;
2187:                    if (tabCount > 0) {
2188:                        int columns = 1;
2189:                        int y = 0;
2190:                        int fontHeight = metrics.getHeight();
2191:
2192:                        maxTabWidth = calculateMaxTabWidth(tabPlacement);
2193:
2194:                        for (int i = 0; i < tabCount; i++) {
2195:                            int tabHeight = calculateTabHeight(tabPlacement, i,
2196:                                    fontHeight);
2197:
2198:                            if (y != 0 && y + tabHeight > height) {
2199:                                columns++;
2200:                                y = 0;
2201:                            }
2202:                            y += tabHeight;
2203:                        }
2204:                        total = calculateTabAreaWidth(tabPlacement, columns,
2205:                                maxTabWidth);
2206:                    }
2207:                    return total;
2208:                }
2209:
2210:                public void layoutContainer(Container parent) {
2211:                    int tabPlacement = tabPane.getTabPlacement();
2212:                    Insets insets = tabPane.getInsets();
2213:                    int selectedIndex = tabPane.getSelectedIndex();
2214:                    Component visibleComponent = getVisibleComponent();
2215:
2216:                    calculateLayoutInfo();
2217:
2218:                    if (selectedIndex < 0) {
2219:                        if (visibleComponent != null) {
2220:                            // The last tab was removed, so remove the component
2221:                            setVisibleComponent(null);
2222:                        }
2223:                    } else {
2224:                        int cx, cy, cw, ch;
2225:                        int totalTabWidth = 0;
2226:                        int totalTabHeight = 0;
2227:                        Insets contentInsets = getContentBorderInsets(tabPlacement);
2228:
2229:                        Component selectedComponent = tabPane
2230:                                .getComponentAt(selectedIndex);
2231:                        boolean shouldChangeFocus = false;
2232:
2233:                        // In order to allow programs to use a single component
2234:                        // as the display for multiple tabs, we will not change
2235:                        // the visible compnent if the currently selected tab
2236:                        // has a null component.  This is a bit dicey, as we don't
2237:                        // explicitly state we support this in the spec, but since
2238:                        // programs are now depending on this, we're making it work.
2239:                        //
2240:                        if (selectedComponent != null) {
2241:                            if (selectedComponent != visibleComponent
2242:                                    && visibleComponent != null) {
2243:
2244:                                if (SwingUtilities
2245:                                        .findFocusOwner(visibleComponent) != null) {
2246:                                    shouldChangeFocus = true;
2247:                                }
2248:                            }
2249:                            setVisibleComponent(selectedComponent);
2250:                        }
2251:
2252:                        Rectangle bounds = tabPane.getBounds();
2253:                        int numChildren = tabPane.getComponentCount();
2254:
2255:                        if (numChildren > 0) {
2256:
2257:                            switch (tabPlacement) {
2258:                            case LEFT:
2259:                                totalTabWidth = calculateTabAreaWidth(
2260:                                        tabPlacement, runCount, maxTabWidth);
2261:                                cx = insets.left + totalTabWidth
2262:                                        + contentInsets.left;
2263:                                cy = insets.top + contentInsets.top;
2264:                                break;
2265:                            case RIGHT:
2266:                                totalTabWidth = calculateTabAreaWidth(
2267:                                        tabPlacement, runCount, maxTabWidth);
2268:                                cx = insets.left + contentInsets.left;
2269:                                cy = insets.top + contentInsets.top;
2270:                                break;
2271:                            case BOTTOM:
2272:                                totalTabHeight = calculateTabAreaHeight(
2273:                                        tabPlacement, runCount, maxTabHeight);
2274:                                cx = insets.left + contentInsets.left;
2275:                                cy = insets.top + contentInsets.top;
2276:                                break;
2277:                            case TOP:
2278:                            default:
2279:                                totalTabHeight = calculateTabAreaHeight(
2280:                                        tabPlacement, runCount, maxTabHeight);
2281:                                cx = insets.left + contentInsets.left;
2282:                                cy = insets.top + totalTabHeight
2283:                                        + contentInsets.top;
2284:                            }
2285:
2286:                            cw = bounds.width - totalTabWidth - insets.left
2287:                                    - insets.right - contentInsets.left
2288:                                    - contentInsets.right;
2289:                            ch = bounds.height - totalTabHeight - insets.top
2290:                                    - insets.bottom - contentInsets.top
2291:                                    - contentInsets.bottom;
2292:
2293:                            for (int i = 0; i < numChildren; i++) {
2294:                                Component child = tabPane.getComponent(i);
2295:                                child.setBounds(cx, cy, cw, ch);
2296:                            }
2297:                        }
2298:
2299:                        if (shouldChangeFocus) {
2300:                            if (!requestFocusForVisibleComponent()) {
2301:                                tabPane.requestFocus();
2302:                            }
2303:                        }
2304:                    }
2305:                }
2306:
2307:                public void calculateLayoutInfo() {
2308:                    int tabCount = tabPane.getTabCount();
2309:                    assureRectsCreated(tabCount);
2310:                    calculateTabRects(tabPane.getTabPlacement(), tabCount);
2311:                }
2312:
2313:                protected void calculateTabRects(int tabPlacement, int tabCount) {
2314:                    FontMetrics metrics = getFontMetrics();
2315:                    Dimension size = tabPane.getSize();
2316:                    Insets insets = tabPane.getInsets();
2317:                    Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
2318:                    int fontHeight = metrics.getHeight();
2319:                    int selectedIndex = tabPane.getSelectedIndex();
2320:                    int tabRunOverlay;
2321:                    int i, j;
2322:                    int x, y;
2323:                    int returnAt;
2324:                    boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT);
2325:                    boolean leftToRight = isLeftToRight(tabPane);
2326:
2327:                    //
2328:                    // Calculate bounds within which a tab run must fit
2329:                    //
2330:                    switch (tabPlacement) {
2331:                    case LEFT:
2332:                        maxTabWidth = calculateMaxTabWidth(tabPlacement);
2333:                        x = insets.left + tabAreaInsets.left;
2334:                        y = insets.top + tabAreaInsets.top;
2335:                        returnAt = size.height
2336:                                - (insets.bottom + tabAreaInsets.bottom);
2337:                        break;
2338:                    case RIGHT:
2339:                        maxTabWidth = calculateMaxTabWidth(tabPlacement);
2340:                        x = size.width - insets.right - tabAreaInsets.right
2341:                                - maxTabWidth;
2342:                        y = insets.top + tabAreaInsets.top;
2343:                        returnAt = size.height
2344:                                - (insets.bottom + tabAreaInsets.bottom);
2345:                        break;
2346:                    case BOTTOM:
2347:                        maxTabHeight = calculateMaxTabHeight(tabPlacement);
2348:                        x = insets.left + tabAreaInsets.left;
2349:                        y = size.height - insets.bottom - tabAreaInsets.bottom
2350:                                - maxTabHeight;
2351:                        returnAt = size.width
2352:                                - (insets.right + tabAreaInsets.right);
2353:                        break;
2354:                    case TOP:
2355:                    default:
2356:                        maxTabHeight = calculateMaxTabHeight(tabPlacement);
2357:                        x = insets.left + tabAreaInsets.left;
2358:                        y = insets.top + tabAreaInsets.top;
2359:                        returnAt = size.width
2360:                                - (insets.right + tabAreaInsets.right);
2361:                        break;
2362:                    }
2363:
2364:                    tabRunOverlay = getTabRunOverlay(tabPlacement);
2365:
2366:                    runCount = 0;
2367:                    selectedRun = -1;
2368:
2369:                    if (tabCount == 0) {
2370:                        return;
2371:                    }
2372:
2373:                    // Run through tabs and partition them into runs
2374:                    Rectangle rect;
2375:                    for (i = 0; i < tabCount; i++) {
2376:                        rect = rects[i];
2377:
2378:                        if (!verticalTabRuns) {
2379:                            // Tabs on TOP or BOTTOM....
2380:                            if (i > 0) {
2381:                                rect.x = rects[i - 1].x + rects[i - 1].width;
2382:                            } else {
2383:                                tabRuns[0] = 0;
2384:                                runCount = 1;
2385:                                maxTabWidth = 0;
2386:                                rect.x = x;
2387:                            }
2388:                            rect.width = calculateTabWidth(tabPlacement, i,
2389:                                    metrics);
2390:                            maxTabWidth = Math.max(maxTabWidth, rect.width);
2391:
2392:                            // Never move a TAB down a run if it is in the first column.
2393:                            // Even if there isn't enough room, moving it to a fresh
2394:                            // line won't help.
2395:                            if (rect.x != 2 + insets.left
2396:                                    && rect.x + rect.width > returnAt) {
2397:                                if (runCount > tabRuns.length - 1) {
2398:                                    expandTabRunsArray();
2399:                                }
2400:                                tabRuns[runCount] = i;
2401:                                runCount++;
2402:                                rect.x = x;
2403:                            }
2404:                            // Initialize y position in case there's just one run
2405:                            rect.y = y;
2406:                            rect.height = maxTabHeight/* - 2*/;
2407:
2408:                        } else {
2409:                            // Tabs on LEFT or RIGHT...
2410:                            if (i > 0) {
2411:                                rect.y = rects[i - 1].y + rects[i - 1].height;
2412:                            } else {
2413:                                tabRuns[0] = 0;
2414:                                runCount = 1;
2415:                                maxTabHeight = 0;
2416:                                rect.y = y;
2417:                            }
2418:                            rect.height = calculateTabHeight(tabPlacement, i,
2419:                                    fontHeight);
2420:                            maxTabHeight = Math.max(maxTabHeight, rect.height);
2421:
2422:                            // Never move a TAB over a run if it is in the first run.
2423:                            // Even if there isn't enough room, moving it to a fresh
2424:                            // column won't help.
2425:                            if (rect.y != 2 + insets.top
2426:                                    && rect.y + rect.height > returnAt) {
2427:                                if (runCount > tabRuns.length - 1) {
2428:                                    expandTabRunsArray();
2429:                                }
2430:                                tabRuns[runCount] = i;
2431:                                runCount++;
2432:                                rect.y = y;
2433:                            }
2434:                            // Initialize x position in case there's just one column
2435:                            rect.x = x;
2436:                            rect.width = maxTabWidth/* - 2*/;
2437:
2438:                        }
2439:                        if (i == selectedIndex) {
2440:                            selectedRun = runCount - 1;
2441:                        }
2442:                    }
2443:
2444:                    if (runCount > 1) {
2445:                        // Re-distribute tabs in case last run has leftover space
2446:                        normalizeTabRuns(tabPlacement, tabCount,
2447:                                verticalTabRuns ? y : x, returnAt);
2448:
2449:                        selectedRun = getRunForTab(tabCount, selectedIndex);
2450:
2451:                        // Rotate run array so that selected run is first
2452:                        if (shouldRotateTabRuns(tabPlacement)) {
2453:                            rotateTabRuns(tabPlacement, selectedRun);
2454:                        }
2455:                    }
2456:
2457:                    // Step through runs from back to front to calculate
2458:                    // tab y locations and to pad runs appropriately
2459:                    for (i = runCount - 1; i >= 0; i--) {
2460:                        int start = tabRuns[i];
2461:                        int next = tabRuns[i == (runCount - 1) ? 0 : i + 1];
2462:                        int end = (next != 0 ? next - 1 : tabCount - 1);
2463:                        if (!verticalTabRuns) {
2464:                            for (j = start; j <= end; j++) {
2465:                                rect = rects[j];
2466:                                rect.y = y;
2467:                                rect.x += getTabRunIndent(tabPlacement, i);
2468:                            }
2469:                            if (shouldPadTabRun(tabPlacement, i)) {
2470:                                padTabRun(tabPlacement, start, end, returnAt);
2471:                            }
2472:                            if (tabPlacement == BOTTOM) {
2473:                                y -= (maxTabHeight - tabRunOverlay);
2474:                            } else {
2475:                                y += (maxTabHeight - tabRunOverlay);
2476:                            }
2477:                        } else {
2478:                            for (j = start; j <= end; j++) {
2479:                                rect = rects[j];
2480:                                rect.x = x;
2481:                                rect.y += getTabRunIndent(tabPlacement, i);
2482:                            }
2483:                            if (shouldPadTabRun(tabPlacement, i)) {
2484:                                padTabRun(tabPlacement, start, end, returnAt);
2485:                            }
2486:                            if (tabPlacement == RIGHT) {
2487:                                x -= (maxTabWidth - tabRunOverlay);
2488:                            } else {
2489:                                x += (maxTabWidth - tabRunOverlay);
2490:                            }
2491:                        }
2492:                    }
2493:
2494:                    // Pad the selected tab so that it appears raised in front
2495:                    padSelectedTab(tabPlacement, selectedIndex);
2496:
2497:                    // if right to left and tab placement on the top or
2498:                    // the bottom, flip x positions and adjust by widths
2499:                    if (!leftToRight && !verticalTabRuns) {
2500:                        int rightMargin = size.width
2501:                                - (insets.right + tabAreaInsets.right);
2502:                        for (i = 0; i < tabCount; i++) {
2503:                            rects[i].x = rightMargin - rects[i].x
2504:                                    - rects[i].width;
2505:                        }
2506:                    }
2507:                }
2508:
2509:                /*
2510:                 * Rotates the run-index array so that the selected run is run[0]
2511:                 */
2512:                protected void rotateTabRuns(int tabPlacement, int selectedRun) {
2513:                    for (int i = 0; i < selectedRun; i++) {
2514:                        int save = tabRuns[0];
2515:                        for (int j = 1; j < runCount; j++) {
2516:                            tabRuns[j - 1] = tabRuns[j];
2517:                        }
2518:                        tabRuns[runCount - 1] = save;
2519:                    }
2520:                }
2521:
2522:                protected void normalizeTabRuns(int tabPlacement, int tabCount,
2523:                        int start, int max) {
2524:                    boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT);
2525:                    int run = runCount - 1;
2526:                    boolean keepAdjusting = true;
2527:                    double weight = 1.25;
2528:
2529:                    // At this point the tab runs are packed to fit as many
2530:                    // tabs as possible, which can leave the last run with a lot
2531:                    // of extra space (resulting in very fat tabs on the last run).
2532:                    // So we'll attempt to distribute this extra space more evenly
2533:                    // across the runs in order to make the runs look more consistent.
2534:                    //
2535:                    // Starting with the last run, determine whether the last tab in
2536:                    // the previous run would fit (generously) in this run; if so,
2537:                    // move tab to current run and shift tabs accordingly.  Cycle
2538:                    // through remaining runs using the same algorithm.
2539:                    //
2540:                    while (keepAdjusting) {
2541:                        int last = lastTabInRun(tabCount, run);
2542:                        int prevLast = lastTabInRun(tabCount, run - 1);
2543:                        int end;
2544:                        int prevLastLen;
2545:
2546:                        if (!verticalTabRuns) {
2547:                            end = rects[last].x + rects[last].width;
2548:                            prevLastLen = (int) (maxTabWidth * weight);
2549:                        } else {
2550:                            end = rects[last].y + rects[last].height;
2551:                            prevLastLen = (int) (maxTabHeight * weight * 2);
2552:                        }
2553:
2554:                        // Check if the run has enough extra space to fit the last tab
2555:                        // from the previous row...
2556:                        if (max - end > prevLastLen) {
2557:
2558:                            // Insert tab from previous row and shift rest over
2559:                            tabRuns[run] = prevLast;
2560:                            if (!verticalTabRuns) {
2561:                                rects[prevLast].x = start;
2562:                            } else {
2563:                                rects[prevLast].y = start;
2564:                            }
2565:                            for (int i = prevLast + 1; i <= last; i++) {
2566:                                if (!verticalTabRuns) {
2567:                                    rects[i].x = rects[i - 1].x
2568:                                            + rects[i - 1].width;
2569:                                } else {
2570:                                    rects[i].y = rects[i - 1].y
2571:                                            + rects[i - 1].height;
2572:                                }
2573:                            }
2574:
2575:                        } else if (run == runCount - 1) {
2576:                            // no more room left in last run, so we're done!
2577:                            keepAdjusting = false;
2578:                        }
2579:                        if (run - 1 > 0) {
2580:                            // check previous run next...
2581:                            run -= 1;
2582:                        } else {
2583:                            // check last run again...but require a higher ratio
2584:                            // of extraspace-to-tabsize because we don't want to
2585:                            // end up with too many tabs on the last run!
2586:                            run = runCount - 1;
2587:                            weight += .25;
2588:                        }
2589:                    }
2590:                }
2591:
2592:                protected void padTabRun(int tabPlacement, int start, int end,
2593:                        int max) {
2594:                    Rectangle lastRect = rects[end];
2595:                    if (tabPlacement == TOP || tabPlacement == BOTTOM) {
2596:                        int runWidth = (lastRect.x + lastRect.width)
2597:                                - rects[start].x;
2598:                        int deltaWidth = max - (lastRect.x + lastRect.width);
2599:                        float factor = (float) deltaWidth / (float) runWidth;
2600:
2601:                        for (int j = start; j <= end; j++) {
2602:                            Rectangle pastRect = rects[j];
2603:                            if (j > start) {
2604:                                pastRect.x = rects[j - 1].x
2605:                                        + rects[j - 1].width;
2606:                            }
2607:                            pastRect.width += Math.round((float) pastRect.width
2608:                                    * factor);
2609:                        }
2610:                        lastRect.width = max - lastRect.x;
2611:                    } else {
2612:                        int runHeight = (lastRect.y + lastRect.height)
2613:                                - rects[start].y;
2614:                        int deltaHeight = max - (lastRect.y + lastRect.height);
2615:                        float factor = (float) deltaHeight / (float) runHeight;
2616:
2617:                        for (int j = start; j <= end; j++) {
2618:                            Rectangle pastRect = rects[j];
2619:                            if (j > start) {
2620:                                pastRect.y = rects[j - 1].y
2621:                                        + rects[j - 1].height;
2622:                            }
2623:                            pastRect.height += Math
2624:                                    .round((float) pastRect.height * factor);
2625:                        }
2626:                        lastRect.height = max - lastRect.y;
2627:                    }
2628:                }
2629:
2630:                protected void padSelectedTab(int tabPlacement,
2631:                        int selectedIndex) {
2632:
2633:                    if (selectedIndex >= 0) {
2634:                        Rectangle selRect = rects[selectedIndex];
2635:                        Insets padInsets = getSelectedTabPadInsets(tabPlacement);
2636:                        selRect.x -= padInsets.left;
2637:                        selRect.width += (padInsets.left + padInsets.right);
2638:                        selRect.y -= padInsets.top;
2639:                        selRect.height += (padInsets.top + padInsets.bottom);
2640:                    }
2641:                }
2642:            }
2643:
2644:            private class TabbedPaneScrollLayout extends TabbedPaneLayout {
2645:
2646:                protected int preferredTabAreaHeight(int tabPlacement, int width) {
2647:                    return calculateMaxTabHeight(tabPlacement);
2648:                }
2649:
2650:                protected int preferredTabAreaWidth(int tabPlacement, int height) {
2651:                    return calculateMaxTabWidth(tabPlacement);
2652:                }
2653:
2654:                public void layoutContainer(Container parent) {
2655:                    int tabPlacement = tabPane.getTabPlacement();
2656:                    int tabCount = tabPane.getTabCount();
2657:                    Insets insets = tabPane.getInsets();
2658:                    int selectedIndex = tabPane.getSelectedIndex();
2659:                    Component visibleComponent = getVisibleComponent();
2660:
2661:                    calculateLayoutInfo();
2662:
2663:                    if (selectedIndex < 0) {
2664:                        if (visibleComponent != null) {
2665:                            // The last tab was removed, so remove the component
2666:                            setVisibleComponent(null);
2667:                        }
2668:                    } else {
2669:                        Component selectedComponent = tabPane
2670:                                .getComponentAt(selectedIndex);
2671:                        boolean shouldChangeFocus = false;
2672:
2673:                        // In order to allow programs to use a single component
2674:                        // as the display for multiple tabs, we will not change
2675:                        // the visible compnent if the currently selected tab
2676:                        // has a null component.  This is a bit dicey, as we don't
2677:                        // explicitly state we support this in the spec, but since
2678:                        // programs are now depending on this, we're making it work.
2679:                        //
2680:                        if (selectedComponent != null) {
2681:                            if (selectedComponent != visibleComponent
2682:                                    && visibleComponent != null) {
2683:                                if (SwingUtilities
2684:                                        .findFocusOwner(visibleComponent) != null) {
2685:                                    shouldChangeFocus = true;
2686:                                }
2687:                            }
2688:                            setVisibleComponent(selectedComponent);
2689:                        }
2690:                        int tx, ty, tw, th; // tab area bounds
2691:                        int cx, cy, cw, ch; // content area bounds
2692:                        Insets contentInsets = getContentBorderInsets(tabPlacement);
2693:                        Rectangle bounds = tabPane.getBounds();
2694:                        int numChildren = tabPane.getComponentCount();
2695:
2696:                        if (numChildren > 0) {
2697:                            switch (tabPlacement) {
2698:                            case LEFT:
2699:                                // calculate tab area bounds
2700:                                tw = calculateTabAreaWidth(tabPlacement,
2701:                                        runCount, maxTabWidth);
2702:                                th = bounds.height - insets.top - insets.bottom;
2703:                                tx = insets.left;
2704:                                ty = insets.top;
2705:
2706:                                // calculate content area bounds
2707:                                cx = tx + tw + contentInsets.left;
2708:                                cy = ty + contentInsets.top;
2709:                                cw = bounds.width - insets.left - insets.right
2710:                                        - tw - contentInsets.left
2711:                                        - contentInsets.right;
2712:                                ch = bounds.height - insets.top - insets.bottom
2713:                                        - contentInsets.top
2714:                                        - contentInsets.bottom;
2715:                                break;
2716:                            case RIGHT:
2717:                                // calculate tab area bounds
2718:                                tw = calculateTabAreaWidth(tabPlacement,
2719:                                        runCount, maxTabWidth);
2720:                                th = bounds.height - insets.top - insets.bottom;
2721:                                tx = bounds.width - insets.right - tw;
2722:                                ty = insets.top;
2723:
2724:                                // calculate content area bounds
2725:                                cx = insets.left + contentInsets.left;
2726:                                cy = insets.top + contentInsets.top;
2727:                                cw = bounds.width - insets.left - insets.right
2728:                                        - tw - contentInsets.left
2729:                                        - contentInsets.right;
2730:                                ch = bounds.height - insets.top - insets.bottom
2731:                                        - contentInsets.top
2732:                                        - contentInsets.bottom;
2733:                                break;
2734:                            case BOTTOM:
2735:                                // calculate tab area bounds
2736:                                tw = bounds.width - insets.left - insets.right;
2737:                                th = calculateTabAreaHeight(tabPlacement,
2738:                                        runCount, maxTabHeight);
2739:                                tx = insets.left;
2740:                                ty = bounds.height - insets.bottom - th;
2741:
2742:                                // calculate content area bounds
2743:                                cx = insets.left + contentInsets.left;
2744:                                cy = insets.top + contentInsets.top;
2745:                                cw = bounds.width - insets.left - insets.right
2746:                                        - contentInsets.left
2747:                                        - contentInsets.right;
2748:                                ch = bounds.height - insets.top - insets.bottom
2749:                                        - th - contentInsets.top
2750:                                        - contentInsets.bottom;
2751:                                break;
2752:                            case TOP:
2753:                            default:
2754:                                // calculate tab area bounds
2755:                                tw = bounds.width - insets.left - insets.right;
2756:                                th = calculateTabAreaHeight(tabPlacement,
2757:                                        runCount, maxTabHeight);
2758:                                tx = insets.left;
2759:                                ty = insets.top;
2760:
2761:                                // calculate content area bounds
2762:                                cx = tx + contentInsets.left;
2763:                                cy = ty + th + contentInsets.top;
2764:                                cw = bounds.width - insets.left - insets.right
2765:                                        - contentInsets.left
2766:                                        - contentInsets.right;
2767:                                ch = bounds.height - insets.top - insets.bottom
2768:                                        - th - contentInsets.top
2769:                                        - contentInsets.bottom;
2770:                            }
2771:
2772:                            for (int i = 0; i < numChildren; i++) {
2773:                                Component child = tabPane.getComponent(i);
2774:
2775:                                if (child instanceof  ScrollableTabViewport) {
2776:                                    JViewport viewport = (JViewport) child;
2777:                                    Rectangle viewRect = viewport.getViewRect();
2778:                                    int vw = tw;
2779:                                    int vh = th;
2780:                                    switch (tabPlacement) {
2781:                                    case LEFT:
2782:                                    case RIGHT:
2783:                                        int totalTabHeight = rects[tabCount - 1].y
2784:                                                + rects[tabCount - 1].height;
2785:                                        if (totalTabHeight > th) {
2786:                                            // Allow space for scrollbuttons
2787:                                            vh = Math.max(th - 36, 36);
2788:                                            if (totalTabHeight - viewRect.y <= vh) {
2789:                                                // Scrolled to the end, so ensure the viewport size is
2790:                                                // such that the scroll offset aligns with a tab
2791:                                                vh = totalTabHeight
2792:                                                        - viewRect.y;
2793:                                            }
2794:                                        }
2795:                                        break;
2796:                                    case BOTTOM:
2797:                                    case TOP:
2798:                                    default:
2799:                                        int totalTabWidth = rects[tabCount - 1].x
2800:                                                + rects[tabCount - 1].width;
2801:                                        if (totalTabWidth > tw) {
2802:                                            // Need to allow space for scrollbuttons
2803:                                            vw = Math.max(tw - 36, 36);
2804:                                            ;
2805:                                            if (totalTabWidth - viewRect.x <= vw) {
2806:                                                // Scrolled to the end, so ensure the viewport size is
2807:                                                // such that the scroll offset aligns with a tab
2808:                                                vw = totalTabWidth - viewRect.x;
2809:                                            }
2810:                                        }
2811:                                    }
2812:                                    child.setBounds(tx, ty, vw, vh);
2813:
2814:                                } else if (child instanceof  ScrollableTabButton) {
2815:                                    ScrollableTabButton scrollbutton = (ScrollableTabButton) child;
2816:                                    Dimension bsize = scrollbutton
2817:                                            .getPreferredSize();
2818:                                    int bx = 0;
2819:                                    int by = 0;
2820:                                    int bw = bsize.width;
2821:                                    int bh = bsize.height;
2822:                                    boolean visible = false;
2823:
2824:                                    switch (tabPlacement) {
2825:                                    case LEFT:
2826:                                    case RIGHT:
2827:                                        int totalTabHeight = rects[tabCount - 1].y
2828:                                                + rects[tabCount - 1].height;
2829:                                        if (totalTabHeight > th) {
2830:                                            int dir = scrollbutton
2831:                                                    .scrollsForward() ? SOUTH
2832:                                                    : NORTH;
2833:                                            scrollbutton.setDirection(dir);
2834:                                            visible = true;
2835:                                            bx = (tabPlacement == LEFT ? tx
2836:                                                    + tw - bsize.width : tx);
2837:                                            by = dir == SOUTH ? bounds.height
2838:                                                    - insets.bottom
2839:                                                    - bsize.height
2840:                                                    : bounds.height
2841:                                                            - insets.bottom - 2
2842:                                                            * bsize.height;
2843:                                        }
2844:                                        break;
2845:
2846:                                    case BOTTOM:
2847:                                    case TOP:
2848:                                    default:
2849:                                        int totalTabWidth = rects[tabCount - 1].x
2850:                                                + rects[tabCount - 1].width;
2851:
2852:                                        if (totalTabWidth > tw) {
2853:                                            int dir = scrollbutton
2854:                                                    .scrollsForward() ? EAST
2855:                                                    : WEST;
2856:                                            scrollbutton.setDirection(dir);
2857:                                            visible = true;
2858:                                            bx = dir == EAST ? bounds.width
2859:                                                    - insets.left - bsize.width
2860:                                                    : bounds.width
2861:                                                            - insets.left - 2
2862:                                                            * bsize.width;
2863:                                            by = (tabPlacement == TOP ? ty + th
2864:                                                    - bsize.height : ty);
2865:                                        }
2866:                                    }
2867:                                    child.setVisible(visible);
2868:                                    if (visible) {
2869:                                        child.setBounds(bx, by, bw, bh);
2870:                                    }
2871:
2872:                                } else {
2873:                                    // All content children...
2874:                                    child.setBounds(cx, cy, cw, ch);
2875:                                }
2876:                            }
2877:                            if (shouldChangeFocus) {
2878:                                if (!requestFocusForVisibleComponent()) {
2879:                                    tabPane.requestFocus();
2880:                                }
2881:                            }
2882:                        }
2883:                    }
2884:                }
2885:
2886:                protected void calculateTabRects(int tabPlacement, int tabCount) {
2887:                    FontMetrics metrics = getFontMetrics();
2888:                    Dimension size = tabPane.getSize();
2889:                    Insets insets = tabPane.getInsets();
2890:                    Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
2891:                    int fontHeight = metrics.getHeight();
2892:                    int selectedIndex = tabPane.getSelectedIndex();
2893:                    int i, j;
2894:                    boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT);
2895:                    boolean leftToRight = isLeftToRight(tabPane);
2896:                    int x = tabAreaInsets.left;
2897:                    int y = tabAreaInsets.top;
2898:                    int totalWidth = 0;
2899:                    int totalHeight = 0;
2900:
2901:                    //
2902:                    // Calculate bounds within which a tab run must fit
2903:                    //
2904:                    switch (tabPlacement) {
2905:                    case LEFT:
2906:                    case RIGHT:
2907:                        maxTabWidth = calculateMaxTabWidth(tabPlacement);
2908:                        break;
2909:                    case BOTTOM:
2910:                    case TOP:
2911:                    default:
2912:                        maxTabHeight = calculateMaxTabHeight(tabPlacement);
2913:                    }
2914:
2915:                    runCount = 0;
2916:                    selectedRun = -1;
2917:
2918:                    if (tabCount == 0) {
2919:                        return;
2920:                    }
2921:
2922:                    selectedRun = 0;
2923:                    runCount = 1;
2924:
2925:                    // Run through tabs and lay them out in a single run
2926:                    Rectangle rect;
2927:                    for (i = 0; i < tabCount; i++) {
2928:                        rect = rects[i];
2929:
2930:                        if (!verticalTabRuns) {
2931:                            // Tabs on TOP or BOTTOM....
2932:                            if (i > 0) {
2933:                                rect.x = rects[i - 1].x + rects[i - 1].width;
2934:                            } else {
2935:                                tabRuns[0] = 0;
2936:                                maxTabWidth = 0;
2937:                                totalHeight += maxTabHeight;
2938:                                rect.x = x;
2939:                            }
2940:                            rect.width = calculateTabWidth(tabPlacement, i,
2941:                                    metrics);
2942:                            totalWidth = rect.x + rect.width;
2943:                            maxTabWidth = Math.max(maxTabWidth, rect.width);
2944:
2945:                            rect.y = y;
2946:                            rect.height = maxTabHeight/* - 2*/;
2947:
2948:                        } else {
2949:                            // Tabs on LEFT or RIGHT...
2950:                            if (i > 0) {
2951:                                rect.y = rects[i - 1].y + rects[i - 1].height;
2952:                            } else {
2953:                                tabRuns[0] = 0;
2954:                                maxTabHeight = 0;
2955:                                totalWidth = maxTabWidth;
2956:                                rect.y = y;
2957:                            }
2958:                            rect.height = calculateTabHeight(tabPlacement, i,
2959:                                    fontHeight);
2960:                            totalHeight = rect.y + rect.height;
2961:                            maxTabHeight = Math.max(maxTabHeight, rect.height);
2962:
2963:                            rect.x = x;
2964:                            rect.width = maxTabWidth/* - 2*/;
2965:
2966:                        }
2967:                    }
2968:
2969:                    // for right to left and tab placement on the top or
2970:                    // the bottom, flip x positions and adjust by widths
2971:                    if (!leftToRight && !verticalTabRuns) {
2972:                        int rightMargin = size.width
2973:                                - (insets.right + tabAreaInsets.right);
2974:                        for (i = 0; i < tabCount; i++) {
2975:                            rects[i].x = rightMargin - rects[i].x
2976:                                    - rects[i].width;
2977:                        }
2978:                    }
2979:                    //tabPanel.setSize(totalWidth, totalHeight);
2980:                    tabScroller.tabPanel.setPreferredSize(new Dimension(
2981:                            totalWidth, totalHeight));
2982:                }
2983:            }
2984:
2985:            private class ScrollableTabSupport implements  ChangeListener,
2986:                    ActionListener {
2987:                public ScrollableTabViewport viewport;
2988:                public ScrollableTabPanel tabPanel;
2989:                public ScrollableTabButton scrollForwardButton;
2990:                public ScrollableTabButton scrollBackwardButton;
2991:                public int leadingTabIndex;
2992:
2993:                private Point tabViewPosition = new Point(0, 0);
2994:
2995:                ScrollableTabSupport(int tabPlacement) {
2996:                    viewport = new ScrollableTabViewport();
2997:                    tabPanel = new ScrollableTabPanel();
2998:                    viewport.setView(tabPanel);
2999:                    viewport.addChangeListener(this );
3000:
3001:                    if (tabPlacement == TOP || tabPlacement == BOTTOM) {
3002:                        scrollForwardButton = new ScrollableTabButton(EAST);
3003:                        scrollBackwardButton = new ScrollableTabButton(WEST);
3004:
3005:                    } else { // tabPlacement = LEFT || RIGHT
3006:                        scrollForwardButton = new ScrollableTabButton(SOUTH);
3007:                        scrollBackwardButton = new ScrollableTabButton(NORTH);
3008:                    }
3009:
3010:                    scrollForwardButton.addActionListener(this );
3011:                    scrollBackwardButton.addActionListener(this );
3012:
3013:                }
3014:
3015:                public void actionPerformed(ActionEvent e) {
3016:                    Object object = e.getSource();
3017:                    if (object == scrollForwardButton) {
3018:                        scrollForward(tabPane.getTabPlacement());
3019:                    } else if (object == scrollBackwardButton) {
3020:                        scrollBackward(tabPane.getTabPlacement());
3021:                    }
3022:                }
3023:
3024:                public void scrollForward(int tabPlacement) {
3025:                    Dimension viewSize = viewport.getViewSize();
3026:                    Rectangle viewRect = viewport.getViewRect();
3027:
3028:                    if (tabPlacement == TOP || tabPlacement == BOTTOM) {
3029:                        if (viewRect.width >= viewSize.width - viewRect.x) {
3030:                            return; // no room left to scroll
3031:                        }
3032:                    } else { // tabPlacement == LEFT || tabPlacement == RIGHT
3033:                        if (viewRect.height >= viewSize.height - viewRect.y) {
3034:                            return;
3035:                        }
3036:                    }
3037:                    setLeadingTabIndex(tabPlacement, leadingTabIndex + 1);
3038:                }
3039:
3040:                public void scrollBackward(int tabPlacement) {
3041:                    if (leadingTabIndex == 0) {
3042:                        return; // no room left to scroll
3043:                    }
3044:                    setLeadingTabIndex(tabPlacement, leadingTabIndex - 1);
3045:                }
3046:
3047:                public void setLeadingTabIndex(int tabPlacement, int index) {
3048:                    leadingTabIndex = index;
3049:                    Dimension viewSize = viewport.getViewSize();
3050:                    Rectangle viewRect = viewport.getViewRect();
3051:
3052:                    switch (tabPlacement) {
3053:                    case TOP:
3054:                    case BOTTOM:
3055:                        tabViewPosition.x = leadingTabIndex == 0 ? 0
3056:                                : rects[leadingTabIndex].x;
3057:
3058:                        if ((viewSize.width - tabViewPosition.x) < viewRect.width) {
3059:                            // We've scrolled to the end, so adjust the viewport size
3060:                            // to ensure the view position remains aligned on a tab boundary
3061:                            Dimension extentSize = new Dimension(viewSize.width
3062:                                    - tabViewPosition.x, viewRect.height);
3063:                            viewport.setExtentSize(extentSize);
3064:                        }
3065:                        break;
3066:                    case LEFT:
3067:                    case RIGHT:
3068:                        tabViewPosition.y = leadingTabIndex == 0 ? 0
3069:                                : rects[leadingTabIndex].y;
3070:
3071:                        if ((viewSize.height - tabViewPosition.y) < viewRect.height) {
3072:                            // We've scrolled to the end, so adjust the viewport size
3073:                            // to ensure the view position remains aligned on a tab boundary
3074:                            Dimension extentSize = new Dimension(
3075:                                    viewRect.width, viewSize.height
3076:                                            - tabViewPosition.y);
3077:                            viewport.setExtentSize(extentSize);
3078:                        }
3079:                    }
3080:                    viewport.setViewPosition(tabViewPosition);
3081:                }
3082:
3083:                public void stateChanged(ChangeEvent e) {
3084:                    JViewport viewport = (JViewport) e.getSource();
3085:                    int tabPlacement = tabPane.getTabPlacement();
3086:                    int tabCount = tabPane.getTabCount();
3087:                    Rectangle vpRect = viewport.getBounds();
3088:                    Dimension viewSize = viewport.getViewSize();
3089:                    Rectangle viewRect = viewport.getViewRect();
3090:
3091:                    leadingTabIndex = getClosestTab(viewRect.x, viewRect.y);
3092:
3093:                    // If the tab isn't right aligned, adjust it.
3094:                    if (leadingTabIndex + 1 < tabCount) {
3095:                        switch (tabPlacement) {
3096:                        case TOP:
3097:                        case BOTTOM:
3098:                            if (rects[leadingTabIndex].x < viewRect.x) {
3099:                                leadingTabIndex++;
3100:                            }
3101:                            break;
3102:                        case LEFT:
3103:                        case RIGHT:
3104:                            if (rects[leadingTabIndex].y < viewRect.y) {
3105:                                leadingTabIndex++;
3106:                            }
3107:                            break;
3108:                        }
3109:                    }
3110:                    Insets contentInsets = getContentBorderInsets(tabPlacement);
3111:                    switch (tabPlacement) {
3112:                    case LEFT:
3113:                        tabPane.repaint(vpRect.x + vpRect.width, vpRect.y,
3114:                                contentInsets.left, vpRect.height);
3115:                        scrollBackwardButton.setEnabled(viewRect.y > 0);
3116:                        scrollForwardButton
3117:                                .setEnabled(leadingTabIndex < tabCount - 1
3118:                                        && viewSize.height - viewRect.y > viewRect.height);
3119:                        break;
3120:                    case RIGHT:
3121:                        tabPane.repaint(vpRect.x - contentInsets.right,
3122:                                vpRect.y, contentInsets.right, vpRect.height);
3123:                        scrollBackwardButton.setEnabled(viewRect.y > 0);
3124:                        scrollForwardButton
3125:                                .setEnabled(leadingTabIndex < tabCount - 1
3126:                                        && viewSize.height - viewRect.y > viewRect.height);
3127:                        break;
3128:                    case BOTTOM:
3129:                        tabPane.repaint(vpRect.x, vpRect.y
3130:                                - contentInsets.bottom, vpRect.width,
3131:                                contentInsets.bottom);
3132:                        scrollBackwardButton.setEnabled(viewRect.x > 0);
3133:                        scrollForwardButton
3134:                                .setEnabled(leadingTabIndex < tabCount - 1
3135:                                        && viewSize.width - viewRect.x > viewRect.width);
3136:                        break;
3137:                    case TOP:
3138:                    default:
3139:                        tabPane.repaint(vpRect.x, vpRect.y + vpRect.height,
3140:                                vpRect.width, contentInsets.top);
3141:                        scrollBackwardButton.setEnabled(viewRect.x > 0);
3142:                        scrollForwardButton
3143:                                .setEnabled(leadingTabIndex < tabCount - 1
3144:                                        && viewSize.width - viewRect.x > viewRect.width);
3145:                    }
3146:                }
3147:
3148:                public String toString() {
3149:                    return new String("viewport.viewSize="
3150:                            + viewport.getViewSize() + "\n"
3151:                            + "viewport.viewRectangle="
3152:                            + viewport.getViewRect() + "\n"
3153:                            + "leadingTabIndex=" + leadingTabIndex + "\n"
3154:                            + "tabViewPosition=" + tabViewPosition);
3155:                }
3156:
3157:            }
3158:
3159:            private class ScrollableTabViewport extends JViewport implements 
3160:                    UIResource {
3161:                public ScrollableTabViewport() {
3162:                    super ();
3163:                    setScrollMode(SIMPLE_SCROLL_MODE);
3164:                }
3165:            } // class ScrollableTabViewport
3166:
3167:            private class ScrollableTabPanel extends JPanel implements 
3168:                    UIResource {
3169:                public ScrollableTabPanel() {
3170:                    setLayout(null);
3171:                }
3172:
3173:                public void paintComponent(Graphics g) {
3174:                    super .paintComponent(g);
3175:                    FlatTabbedPaneUI.this .paintTabArea(g, tabPane
3176:                            .getTabPlacement(), tabPane.getSelectedIndex());
3177:
3178:                }
3179:            } // class ScrollableTabPanel
3180:
3181:            private class ScrollableTabButton extends BasicArrowButton
3182:                    implements  UIResource, SwingConstants, MouseListener {
3183:                private boolean mouseOver = false;
3184:
3185:                public ScrollableTabButton(int direction) {
3186:                    super (direction);
3187:                    addMouseListener(this );
3188:                }
3189:
3190:                public boolean scrollsForward() {
3191:                    return direction == EAST || direction == SOUTH;
3192:                }
3193:
3194:                public void mouseEntered(MouseEvent e) {
3195:                    mouseOver = true;
3196:                    repaint();
3197:                }
3198:
3199:                public void mouseExited(MouseEvent e) {
3200:                    mouseOver = false;
3201:                    repaint();
3202:                }
3203:
3204:                public void mouseClicked(MouseEvent e) {
3205:                }
3206:
3207:                public void mousePressed(MouseEvent e) {
3208:                }
3209:
3210:                public void mouseReleased(MouseEvent e) {
3211:                }
3212:
3213:                public boolean isMouseOver() {
3214:                    return mouseOver;
3215:                }
3216:
3217:                public void setMouseOver(boolean _mouseOver) {
3218:                    mouseOver = _mouseOver;
3219:                }
3220:
3221:                public void paint(Graphics g) {
3222:                    Color origColor;
3223:                    boolean isPressed, isEnabled;
3224:                    int w, h, size;
3225:
3226:                    w = getSize().width;
3227:                    h = getSize().height;
3228:                    origColor = g.getColor();
3229:                    isPressed = getModel().isPressed();
3230:                    isEnabled = isEnabled();
3231:
3232:                    g.setColor(getBackground());
3233:                    g.fillRect(0, 0, w, h);
3234:
3235:                    if (mouseOver && isEnabled) {
3236:                        g.setColor(Color.DARK_GRAY);
3237:                        g.drawRect(1, 1, w - 2, h - 2);
3238:                    }
3239:
3240:                    // If there's no room to draw arrow, bail
3241:                    if (h < 5 || w < 5) {
3242:                        g.setColor(origColor);
3243:                        return;
3244:                    }
3245:
3246:                    g.translate(1, 1);
3247:
3248:                    // Draw the arrow
3249:                    size = Math.min((h - 4) / 3, (w - 4) / 3);
3250:                    size = Math.max(size, 2);
3251:
3252:                    paintTriangle(g, (w - size) / 2, (h - size) / 2, size,
3253:                            direction, isEnabled);
3254:
3255:                    // Reset the Graphics back to it's original settings
3256:                    g.translate(-1, -1);
3257:                    g.setColor(origColor);
3258:
3259:                }
3260:
3261:                public void paintTriangle(Graphics g, int x, int y, int size,
3262:                        int direction, boolean isEnabled) {
3263:
3264:                    Color oldColor = g.getColor();
3265:                    int mid, i, j;
3266:
3267:                    j = 0;
3268:                    size = Math.max(size, 2);
3269:                    mid = (size / 2) - 1;
3270:
3271:                    g.translate(x, y);
3272:
3273:                    if (isEnabled)
3274:                        g.setColor(darkShadow);
3275:                    else
3276:                        g.setColor(shadow);
3277:
3278:                    switch (direction) {
3279:                    case NORTH:
3280:                        for (i = 0; i < size; i++) {
3281:                            g.drawLine(mid - i, i, mid + i, i);
3282:                        }
3283:                        break;
3284:                    case SOUTH:
3285:                        j = 0;
3286:                        for (i = size - 1; i >= 0; i--) {
3287:                            g.drawLine(mid - i, j, mid + i, j);
3288:                            j++;
3289:                        }
3290:                        break;
3291:                    case WEST:
3292:                        for (i = 0; i < size; i++) {
3293:                            g.drawLine(i, mid - i, i, mid + i);
3294:                        }
3295:                        break;
3296:                    case EAST:
3297:                        j = 0;
3298:                        for (i = size - 1; i >= 0; i--) {
3299:                            g.drawLine(j, mid - i, j, mid + i);
3300:                            j++;
3301:                        }
3302:                        break;
3303:                    }
3304:                    g.translate(-x, -y);
3305:                    g.setColor(oldColor);
3306:                }
3307:
3308:            } // class ScrollableTabButton
3309:
3310:            // Controller: event listeners
3311:
3312:            /**
3313:             * This inner class is marked &quot;public&quot; due to a compiler bug.
3314:             * This class should be treated as a &quot;protected&quot; inner class.
3315:             * Instantiate it only within subclasses of FlatTabbedPaneUI.
3316:             */
3317:            public class PropertyChangeHandler implements 
3318:                    PropertyChangeListener {
3319:                public void propertyChange(PropertyChangeEvent e) {
3320:                    JTabbedPane pane = (JTabbedPane) e.getSource();
3321:                    String name = e.getPropertyName();
3322:
3323:                    if ("mnemonicAt".equals(name)) {
3324:                        updateMnemonics();
3325:                        pane.repaint();
3326:                    } else if ("displayedMnemonicIndexAt".equals(name)) {
3327:                        pane.repaint();
3328:                    } else if (name.equals("indexForTitle")) {
3329:                        int index = ((Integer) e.getNewValue()).intValue();
3330:                        String title = tabPane.getTitleAt(index);
3331:                        if (BasicHTML.isHTMLString(title)) {
3332:                            if (htmlViews == null) { // Initialize vector
3333:                                htmlViews = createHTMLVector();
3334:                            } else { // Vector already exists
3335:                                View v = BasicHTML.createHTMLView(tabPane,
3336:                                        title);
3337:                                htmlViews.setElementAt(v, index);
3338:                            }
3339:                        } else {
3340:                            if (htmlViews != null
3341:                                    && htmlViews.elementAt(index) != null) {
3342:                                htmlViews.setElementAt(null, index);
3343:                            }
3344:                        }
3345:                        updateMnemonics();
3346:                    } else if (name.equals("tabLayoutPolicy")) {
3347:                        FlatTabbedPaneUI.this .uninstallUI(pane);
3348:                        FlatTabbedPaneUI.this .installUI(pane);
3349:                    }
3350:                }
3351:            }
3352:
3353:            /**
3354:             * This inner class is marked &quot;public&quot; due to a compiler bug.
3355:             * This class should be treated as a &quot;protected&quot; inner class.
3356:             * Instantiate it only within subclasses of FlatTabbedPaneUI.
3357:             */
3358:            public class TabSelectionHandler implements  ChangeListener {
3359:                public void stateChanged(ChangeEvent e) {
3360:                    JTabbedPane tabPane = (JTabbedPane) e.getSource();
3361:                    tabPane.revalidate();
3362:                    tabPane.repaint();
3363:
3364:                    if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) {
3365:                        int index = tabPane.getSelectedIndex();
3366:                        if (index < rects.length && index != -1) {
3367:                            tabScroller.tabPanel
3368:                                    .scrollRectToVisible(rects[index]);
3369:                        }
3370:                    }
3371:                }
3372:            }
3373:
3374:            /**
3375:             * This inner class is marked &quot;public&quot; due to a compiler bug.
3376:             * This class should be treated as a &quot;protected&quot; inner class.
3377:             * Instantiate it only within subclasses of FlatTabbedPaneUI.
3378:             */
3379:            public class MouseHandler extends MouseAdapter {
3380:                public void mousePressed(MouseEvent e) {
3381:                    if (!tabPane.isEnabled()) {
3382:                        return;
3383:                    }
3384:                    int tabIndex = getTabAtLocation(e.getX(), e.getY());
3385:                    if (tabIndex >= 0 && tabPane.isEnabledAt(tabIndex)) {
3386:                        if (tabIndex == tabPane.getSelectedIndex()) {
3387:                            if (tabPane.isRequestFocusEnabled()) {
3388:                                tabPane.requestFocus();
3389:                                tabPane
3390:                                        .repaint(getTabBounds(tabPane, tabIndex));
3391:                            }
3392:                        } else {
3393:                            tabPane.setSelectedIndex(tabIndex);
3394:                        }
3395:                    }
3396:                }
3397:            }
3398:
3399:            /**
3400:             * This inner class is marked &quot;public&quot; due to a compiler bug.
3401:             * This class should be treated as a &quot;protected&quot; inner class.
3402:             * Instantiate it only within subclasses of FlatTabbedPaneUI.
3403:             */
3404:            public class FocusHandler extends FocusAdapter {
3405:                public void focusGained(FocusEvent e) {
3406:                    JTabbedPane tabPane = (JTabbedPane) e.getSource();
3407:                    int tabCount = tabPane.getTabCount();
3408:                    int selectedIndex = tabPane.getSelectedIndex();
3409:                    if (selectedIndex != -1 && tabCount > 0
3410:                            && tabCount == rects.length) {
3411:                        tabPane.repaint(getTabBounds(tabPane, selectedIndex));
3412:                    }
3413:                }
3414:
3415:                public void focusLost(FocusEvent e) {
3416:                    JTabbedPane tabPane = (JTabbedPane) e.getSource();
3417:                    int tabCount = tabPane.getTabCount();
3418:                    int selectedIndex = tabPane.getSelectedIndex();
3419:                    if (selectedIndex != -1 && tabCount > 0
3420:                            && tabCount == rects.length) {
3421:                        tabPane.repaint(getTabBounds(tabPane, selectedIndex));
3422:                    }
3423:                }
3424:            }
3425:
3426:            /* GES 2/3/99:
3427:               The container listener code was added to support HTML
3428:               rendering of tab titles.
3429:             
3430:               Ideally, we would be able to listen for property changes
3431:               when a tab is added or its text modified.  At the moment
3432:               there are no such events because the Beans spec doesn't
3433:               allow 'indexed' property changes (i.e. tab 2's text changed
3434:               from A to B).
3435:             
3436:               In order to get around this, we listen for tabs to be added
3437:               or removed by listening for the container events.  we then
3438:               queue up a runnable (so the component has a chance to complete
3439:               the add) which checks the tab title of the new component to see
3440:               if it requires HTML rendering.
3441:             
3442:               The Views (one per tab title requiring HTML rendering) are
3443:               stored in the htmlViews Vector, which is only allocated after
3444:               the first time we run into an HTML tab.  Note that this vector
3445:               is kept in step with the number of pages, and nulls are added
3446:               for those pages whose tab title do not require HTML rendering.
3447:             
3448:               This makes it easy for the paint and layout code to tell
3449:               whether to invoke the HTML engine without having to check
3450:               the string during time-sensitive operations.
3451:             
3452:               When we have added a way to listen for tab additions and
3453:               changes to tab text, this code should be removed and
3454:               replaced by something which uses that.  */
3455:
3456:            private class ContainerHandler implements  ContainerListener {
3457:                public void componentAdded(ContainerEvent e) {
3458:                    JTabbedPane tp = (JTabbedPane) e.getContainer();
3459:                    Component child = e.getChild();
3460:                    if (child instanceof  UIResource) {
3461:                        return;
3462:                    }
3463:                    int index = tp.indexOfComponent(child);
3464:                    String title = tp.getTitleAt(index);
3465:                    boolean isHTML = BasicHTML.isHTMLString(title);
3466:                    if (isHTML) {
3467:                        if (htmlViews == null) { // Initialize vector
3468:                            htmlViews = createHTMLVector();
3469:                        } else { // Vector already exists
3470:                            View v = BasicHTML.createHTMLView(tp, title);
3471:                            htmlViews.insertElementAt(v, index);
3472:                        }
3473:                    } else { // Not HTML
3474:                        if (htmlViews != null) { // Add placeholder
3475:                            htmlViews.insertElementAt(null, index);
3476:                        } // nada!
3477:                    }
3478:                }
3479:
3480:                public void componentRemoved(ContainerEvent e) {
3481:                    JTabbedPane tp = (JTabbedPane) e.getContainer();
3482:                    Component child = e.getChild();
3483:                    if (child instanceof  UIResource) {
3484:                        return;
3485:                    }
3486:
3487:                    // NOTE 4/15/2002 (joutwate):
3488:                    // This fix is implemented using client properties since there is
3489:                    // currently no IndexPropertyChangeEvent.  Once
3490:                    // IndexPropertyChangeEvents have been added this code should be
3491:                    // modified to use it.
3492:                    Integer indexObj = (Integer) tp
3493:                            .getClientProperty("__index_to_remove__");
3494:                    if (indexObj != null) {
3495:                        int index = indexObj.intValue();
3496:                        if (htmlViews != null && htmlViews.size() >= index) {
3497:                            htmlViews.removeElementAt(index);
3498:                        }
3499:                    }
3500:                }
3501:            }
3502:
3503:            private Vector createHTMLVector() {
3504:                Vector htmlViews = new Vector();
3505:                int count = tabPane.getTabCount();
3506:                if (count > 0) {
3507:                    for (int i = 0; i < count; i++) {
3508:                        String title = tabPane.getTitleAt(i);
3509:                        if (BasicHTML.isHTMLString(title)) {
3510:                            htmlViews.addElement(BasicHTML.createHTMLView(
3511:                                    tabPane, title));
3512:                        } else {
3513:                            htmlViews.addElement(null);
3514:                        }
3515:                    }
3516:                }
3517:                return htmlViews;
3518:            }
3519:
3520:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.