Source Code Cross Referenced for TabState.java in  » IDE-Netbeans » library » org » netbeans » swing » tabcontrol » 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 » IDE Netbeans » library » org.netbeans.swing.tabcontrol.plaf 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:        package org.netbeans.swing.tabcontrol.plaf;
0042:
0043:        import java.awt.event.ActionEvent;
0044:        import java.awt.event.ActionListener;
0045:        import java.util.ArrayList;
0046:        import java.util.Arrays;
0047:        import java.util.HashSet;
0048:        import java.util.Iterator;
0049:        import java.util.List;
0050:        import java.util.Set;
0051:        import javax.swing.Timer;
0052:        import javax.swing.event.ListDataEvent;
0053:        import org.netbeans.swing.tabcontrol.TabData;
0054:        import org.netbeans.swing.tabcontrol.event.ArrayDiff;
0055:        import org.netbeans.swing.tabcontrol.event.ComplexListDataEvent;
0056:        import org.netbeans.swing.tabcontrol.event.VeryComplexListDataEvent;
0057:        import org.openide.util.Utilities;
0058:
0059:        /**
0060:         * Used by BasicTabDisplayerUI and its subclasses.
0061:         * Tracks and manages the state of tabs, mainly which one currently contains the
0062:         * mouse, if the mouse is in the close button, if the tab is adjacent to a
0063:         * selected tab, if it is leftmost, rightmost, active, etc. This class hides
0064:         * most of the complexity of deciding what mouse events should trigger a repaint
0065:         * of what areas in an optimized way.  It provides setters which a mouse
0066:         * listener can call to indicate that the mouse has, say, moved into a tab, or
0067:         * from one tab to another, or the selection has changed, etc.
0068:         * <p>
0069:         * Essentially, this class is fed indices of tabs that have various states (selected,
0070:         * contains mouse, etc.), figures out if this affects one tab, two tabs (a different
0071:         * tab had the state, such as the mouse moving from one tab to another) or all tabs (activated).  It determines
0072:         * a change type, and consults a <i>repaint policy</i> (an integer bitmask) to decide
0073:         * if one, both, all or no tabs should be repainted.
0074:         * <p>
0075:         * The typical use case is to implement a subclass, and override getState() to
0076:         * mix in bitmasks for things like whether a tab is clipped, etc. - things the
0077:         * base implementation can't know about.
0078:         *
0079:         * <p>
0080:         * Subclasses implement the <code>repaintTab()</code> method to do the actual
0081:         * repainting, and implement <code>getRepaintPolicy()</code>.  The repainting will be
0082:         * called if an event happens that changes the state in a way that the repaint policy
0083:         * bitmask indicates should cause a repaint.
0084:         * <p>
0085:         * BasicTabDisplayerUI implements a mouse listener which will call the appropriate
0086:         * methods when the mouse enters/exits tabs, etc.
0087:         * <h4>Details</h4>
0088:         * <p>
0089:         * State is composed as an integer bitmask which covers all of the supported
0090:         * states of a tab that may affect the way they paint.  These are also the values that
0091:         * are passed to the methods of a <code>TabCellRenderer</code> to tell it how to
0092:         * paint itself. Two other integer
0093:         * bitmasks are used:  The <code>changeType</code>, which indicates whether a
0094:         * change was from one tab to another tab, one tab to no tab (i.e. selection set
0095:         * to -1), one tab to the same tab (i.e. the mouse moved out of the tab control,
0096:         * and so the tab with the mouse in it is now no tab).  RepaintPolicy is an integer
0097:         * bitmask composed of conditions under which the control should repaint one or all
0098:         * tabs, and determines what types of changes actually trigger repaints.
0099:         * <p>
0100:         * Subclasses are expected to override <code>getState()</code> to provide
0101:         * information about non-mouse-or-focus related states, such as clipping of
0102:         * scrollable tabs.  Predefined states for tabs are: CLIP_RIGHT, CLIP_LEFT,
0103:         * ARMED, PRESSED, SELECTED, ACTIVE, NOT_ONSCREEN, LEFTMOST, RIGHTMOST,
0104:         * CLOSE_BUTTON_ARMED, BEFORE_SELECTED, AFTER_SELECTED, MOUSE_IN_TABS_AREA,
0105:         * MOUSE_PRESSED_IN_CLOSE_BUTTON. Subclasses must handle returning the following
0106:         * states if they wish to, which are not handled directly in TabState: LEFTMOST,
0107:         * RIGHTMOST, CLIP_LEFT, CLIP_RIGHT, NOT_ONSCREEN.
0108:         * <p>
0109:         * Most of the states are fairly self-explanatory; NOT_ONSCREEN is useful as an
0110:         * optimization so that no work is done for events that would try to produce a
0111:         * repaint for something not visible; CLIP_* refers to the case in scrollable
0112:         * tab UIs, in which a tab may only be partially visible;
0113:         * MOUSE_PRESSED_IN_CLOSE_BUTTON is distinct because the CLOSE_BUTTON_ARMED
0114:         * state will be reset if the mouse moves out of the close button area, but UIs
0115:         * should perform a close action if the mouse was pressed over the close button,
0116:         * moved away from the close button and then back to it, so this state preserves
0117:         * the information that the originating location of a mouse press was in the
0118:         * close button.
0119:         */
0120:        public abstract class TabState {
0121:
0122:            /**
0123:             * Bitmask for state of tabs clipped on the right side - that is, partially
0124:             * displayed
0125:             */
0126:            public static final int CLIP_RIGHT = 1;
0127:            /**
0128:             * Bitmask for state of tabs clipped on the right side - that is, partially
0129:             * displayed
0130:             */
0131:            public static final int CLIP_LEFT = 2;
0132:            /**
0133:             * Bitmask indicating the tab contains the mouse
0134:             */
0135:            public static final int ARMED = 4;
0136:            /**
0137:             * Bitmask indicating the tab contains the mouse and the mouse button has
0138:             * been pressed
0139:             */
0140:            public static final int PRESSED = 8;
0141:            /**
0142:             * Bitmask indicating the tab is selected
0143:             */
0144:            public static final int SELECTED = 16;
0145:            /**
0146:             * Bitmask indicating the tab is activated
0147:             */
0148:            public static final int ACTIVE = 32;
0149:            /**
0150:             * State bitmask indicating a tab is not displayed at all and shouldn't be
0151:             * painted. Implementations may more simply avoid not painting a tab by not
0152:             * including it in the range returned by getFirstVisibleTab()/getLastVisibleTab().
0153:             * This state exists so that implementations have the option of returning
0154:             * the entire range of tabs as visible and determining if one is truly
0155:             * visble or not in getTabState() - sometimes doing it this way will be less
0156:             * expensive.
0157:             */
0158:            public static final int NOT_ONSCREEN = 64;
0159:            /**
0160:             * Bitmask indicating the tab is at the extreme left and
0161:             * <strong>not</strong> clipped
0162:             */
0163:            public static final int LEFTMOST = 128;
0164:            /**
0165:             * Bitmask indicating the tab is at the extreme right and
0166:             * <strong>not</strong> clipped
0167:             */
0168:            public static final int RIGHTMOST = 256;
0169:            /**
0170:             * Bitmask indicating that the tab contains the mouse and the mouse is in
0171:             * the close button
0172:             */
0173:            public static final int CLOSE_BUTTON_ARMED = 512;
0174:            /**
0175:             * Bitmask indicating that the tab's index is that of the selected index
0176:             * less one
0177:             */
0178:            public static final int BEFORE_SELECTED = 1024;
0179:            /**
0180:             * Bitmask indicating that the tab's index is that of the selected index
0181:             * plus one
0182:             */
0183:            public static final int AFTER_SELECTED = 2048;
0184:            /**
0185:             * Bitmask indicating that the mouse is in the tabs area
0186:             */
0187:            public static final int MOUSE_IN_TABS_AREA = 4096;
0188:
0189:            /**
0190:             * Bitmask indicating that the mouse is inside the close button and has 
0191:             * been pressed.
0192:             */
0193:            public static final int MOUSE_PRESSED_IN_CLOSE_BUTTON = 8192;
0194:
0195:            /**
0196:             * Bitmask indicating that the tab is in "attention" mode - blinking or
0197:             * flashing to get the user's attention.
0198:             */
0199:            public static final int ATTENTION = 16384;
0200:
0201:            /**
0202:             * Bitmask indicating that the tab's index is that of the armed index
0203:             * less one
0204:             */
0205:            public static final int BEFORE_ARMED = 32768;
0206:
0207:            /**
0208:             * Indicates the last constant defined - renderers that wish to add their
0209:             * own bitmasks should use multiples of this number
0210:             */
0211:            public static int STATE_LAST = MOUSE_PRESSED_IN_CLOSE_BUTTON;
0212:
0213:            private int pressedIndex = -1;
0214:            private int containsMouseIndex = -1;
0215:            private int closeButtonContainsMouseIndex = -1;
0216:            private int mousePressedInCloseButtonIndex = -1;
0217:            private boolean mouseInTabsArea = false;
0218:            private boolean active = false;
0219:            private int selectedIndex = -1;
0220:
0221:            private int prev = -1;
0222:            private int curr = -1;
0223:            private int lastChangeType = NO_CHANGE;
0224:            private int lastAffected = 0;
0225:            private int lastChange = 0;
0226:
0227:            /** Repaint policy bitmask indicating that a tab should be repainted whenever the mouse enters or exits it */
0228:            public static final int REPAINT_ON_MOUSE_ENTER_TAB = 1;
0229:            /** Repaint policy bitmask indicating that all tabs should be repainted whenever the mouse enters or leaves the
0230:             * area in which tabs are painted */
0231:            public static final int REPAINT_ALL_ON_MOUSE_ENTER_TABS_AREA = 3;
0232:            /** Repaint policy bitmask indicating that the tab should be repainted when the mouse enters or exits the close
0233:             * button region */
0234:            public static final int REPAINT_ON_MOUSE_ENTER_CLOSE_BUTTON = 4;
0235:            /** Repaint policy bitmask indicating that the tab should be repainted on mouse pressed events */
0236:            public static final int REPAINT_ON_MOUSE_PRESSED = 8;
0237:            /** Repaint policy bitmask indicating that the selected tab should be repainted when the activated state changes */
0238:            public static final int REPAINT_SELECTION_ON_ACTIVATION_CHANGE = 16;
0239:            /** Repaint policy bitmask indicating that all tabs should be repainted when the activated state changes */
0240:            public static final int REPAINT_ALL_TABS_ON_ACTIVATION_CHANGE = 32; //includes selection
0241:            /** Repaint policy bitmask indicating that a tab should be repainted when it becomes selected/unselected */
0242:            public static final int REPAINT_ON_SELECTION_CHANGE = 64;
0243:            /** Repaint policy bitmask indicating that all tabs should be repainted whenever the selection changes */
0244:            public static final int REPAINT_ALL_TABS_ON_SELECTION_CHANGE = 128;
0245:            /** Repaint policy bitmask indicating that the tab should be repainted when the close button is pressed */
0246:            public static final int REPAINT_ON_CLOSE_BUTTON_PRESSED = 256;
0247:
0248:            /**
0249:             * Get the state of a given tab.  Subclasses are expected to override this
0250:             * to provide information about states such as clipping which can only be
0251:             * found out via layout information, such as LEFTMOST, RIGHTMOST, CLIP_LEFT
0252:             * and CLIP_RIGHT.  The state is used by tab renderers to determine how they
0253:             * should paint themselves.
0254:             *
0255:             * @param tab The index of the tab
0256:             * @return The state
0257:             */
0258:            public int getState(int tab) {
0259:                int result = 0;
0260:                if (tab == pressedIndex) {
0261:                    result |= PRESSED;
0262:                }
0263:                if (tab == containsMouseIndex) {
0264:                    result |= ARMED;
0265:                }
0266:                if (tab == closeButtonContainsMouseIndex) {
0267:                    result |= CLOSE_BUTTON_ARMED;
0268:                }
0269:                if (tab == mousePressedInCloseButtonIndex) {
0270:                    result |= MOUSE_PRESSED_IN_CLOSE_BUTTON;
0271:                }
0272:                if (mouseInTabsArea) {
0273:                    result |= MOUSE_IN_TABS_AREA;
0274:                }
0275:                if (active) {
0276:                    result |= ACTIVE;
0277:                }
0278:                if (tab == selectedIndex) {
0279:                    result |= SELECTED;
0280:                }
0281:                if (tab != 0 && tab == selectedIndex + 1) {
0282:                    result |= AFTER_SELECTED;
0283:                }
0284:                if (tab == selectedIndex - 1) {
0285:                    result |= BEFORE_SELECTED;
0286:                }
0287:                if (tab == containsMouseIndex - 1) {
0288:                    result |= BEFORE_ARMED;
0289:                }
0290:                if (isAlarmTab(tab)) {
0291:                    result |= ATTENTION;
0292:                }
0293:                return result;
0294:            }
0295:
0296:            /** For debugging, enables fetching tab state as a string */
0297:            String getStateString(int tab) {
0298:                return stateToString(getState(tab));
0299:            }
0300:
0301:            /**
0302:             * Clear all mouse position related state information.  This should be done
0303:             * following events in the model that alter the state sufficiently that the
0304:             * cached information is probably wrong.
0305:             */
0306:            public void clearTransientStates() {
0307:                pressedIndex = -1;
0308:                containsMouseIndex = -1;
0309:                closeButtonContainsMouseIndex = -1;
0310:                mousePressedInCloseButtonIndex = -1;
0311:                mouseInTabsArea = false;
0312:                lastChangeType = NO_CHANGE;
0313:                lastChange = 0;
0314:                prev = -1;
0315:                curr = -1;
0316:            }
0317:
0318:            /**
0319:             * Set the index of the tab over which a mouse button has been pressed.
0320:             *
0321:             * @param i The tab which is pressed, or -1 to clear PRESSED from the state
0322:             *          of the previously pressed tab
0323:             * @return Index of the tab which previously had the state PRESSED, or -1
0324:             */
0325:            public final int setPressed(int i) {
0326:                prev = pressedIndex;
0327:                pressedIndex = i;
0328:                curr = i;
0329:                possibleChange(prev, curr, PRESSED);
0330:                return prev;
0331:            }
0332:
0333:            /**
0334:             * Set the index of the tab which currently contains the mouse cursor.
0335:             *
0336:             * @param i The tab which contains the mouse cursor, or -1 to clear ARMED
0337:             *          from the state of the tab
0338:             * @return Index of the tab which previously had the state ARMED, or -1
0339:             */
0340:            public final int setContainsMouse(int i) {
0341:                prev = containsMouseIndex;
0342:                containsMouseIndex = i;
0343:                curr = i;
0344:                possibleChange(prev, curr, ARMED);
0345:                return prev;
0346:            }
0347:
0348:            /**
0349:             * Set the index of the tab whose close button contains the mouse cursor.
0350:             *
0351:             * @param i The index of the tab whose close button contains the mouse
0352:             *          cursor, or -1 to clear CLOSE_BUTTON_CONTAINS_MOUSE from the
0353:             *          state of the tab which previously had it
0354:             * @return Index of the tab which formerly had the state
0355:             *         CLOSE_BUTTON_CONTAINS_MOUSE, or -1
0356:             */
0357:            public final int setCloseButtonContainsMouse(int i) {
0358:                prev = closeButtonContainsMouseIndex;
0359:                closeButtonContainsMouseIndex = i;
0360:                curr = i;
0361:                possibleChange(prev, curr, CLOSE_BUTTON_ARMED);
0362:                return prev;
0363:            }
0364:
0365:            /**
0366:             * Set the index of the tab in which the mouse button has been pressed in
0367:             * the close button.  This is distinct from the combination of
0368:             * CLOSE_BUTTON_ARMED and PRESSED, since the user may press the close button
0369:             * and then drag away from the close button (clearing the CLOSE_BUTTON_ARMED
0370:             * state) to abort closing a tab.
0371:             *
0372:             * @param i The tab in which the mouse was pressed while over the close
0373:             *          button
0374:             * @return Index of the tab which previously had the state
0375:             *         MOUSE_PRESSED_IN_CLOSE_BUTTON, or -1
0376:             */
0377:            public final int setMousePressedInCloseButton(int i) {
0378:                prev = mousePressedInCloseButtonIndex;
0379:                mousePressedInCloseButtonIndex = i;
0380:                curr = i;
0381:                possibleChange(prev, curr, MOUSE_PRESSED_IN_CLOSE_BUTTON);
0382:                return prev;
0383:            }
0384:
0385:            /**
0386:             * Set the index of the tab which is currently selected. Note that users of
0387:             * this class must ensure that this value stays up to date when changes
0388:             * occur in the model such as inserting tabs before the selected one.
0389:             *
0390:             * @param i The tab index which is selected
0391:             * @return Index of the tab which previously was selected, or -1 if none
0392:             */
0393:            public final int setSelected(int i) {
0394:                prev = selectedIndex;
0395:                selectedIndex = i;
0396:                curr = i;
0397:                removeAlarmTab(i);
0398:                possibleChange(prev, curr, SELECTED);
0399:                return prev;
0400:            }
0401:
0402:            /**
0403:             * Set the condition for all tabs of the mouse being in the tabs area.
0404:             *
0405:             * @param b Whether the mouse is in the tabs area or not
0406:             * @return The previous state with regard to the mouse being in the tabs
0407:             *         area
0408:             */
0409:            public final boolean setMouseInTabsArea(boolean b) {
0410:                boolean prev = mouseInTabsArea;
0411:                mouseInTabsArea = b;
0412:                possibleChange(prev, b, MOUSE_IN_TABS_AREA);
0413:                return prev;
0414:            }
0415:
0416:            /**
0417:             * Set the condition for all tabs of the component being activated.
0418:             *
0419:             * @param b Whether or not the component is activated
0420:             * @return The previous state with regard to the component being activated
0421:             */
0422:            public final boolean setActive(boolean b) {
0423:                boolean prev = active;
0424:                active = b;
0425:                possibleChange(prev, b, ACTIVE);
0426:                removeAlarmTab(selectedIndex);
0427:                return prev;
0428:            }
0429:
0430:            private boolean isAlarmTab(int tab) {
0431:                return attentionToggle && alarmTabs.contains(new Integer(tab));
0432:            }
0433:
0434:            private final HashSet<Integer> alarmTabs = new HashSet<Integer>(6);
0435:
0436:            /** Add a tab to the list of those which should "flash" or otherwise give
0437:             * some notification to the user to get their attention */
0438:            public final void addAlarmTab(int alarmTab) {
0439:                Integer in = new Integer(alarmTab);
0440:                boolean added = alarmTabs.contains(in);
0441:                boolean wasEmpty = alarmTabs.isEmpty();
0442:                if (!added) {
0443:                    alarmTabs.add(new Integer(alarmTab));
0444:                    repaintTab(alarmTab);
0445:                }
0446:                if (wasEmpty) {
0447:                    startAlarmTimer();
0448:                    attentionToggle = true;
0449:                    repaintTab(alarmTab);
0450:                }
0451:            }
0452:
0453:            /** Remove a tab to the list of those which should "flash" or otherwise give
0454:             * some notification to the user to get their attention */
0455:            public final void removeAlarmTab(int alarmTab) {
0456:                Integer in = new Integer(alarmTab);
0457:                boolean contained = alarmTabs.contains(in);
0458:                if (contained) {
0459:                    alarmTabs.remove(in);
0460:                    boolean empty = alarmTabs.isEmpty();
0461:                    boolean wasAttentionToggled = attentionToggle;
0462:                    if (alarmTabs.isEmpty()) {
0463:                        stopAlarmTimer();
0464:                    }
0465:                    if (wasAttentionToggled) {
0466:                        repaintTab(alarmTab);
0467:                    }
0468:                }
0469:            }
0470:
0471:            private Timer alarmTimer = null;
0472:            private boolean attentionToggle = false;
0473:
0474:            private final void startAlarmTimer() {
0475:                if (alarmTimer == null) {
0476:                    ActionListener al = new ActionListener() {
0477:                        public void actionPerformed(ActionEvent ae) {
0478:                            attentionToggle = !attentionToggle;
0479:                            Timer timer = (Timer) ae.getSource();
0480:                            for (Iterator i = alarmTabs.iterator(); i.hasNext();) {
0481:                                repaintTab(((Integer) i.next()).intValue());
0482:                            }
0483:                        }
0484:                    };
0485:                    alarmTimer = new Timer(700, al);
0486:                    alarmTimer.setRepeats(true);
0487:                }
0488:                alarmTimer.start();
0489:            }
0490:
0491:            private final void stopAlarmTimer() {
0492:                if (alarmTimer != null && alarmTimer.isRunning()) {
0493:                    alarmTimer.stop();
0494:                    attentionToggle = false;
0495:                    repaintAllTabs(); //XXX optimize
0496:                }
0497:            }
0498:
0499:            boolean hasAlarmTabs() {
0500:                return alarmTabs != null && !alarmTabs.isEmpty();
0501:            }
0502:
0503:            void pruneAlarmTabs(int max) {
0504:                if (!hasAlarmTabs()) {
0505:                    return;
0506:                }
0507:                for (Iterator i = alarmTabs.iterator(); i.hasNext();) {
0508:                    if (((Integer) i.next()).intValue() >= max) {
0509:                        i.remove();
0510:                    }
0511:                }
0512:                if (alarmTabs.isEmpty()) {
0513:                    stopAlarmTimer();
0514:                }
0515:            }
0516:
0517:            int[] getAlarmTabs() {
0518:                int[] alarms = (int[]) Utilities
0519:                        .toPrimitiveArray((Integer[]) alarmTabs
0520:                                .toArray(new Integer[0]));
0521:                Arrays.sort(alarms);
0522:                return alarms;
0523:            }
0524:
0525:            //Handling of insertions/deletions where we'll need to update the 
0526:            //list of blinking tabs here.
0527:            void intervalAdded(ListDataEvent evt) {
0528:                if (!hasAlarmTabs())
0529:                    return;
0530:                int start = evt.getIndex0();
0531:                int end = evt.getIndex1();
0532:                int[] alarms = (int[]) Utilities
0533:                        .toPrimitiveArray((Integer[]) alarmTabs
0534:                                .toArray(new Integer[0]));
0535:                boolean changed = false;
0536:                for (int i = 0; i < alarms.length; i++) {
0537:                    if (alarms[i] >= start) {
0538:                        alarms[i] += (end - start) + 1;
0539:                        changed = true;
0540:                    }
0541:                }
0542:                if (changed) {
0543:                    alarmTabs.clear();
0544:                    for (int i = 0; i < alarms.length; i++) {
0545:                        addAlarmTab(alarms[i]);
0546:                    }
0547:                }
0548:            }
0549:
0550:            void intervalRemoved(ListDataEvent evt) {
0551:                if (!hasAlarmTabs())
0552:                    return;
0553:                int start = evt.getIndex0();
0554:                int end = evt.getIndex1();
0555:
0556:                int[] alarms = (int[]) Utilities
0557:                        .toPrimitiveArray((Integer[]) alarmTabs
0558:                                .toArray(new Integer[0]));
0559:                Arrays.sort(alarms);
0560:
0561:                if (end == start) {
0562:                    //Faster to handle this case separately
0563:                    boolean changed = true;
0564:                    for (int i = 0; i < alarms.length; i++) {
0565:                        if (alarms[i] > end) {
0566:                            alarms[i]--;
0567:                        } else if (alarms[i] == end) {
0568:                            alarms[i] = -1;
0569:                        }
0570:                    }
0571:                    if (changed) {
0572:                        alarmTabs.clear();
0573:                        boolean added = false;
0574:                        for (int i = 0; i < alarms.length; i++) {
0575:                            if (alarms[i] != -1) {
0576:                                addAlarmTab(alarms[i]);
0577:                                added = true;
0578:                            }
0579:                        }
0580:                        if (!added) {
0581:                            stopAlarmTimer();
0582:                        }
0583:                    }
0584:                    return;
0585:                }
0586:
0587:                boolean changed = false;
0588:                for (int i = 0; i < alarms.length; i++) {
0589:                    if (alarms[i] >= start && alarms[i] <= end) {
0590:                        alarms[i] = -1;
0591:                        changed = true;
0592:                    }
0593:                }
0594:                for (int i = 0; i < alarms.length; i++) {
0595:                    if (alarms[i] > end) {
0596:                        alarms[i] -= (end - start) + 1;
0597:                        changed = true;
0598:                    }
0599:                }
0600:                if (changed) {
0601:                    alarmTabs.clear();
0602:                    boolean added = false;
0603:                    for (int i = 0; i < alarms.length; i++) {
0604:                        if (alarms[i] != -1) {
0605:                            addAlarmTab(alarms[i]);
0606:                            added = true;
0607:                        }
0608:                    }
0609:                    if (!added) {
0610:                        stopAlarmTimer();
0611:                    }
0612:                }
0613:            }
0614:
0615:            void indicesAdded(ComplexListDataEvent e) {
0616:                if (!hasAlarmTabs())
0617:                    return;
0618:                int[] alarms = (int[]) Utilities
0619:                        .toPrimitiveArray((Integer[]) alarmTabs
0620:                                .toArray(new Integer[0]));
0621:                java.util.Arrays.sort(alarms);
0622:
0623:                int[] indices = e.getIndices();
0624:                java.util.Arrays.sort(indices);
0625:
0626:                boolean changed = false;
0627:                for (int i = 0; i < indices.length; i++) {
0628:                    for (int j = 0; j < alarms.length; j++) {
0629:                        if (alarms[j] >= indices[i]) {
0630:                            alarms[j]++;
0631:                            changed = true;
0632:                        }
0633:                    }
0634:                }
0635:                if (changed) {
0636:                    alarmTabs.clear();
0637:                    for (int i = 0; i < alarms.length; i++) {
0638:                        if (alarms[i] != -1) {
0639:                            addAlarmTab(alarms[i]);
0640:                        }
0641:                    }
0642:                }
0643:            }
0644:
0645:            void indicesRemoved(ComplexListDataEvent e) {
0646:                if (!hasAlarmTabs())
0647:                    return;
0648:                int[] indices = e.getIndices();
0649:                java.util.Arrays.sort(indices);
0650:
0651:                int[] alarms = (int[]) Utilities
0652:                        .toPrimitiveArray((Integer[]) alarmTabs
0653:                                .toArray(new Integer[0]));
0654:                java.util.Arrays.sort(alarms);
0655:
0656:                if (alarms[alarms.length - 1] < indices[0]) {
0657:                    //Some tab removed after the last blinking tab, don't care
0658:                    return;
0659:                }
0660:
0661:                boolean changed = false;
0662:                for (int i = 0; i < alarms.length; i++) {
0663:                    //First weed out all deleted alarm tabs
0664:                    for (int j = 0; j < indices.length; j++) {
0665:                        if (alarms[i] == indices[j]) {
0666:                            alarms[i] = -1;
0667:                            changed = true;
0668:                        }
0669:                    }
0670:                }
0671:                for (int i = 0; i < alarms.length; i++) {
0672:                    //Now decrement those that remain that are affected
0673:                    int alarm = alarms[i];
0674:                    for (int j = 0; j < indices.length; j++) {
0675:                        if (alarm > indices[j]) {
0676:                            alarms[i]--;
0677:                            changed = true;
0678:                        }
0679:                    }
0680:                }
0681:
0682:                if (changed) {
0683:                    alarmTabs.clear();
0684:                    boolean addedSome = false;
0685:                    for (int i = 0; i < alarms.length; i++) {
0686:                        if (alarms[i] >= 0) {
0687:                            addAlarmTab(alarms[i]);
0688:                            addedSome = true;
0689:                        }
0690:                    }
0691:                    if (!addedSome) {
0692:                        stopAlarmTimer();
0693:                    }
0694:                }
0695:
0696:                repaintAllTabs();
0697:            }
0698:
0699:            void indicesChanged(ComplexListDataEvent e) {
0700:                if (!hasAlarmTabs())
0701:                    return;
0702:                if (e instanceof  VeryComplexListDataEvent) { //it always will be
0703:                    VeryComplexListDataEvent ve = (VeryComplexListDataEvent) e;
0704:
0705:                    ArrayDiff dif = ((VeryComplexListDataEvent) e).getDiff();
0706:
0707:                    List old = Arrays.asList(dif.getOldData());
0708:                    List nue = Arrays.asList(dif.getNewData());
0709:
0710:                    int[] alarms = (int[]) Utilities
0711:                            .toPrimitiveArray((Integer[]) alarmTabs
0712:                                    .toArray(new Integer[0]));
0713:
0714:                    boolean changed = false;
0715:                    for (int i = 0; i < alarms.length; i++) {
0716:                        Object o = old.get(alarms[i]);
0717:                        int idx = nue.indexOf(o);
0718:                        changed |= idx != alarms[i];
0719:                        alarms[i] = nue.indexOf(o);
0720:                    }
0721:                    if (changed) {
0722:                        alarmTabs.clear();
0723:                        boolean addedSome = false;
0724:                        for (int i = 0; i < alarms.length; i++) {
0725:                            if (alarms[i] >= 0) {
0726:                                addAlarmTab(alarms[i]);
0727:                                addedSome = true;
0728:                            }
0729:                        }
0730:                        if (!addedSome) {
0731:                            stopAlarmTimer();
0732:                        }
0733:                    }
0734:                }
0735:            }
0736:
0737:            void contentsChanged(ListDataEvent evt) {
0738:                if (!hasAlarmTabs())
0739:                    return;
0740:                //Do nothing, just means some text or icons changed
0741:            }
0742:
0743:            //Change types
0744:            /** Change type indicating no change happened (i.e. calling setSelected() with the same value it was previously
0745:             * called with).
0746:             */
0747:            public static final int NO_CHANGE = 0;
0748:            /** Change type indicating a change of state for two tabs */
0749:            public static final int CHANGE_TAB_TO_TAB = 1;
0750:            /** Change type indicating a change happened (such as the mouse leaving a tab) such that now no tab has the
0751:             * state previously held by the affected tab */
0752:            public static final int CHANGE_TAB_TO_NONE = 2;
0753:            /** Change type indicating that a state was added that no tab previously had */
0754:            public static final int CHANGE_NONE_TO_TAB = 3;
0755:            public static final int CHANGE_TAB_TO_SELF = 4;
0756:            /** Change type indicating one of the boolean state changes, such as STATE_ACTIVE */
0757:            public static final int ALL_TABS = Integer.MAX_VALUE;
0758:
0759:            protected void possibleChange(boolean prevVal, boolean currVal,
0760:                    int type) {
0761:                if (prevVal == currVal) {
0762:                    lastChangeType = NO_CHANGE;
0763:                } else {
0764:                    lastChangeType = ALL_TABS;
0765:                }
0766:                if (lastChangeType != NO_CHANGE) {
0767:                    lastAffected = ALL_TABS;
0768:                    change(ALL_TABS, ALL_TABS, type, lastChangeType);
0769:                }
0770:            }
0771:
0772:            protected void possibleChange(int lastTab, int currTab, int type) {
0773:                if (lastTab == currTab) {
0774:                    lastChangeType = NO_CHANGE;
0775:                } else {
0776:                    if (currTab == -1) {
0777:                        lastChangeType = CHANGE_TAB_TO_NONE;
0778:                    } else if (lastTab == -1) {
0779:                        lastChangeType = CHANGE_NONE_TO_TAB;
0780:                    } else {
0781:                        lastChangeType = CHANGE_TAB_TO_TAB;
0782:                    }
0783:                }
0784:                if (lastChangeType != NO_CHANGE) {
0785:                    lastAffected = currTab;
0786:                    change(lastTab, currTab, type, lastChangeType);
0787:                }
0788:            }
0789:
0790:            public String toString() {
0791:                StringBuffer sb = new StringBuffer(50);
0792:                sb.append("TabState [lastTab=");
0793:                sb.append(tabToString(prev));
0794:                sb.append(" currTab=");
0795:                sb.append(tabToString(curr));
0796:                sb.append(" lastAffected=");
0797:                sb.append(tabToString(lastAffected));
0798:                sb.append(" lastChangeType=");
0799:                sb.append(changeToString(lastChangeType));
0800:                sb.append(" lastChange=");
0801:                sb.append(stateToString(lastChange));
0802:                sb.append(" <active=");
0803:                sb.append(active);
0804:                sb.append(" sel=");
0805:                sb.append(tabToString(selectedIndex));
0806:                sb.append(" mouse=");
0807:                sb.append(tabToString(containsMouseIndex));
0808:                sb.append(" inTabs=");
0809:                sb.append(mouseInTabsArea);
0810:                sb.append(" pressed=");
0811:                sb.append(tabToString(pressedIndex));
0812:                sb.append(" inCloseButton=");
0813:                sb.append(tabToString(closeButtonContainsMouseIndex));
0814:                sb.append(" pressedCloseButton=");
0815:                sb.append(tabToString(mousePressedInCloseButtonIndex));
0816:                sb.append(">]");
0817:                return sb.toString();
0818:            }
0819:
0820:            /**
0821:             * Called when a setter for a tab index has produced a change in a
0822:             * state-affecting property, such as which tab contains the mouse.  Fetches
0823:             * the repaint policies, and if the change is one that the policy says
0824:             * should produce a repaint, calls repaintTab for the appropriate tabs.
0825:             *
0826:             * @param lastTab    The tab previously holding the state which has changed,
0827:             *                   or -1
0828:             * @param currTab    The tab currently holding the state which has changed,
0829:             *                   or -1
0830:             * @param type       The thing that changed.  This will be one of the state
0831:             *                   constants.
0832:             * @param changeType This is one of the defined change types such as
0833:             *                   ALL_TABS, TAB_TO_TAB, etc.
0834:             */
0835:            protected void change(int lastTab, int currTab, int type,
0836:                    int changeType) {
0837:                lastChange = type;
0838:                //        System.err.println("Change-type: " + stateToString(type) + " - " + changeToString (changeType) + " from " + tabToString (lastTab) + " to " + tabToString (currTab));
0839:                if (changeType == CHANGE_TAB_TO_TAB) {
0840:                    maybeRepaint(lastTab, type);
0841:                } else if (changeType == CHANGE_TAB_TO_NONE) {
0842:                    maybeRepaint(lastTab, type);
0843:                    return;
0844:                } else if (changeType == ALL_TABS
0845:                        && (getRepaintPolicy(currTab) & REPAINT_ALL_ON_MOUSE_ENTER_TABS_AREA) != 0) {
0846:                    repaintAllTabs();
0847:                    return;
0848:                }
0849:                maybeRepaint(currTab, type);
0850:            }
0851:
0852:            protected void maybeRepaint(int tab, int type) {
0853:                int rpol = getRepaintPolicy(tab);
0854:                boolean go = false;
0855:                switch (type) {
0856:                case ACTIVE:
0857:                    go = (rpol & REPAINT_SELECTION_ON_ACTIVATION_CHANGE) != 0;
0858:                    if ((rpol & REPAINT_ALL_TABS_ON_ACTIVATION_CHANGE) != 0) {
0859:                        type = ALL_TABS;
0860:                        go = true;
0861:                    }
0862:                    break;
0863:                case ARMED:
0864:                    go = (rpol & REPAINT_ON_MOUSE_ENTER_TAB) != 0
0865:                            || tab == closeButtonContainsMouseIndex;
0866:                    closeButtonContainsMouseIndex = -1;
0867:                    break;
0868:                case CLOSE_BUTTON_ARMED:
0869:                    go = (rpol & REPAINT_ON_MOUSE_ENTER_CLOSE_BUTTON) != 0;
0870:                    break;
0871:                case MOUSE_IN_TABS_AREA:
0872:                    go = (rpol & REPAINT_ALL_ON_MOUSE_ENTER_TABS_AREA) != 0;
0873:                    break;
0874:                case MOUSE_PRESSED_IN_CLOSE_BUTTON:
0875:                    go = (rpol & REPAINT_ON_CLOSE_BUTTON_PRESSED) != 0;
0876:                    break;
0877:                case PRESSED:
0878:                    go = (rpol & REPAINT_ON_MOUSE_PRESSED) != 0;
0879:                    break;
0880:                case SELECTED:
0881:                    go = (rpol & REPAINT_ON_SELECTION_CHANGE) != 0;
0882:                    if ((rpol & REPAINT_ALL_TABS_ON_SELECTION_CHANGE) != 0) {
0883:                        type = ALL_TABS;
0884:                        go = true;
0885:                    }
0886:                    break;
0887:                case ATTENTION:
0888:                    go = true;
0889:                }
0890:                if (go) {
0891:                    if (type == ALL_TABS) {
0892:                        repaintAllTabs();
0893:                    } else {
0894:                        repaintTab(tab);
0895:                    }
0896:                }
0897:            }
0898:
0899:            protected abstract void repaintTab(int tab);
0900:
0901:            protected abstract void repaintAllTabs();
0902:
0903:            static final String changeToString(int change) {
0904:                switch (change) {
0905:                case NO_CHANGE:
0906:                    return "no change"; //NOI18N
0907:                case CHANGE_TAB_TO_TAB:
0908:                    return "tab to tab"; //NOI18N
0909:                case CHANGE_TAB_TO_NONE:
0910:                    return "tab to none"; //NOI18N
0911:                case CHANGE_NONE_TO_TAB:
0912:                    return "none to tab"; //NOI18N
0913:                case CHANGE_TAB_TO_SELF:
0914:                    return "tab to self"; //NOI18N
0915:                case ALL_TABS:
0916:                    return "all tabs"; //NOI18N
0917:                default:
0918:                    return "??? " + change; //NOI18N
0919:                }
0920:            }
0921:
0922:            static final String tabToString(int tab) {
0923:                if (tab == ALL_TABS) {
0924:                    return "all tabs"; //NOI18N
0925:                } else if (tab == -1) {
0926:                    return "none"; //NOI18N
0927:                } else {
0928:                    return Integer.toString(tab);
0929:                }
0930:            }
0931:
0932:            /**
0933:             * Static utility method to get a string representation of a state
0934:             */
0935:            static final String stateToString(int st) {
0936:                String[] states = new String[] { "clip right", "clip left",
0937:                        "armed", "pressed", "selected", "active",
0938:                        "not onscreen",
0939:                        "leftmost", //NOI18N
0940:                        "rightmost", "in closebutton", "before selected",
0941:                        "after selected", "mouse in tabs area", //NOI18N
0942:                        "mouse pressed in close button" //NOI18N
0943:                }; //NOI18N
0944:                int[] vals = new int[] { CLIP_RIGHT, CLIP_LEFT, ARMED, PRESSED,
0945:                        SELECTED, ACTIVE, NOT_ONSCREEN, LEFTMOST, RIGHTMOST,
0946:                        CLOSE_BUTTON_ARMED, BEFORE_SELECTED, AFTER_SELECTED,
0947:                        MOUSE_IN_TABS_AREA, MOUSE_PRESSED_IN_CLOSE_BUTTON };
0948:                StringBuffer sb = new StringBuffer();
0949:                for (int i = 0; i < vals.length; i++) {
0950:                    if ((st & vals[i]) != 0) {
0951:                        if (sb.length() > 0) {
0952:                            sb.append(',');
0953:                        }
0954:                        sb.append(states[i]);
0955:                    }
0956:                }
0957:                if (sb.length() == 0) {
0958:                    sb.append("no flags set"); //NOI18N
0959:                }
0960:                sb.append("=");
0961:                sb.append(st);
0962:                return sb.toString();
0963:            }
0964:
0965:            static String repaintPolicyToString(int policy) {
0966:                if (policy == 0) {
0967:                    return "repaint nothing";
0968:                }
0969:                String[] names = new String[] { "REPAINT_ON_MOUSE_ENTER_TAB",
0970:                        "REPAINT_ALL_ON_MOUSE_ENTER_TABS_AREA",
0971:                        "REPAINT_ON_MOUSE_ENTER_CLOSE_BUTTON",
0972:                        "REPAINT_ON_MOUSE_PRESSED",
0973:                        "REPAINT_SELECTION_ON_ACTIVATION_CHANGE",
0974:                        "REPAINT_ALL_TABS_ON_ACTIVATION_CHANGE",
0975:                        "REPAINT_ON_SELECTION_CHANGE",
0976:                        "REPAINT_ALL_TABS_ON_SELECTION_CHANGE",
0977:                        "REPAINT_ON_CLOSE_BUTTON_PRESSED", };
0978:                int[] vals = new int[] { REPAINT_ON_MOUSE_ENTER_TAB,
0979:                        REPAINT_ALL_ON_MOUSE_ENTER_TABS_AREA,
0980:                        REPAINT_ON_MOUSE_ENTER_CLOSE_BUTTON,
0981:                        REPAINT_ON_MOUSE_PRESSED,
0982:                        REPAINT_SELECTION_ON_ACTIVATION_CHANGE,
0983:                        REPAINT_ALL_TABS_ON_ACTIVATION_CHANGE,
0984:                        REPAINT_ON_SELECTION_CHANGE,
0985:                        REPAINT_ALL_TABS_ON_SELECTION_CHANGE,
0986:                        REPAINT_ON_CLOSE_BUTTON_PRESSED, };
0987:                StringBuffer sb = new StringBuffer();
0988:                for (int i = 0; i < vals.length; i++) {
0989:                    if ((policy & vals[i]) != 0) {
0990:                        sb.append(names[i]);
0991:                        if (i != vals.length - 1) {
0992:                            sb.append('+');
0993:                        }
0994:                    }
0995:                }
0996:                return sb.toString();
0997:            }
0998:
0999:            /**
1000:             * Get the repaint policy that will be used to determine what tabs to repaint, based on state changes.
1001:             * The default implementation in BasicTabDisplayerUI simply ignores the tab argument and returns a
1002:             * single policy for all tabs created in <code>BasicTabDisplayerUI.createRepaintPolicy()</code>
1003:             *
1004:             * @param tab Index of tab in question 
1005:             * @return Type of repaint policy for given tab
1006:             */
1007:            public abstract int getRepaintPolicy(int tab);
1008:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.