1 19 package org.netbeans.swing.tabcontrol.plaf; 20 21 import java.awt.event.ActionEvent ; 22 import java.awt.event.ActionListener ; 23 import java.util.ArrayList ; 24 import java.util.Arrays ; 25 import java.util.HashSet ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 import java.util.Set ; 29 import javax.swing.Timer ; 30 import javax.swing.event.ListDataEvent ; 31 import org.netbeans.swing.tabcontrol.TabData; 32 import org.netbeans.swing.tabcontrol.event.ArrayDiff; 33 import org.netbeans.swing.tabcontrol.event.ComplexListDataEvent; 34 import org.netbeans.swing.tabcontrol.event.VeryComplexListDataEvent; 35 import org.openide.util.Utilities; 36 37 98 public abstract class TabState { 99 100 104 public static final int CLIP_RIGHT = 1; 105 109 public static final int CLIP_LEFT = 2; 110 113 public static final int ARMED = 4; 114 118 public static final int PRESSED = 8; 119 122 public static final int SELECTED = 16; 123 126 public static final int ACTIVE = 32; 127 136 public static final int NOT_ONSCREEN = 64; 137 141 public static final int LEFTMOST = 128; 142 146 public static final int RIGHTMOST = 256; 147 151 public static final int CLOSE_BUTTON_ARMED = 512; 152 156 public static final int BEFORE_SELECTED = 1024; 157 161 public static final int AFTER_SELECTED = 2048; 162 165 public static final int MOUSE_IN_TABS_AREA = 4096; 166 167 171 public static final int MOUSE_PRESSED_IN_CLOSE_BUTTON = 8192; 172 173 177 public static final int ATTENTION = 16384; 178 179 183 public static final int BEFORE_ARMED = 32768; 184 185 189 public static int STATE_LAST = MOUSE_PRESSED_IN_CLOSE_BUTTON; 190 191 192 private int pressedIndex = -1; 193 private int containsMouseIndex = -1; 194 private int closeButtonContainsMouseIndex = -1; 195 private int mousePressedInCloseButtonIndex = -1; 196 private boolean mouseInTabsArea = false; 197 private boolean active = false; 198 private int selectedIndex = -1; 199 200 private int prev = -1; 201 private int curr = -1; 202 private int lastChangeType = NO_CHANGE; 203 private int lastAffected = 0; 204 private int lastChange = 0; 205 206 207 public static final int REPAINT_ON_MOUSE_ENTER_TAB = 1; 208 210 public static final int REPAINT_ALL_ON_MOUSE_ENTER_TABS_AREA = 3; 211 213 public static final int REPAINT_ON_MOUSE_ENTER_CLOSE_BUTTON = 4; 214 215 public static final int REPAINT_ON_MOUSE_PRESSED = 8; 216 217 public static final int REPAINT_SELECTION_ON_ACTIVATION_CHANGE = 16; 218 219 public static final int REPAINT_ALL_TABS_ON_ACTIVATION_CHANGE = 32; 221 public static final int REPAINT_ON_SELECTION_CHANGE = 64; 222 223 public static final int REPAINT_ALL_TABS_ON_SELECTION_CHANGE = 128; 224 225 public static final int REPAINT_ON_CLOSE_BUTTON_PRESSED = 256; 226 227 237 public int getState(int tab) { 238 int result = 0; 239 if (tab == pressedIndex) { 240 result |= PRESSED; 241 } 242 if (tab == containsMouseIndex) { 243 result |= ARMED; 244 } 245 if (tab == closeButtonContainsMouseIndex) { 246 result |= CLOSE_BUTTON_ARMED; 247 } 248 if (tab == mousePressedInCloseButtonIndex) { 249 result |= MOUSE_PRESSED_IN_CLOSE_BUTTON; 250 } 251 if (mouseInTabsArea) { 252 result |= MOUSE_IN_TABS_AREA; 253 } 254 if (active) { 255 result |= ACTIVE; 256 } 257 if (tab == selectedIndex) { 258 result |= SELECTED; 259 } 260 if (tab != 0 && tab == selectedIndex + 1) { 261 result |= AFTER_SELECTED; 262 } 263 if (tab == selectedIndex - 1) { 264 result |= BEFORE_SELECTED; 265 } 266 if (tab == containsMouseIndex - 1) { 267 result |= BEFORE_ARMED; 268 } 269 if (isAlarmTab(tab)) { 270 result |= ATTENTION; 271 } 272 return result; 273 } 274 275 276 String getStateString (int tab) { 277 return stateToString (getState(tab)); 278 } 279 280 285 public void clearTransientStates() { 286 pressedIndex = -1; 287 containsMouseIndex = -1; 288 closeButtonContainsMouseIndex = -1; 289 mousePressedInCloseButtonIndex = -1; 290 mouseInTabsArea = false; 291 lastChangeType = NO_CHANGE; 292 lastChange = 0; 293 prev = -1; 294 curr = -1; 295 } 296 297 304 public final int setPressed(int i) { 305 prev = pressedIndex; 306 pressedIndex = i; 307 curr = i; 308 possibleChange(prev, curr, PRESSED); 309 return prev; 310 } 311 312 319 public final int setContainsMouse(int i) { 320 prev = containsMouseIndex; 321 containsMouseIndex = i; 322 curr = i; 323 possibleChange(prev, curr, ARMED); 324 return prev; 325 } 326 327 336 public final int setCloseButtonContainsMouse(int i) { 337 prev = closeButtonContainsMouseIndex; 338 closeButtonContainsMouseIndex = i; 339 curr = i; 340 possibleChange(prev, curr, CLOSE_BUTTON_ARMED); 341 return prev; 342 } 343 344 356 public final int setMousePressedInCloseButton(int i) { 357 prev = mousePressedInCloseButtonIndex; 358 mousePressedInCloseButtonIndex = i; 359 curr = i; 360 possibleChange(prev, curr, MOUSE_PRESSED_IN_CLOSE_BUTTON); 361 return prev; 362 } 363 364 372 public final int setSelected(int i) { 373 prev = selectedIndex; 374 selectedIndex = i; 375 curr = i; 376 removeAlarmTab(i); 377 possibleChange(prev, curr, SELECTED); 378 return prev; 379 } 380 381 388 public final boolean setMouseInTabsArea(boolean b) { 389 boolean prev = mouseInTabsArea; 390 mouseInTabsArea = b; 391 possibleChange(prev, b, MOUSE_IN_TABS_AREA); 392 return prev; 393 } 394 395 401 public final boolean setActive(boolean b) { 402 boolean prev = active; 403 active = b; 404 possibleChange(prev, b, ACTIVE); 405 removeAlarmTab(selectedIndex); 406 return prev; 407 } 408 409 private boolean isAlarmTab (int tab) { 410 return attentionToggle && alarmTabs.contains(new Integer (tab)); 411 } 412 413 private final HashSet <Integer > alarmTabs = new HashSet <Integer >(6); 414 415 417 public final void addAlarmTab (int alarmTab) { 418 Integer in = new Integer (alarmTab); 419 boolean added = alarmTabs.contains(in); 420 boolean wasEmpty = alarmTabs.isEmpty(); 421 if (!added) { 422 alarmTabs.add (new Integer (alarmTab)); 423 repaintTab (alarmTab); 424 } 425 if (wasEmpty) { 426 startAlarmTimer(); 427 attentionToggle = true; 428 repaintTab (alarmTab); 429 } 430 } 431 432 434 public final void removeAlarmTab (int alarmTab) { 435 Integer in = new Integer (alarmTab); 436 boolean contained = alarmTabs.contains(in); 437 if (contained) { 438 alarmTabs.remove(in); 439 boolean empty = alarmTabs.isEmpty(); 440 boolean wasAttentionToggled = attentionToggle; 441 if (alarmTabs.isEmpty()) { 442 stopAlarmTimer(); 443 } 444 if (wasAttentionToggled) { 445 repaintTab(alarmTab); 446 } 447 } 448 } 449 450 private Timer alarmTimer = null; 451 private boolean attentionToggle = false; 452 private final void startAlarmTimer() { 453 if (alarmTimer == null) { 454 ActionListener al = new ActionListener () { 455 public void actionPerformed (ActionEvent ae) { 456 attentionToggle = !attentionToggle; 457 Timer timer = (Timer ) ae.getSource(); 458 for (Iterator i=alarmTabs.iterator(); i.hasNext();) { 459 repaintTab (((Integer ) i.next()).intValue()); 460 } 461 } 462 }; 463 alarmTimer = new Timer (700, al); 464 alarmTimer.setRepeats(true); 465 } 466 alarmTimer.start(); 467 } 468 469 private final void stopAlarmTimer() { 470 if (alarmTimer != null && alarmTimer.isRunning()) { 471 alarmTimer.stop(); 472 attentionToggle = false; 473 repaintAllTabs(); } 475 } 476 477 boolean hasAlarmTabs() { 478 return alarmTabs != null && !alarmTabs.isEmpty(); 479 } 480 481 void pruneAlarmTabs(int max) { 482 if (!hasAlarmTabs()) { 483 return; 484 } 485 for (Iterator i=alarmTabs.iterator(); i.hasNext();) { 486 if (((Integer ) i.next()).intValue() >= max) { 487 i.remove(); 488 } 489 } 490 if (alarmTabs.isEmpty()) { 491 stopAlarmTimer(); 492 } 493 } 494 495 int[] getAlarmTabs() { 496 int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer []) alarmTabs.toArray(new Integer [0])); 497 Arrays.sort(alarms); 498 return alarms; 499 } 500 501 void intervalAdded (ListDataEvent evt) { 504 if (!hasAlarmTabs()) return; 505 int start = evt.getIndex0(); 506 int end = evt.getIndex1(); 507 int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer []) alarmTabs.toArray(new Integer [0])); 508 boolean changed = false; 509 for (int i=0; i < alarms.length; i++) { 510 if (alarms[i] >= start) { 511 alarms[i] += (end - start) + 1; 512 changed = true; 513 } 514 } 515 if (changed) { 516 alarmTabs.clear(); 517 for (int i=0; i < alarms.length; i++) { 518 addAlarmTab(alarms[i]); 519 } 520 } 521 } 522 523 void intervalRemoved (ListDataEvent evt) { 524 if (!hasAlarmTabs()) return; 525 int start = evt.getIndex0(); 526 int end = evt.getIndex1(); 527 528 int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer []) alarmTabs.toArray(new Integer [0])); 529 Arrays.sort(alarms); 530 531 if (end == start) { 532 boolean changed = true; 534 for (int i=0; i < alarms.length; i++) { 535 if (alarms[i] > end) { 536 alarms[i]--; 537 } else if (alarms[i] == end) { 538 alarms[i] = -1; 539 } 540 } 541 if (changed) { 542 alarmTabs.clear(); 543 boolean added = false; 544 for (int i=0; i < alarms.length; i++) { 545 if (alarms[i] != -1) { 546 addAlarmTab(alarms[i]); 547 added = true; 548 } 549 } 550 if (!added) { 551 stopAlarmTimer(); 552 } 553 } 554 return; 555 } 556 557 boolean changed = false; 558 for (int i=0; i < alarms.length; i++) { 559 if (alarms[i] >= start && alarms[i] <= end) { 560 alarms[i] = -1; 561 changed = true; 562 } 563 } 564 for (int i=0; i < alarms.length; i++) { 565 if (alarms[i] > end) { 566 alarms[i] -= (end - start) + 1; 567 changed = true; 568 } 569 } 570 if (changed) { 571 alarmTabs.clear(); 572 boolean added = false; 573 for (int i=0; i < alarms.length; i++) { 574 if (alarms[i] != -1) { 575 addAlarmTab(alarms[i]); 576 added = true; 577 } 578 } 579 if (!added) { 580 stopAlarmTimer(); 581 } 582 } 583 } 584 585 void indicesAdded (ComplexListDataEvent e) { 586 if (!hasAlarmTabs()) return; 587 int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer []) alarmTabs.toArray(new Integer [0])); 588 java.util.Arrays.sort(alarms); 589 590 int[] indices = e.getIndices(); 591 java.util.Arrays.sort(indices); 592 593 boolean changed = false; 594 for (int i=0; i < indices.length; i++) { 595 for (int j=0; j < alarms.length; j++) { 596 if (alarms[j] >= indices[i]) { 597 alarms[j]++; 598 changed = true; 599 } 600 } 601 } 602 if (changed) { 603 alarmTabs.clear(); 604 for (int i=0; i < alarms.length; i++) { 605 if (alarms[i] != -1) { 606 addAlarmTab(alarms[i]); 607 } 608 } 609 } 610 } 611 612 void indicesRemoved (ComplexListDataEvent e) { 613 if (!hasAlarmTabs()) return; 614 int[] indices = e.getIndices(); 615 java.util.Arrays.sort(indices); 616 617 int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer []) alarmTabs.toArray(new Integer [0])); 618 java.util.Arrays.sort(alarms); 619 620 if (alarms[alarms.length -1] < indices[0]) { 621 return; 623 } 624 625 boolean changed = false; 626 for (int i=0; i < alarms.length; i++) { 627 for (int j=0; j < indices.length; j++) { 629 if (alarms[i] == indices[j]) { 630 alarms[i] = -1; 631 changed = true; 632 } 633 } 634 } 635 for (int i=0; i < alarms.length; i++) { 636 int alarm = alarms[i]; 638 for (int j=0; j < indices.length; j++) { 639 if (alarm > indices[j]) { 640 alarms[i]--; 641 changed = true; 642 } 643 } 644 } 645 646 if (changed) { 647 alarmTabs.clear(); 648 boolean addedSome = false; 649 for (int i=0; i < alarms.length; i++) { 650 if (alarms[i] >= 0) { 651 addAlarmTab(alarms[i]); 652 addedSome = true; 653 } 654 } 655 if (!addedSome) { 656 stopAlarmTimer(); 657 } 658 } 659 660 repaintAllTabs(); 661 } 662 663 void indicesChanged (ComplexListDataEvent e) { 664 if (!hasAlarmTabs()) return; 665 if (e instanceof VeryComplexListDataEvent) { VeryComplexListDataEvent ve = (VeryComplexListDataEvent) e; 667 668 ArrayDiff dif = ((VeryComplexListDataEvent) e).getDiff(); 669 670 List old = Arrays.asList(dif.getOldData()); 671 List nue = Arrays.asList(dif.getNewData()); 672 673 int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer []) alarmTabs.toArray(new Integer [0])); 674 675 boolean changed = false; 676 for (int i=0; i < alarms.length; i++) { 677 Object o = old.get(alarms[i]); 678 int idx = nue.indexOf(o); 679 changed |= idx != alarms[i]; 680 alarms[i] = nue.indexOf(o); 681 } 682 if (changed) { 683 alarmTabs.clear(); 684 boolean addedSome = false; 685 for (int i=0; i < alarms.length; i++) { 686 if (alarms[i] >= 0) { 687 addAlarmTab(alarms[i]); 688 addedSome = true; 689 } 690 } 691 if (!addedSome) { 692 stopAlarmTimer(); 693 } 694 } 695 } 696 } 697 698 699 void contentsChanged(ListDataEvent evt) { 700 if (!hasAlarmTabs()) return; 701 } 703 704 708 public static final int NO_CHANGE = 0; 709 710 public static final int CHANGE_TAB_TO_TAB = 1; 711 713 public static final int CHANGE_TAB_TO_NONE = 2; 714 715 public static final int CHANGE_NONE_TO_TAB = 3; 716 public static final int CHANGE_TAB_TO_SELF = 4; 717 718 public static final int ALL_TABS = Integer.MAX_VALUE; 719 720 protected void possibleChange(boolean prevVal, boolean currVal, int type) { 721 if (prevVal == currVal) { 722 lastChangeType = NO_CHANGE; 723 } else { 724 lastChangeType = ALL_TABS; 725 } 726 if (lastChangeType != NO_CHANGE) { 727 lastAffected = ALL_TABS; 728 change(ALL_TABS, ALL_TABS, type, lastChangeType); 729 } 730 } 731 732 protected void possibleChange(int lastTab, int currTab, int type) { 733 if (lastTab == currTab) { 734 lastChangeType = NO_CHANGE; 735 } else { 736 if (currTab == -1) { 737 lastChangeType = CHANGE_TAB_TO_NONE; 738 } else if (lastTab == -1) { 739 lastChangeType = CHANGE_NONE_TO_TAB; 740 } else { 741 lastChangeType = CHANGE_TAB_TO_TAB; 742 } 743 } 744 if (lastChangeType != NO_CHANGE) { 745 lastAffected = currTab; 746 change(lastTab, currTab, type, lastChangeType); 747 } 748 } 749 750 public String toString() { 751 StringBuffer sb = new StringBuffer (50); 752 sb.append("TabState [lastTab="); 753 sb.append(tabToString(prev)); 754 sb.append(" currTab="); 755 sb.append(tabToString(curr)); 756 sb.append(" lastAffected="); 757 sb.append(tabToString(lastAffected)); 758 sb.append(" lastChangeType="); 759 sb.append(changeToString(lastChangeType)); 760 sb.append(" lastChange="); 761 sb.append(stateToString(lastChange)); 762 sb.append(" <active="); 763 sb.append(active); 764 sb.append(" sel="); 765 sb.append(tabToString(selectedIndex)); 766 sb.append(" mouse="); 767 sb.append(tabToString(containsMouseIndex)); 768 sb.append(" inTabs="); 769 sb.append(mouseInTabsArea); 770 sb.append(" pressed="); 771 sb.append(tabToString(pressedIndex)); 772 sb.append(" inCloseButton="); 773 sb.append(tabToString(closeButtonContainsMouseIndex)); 774 sb.append(" pressedCloseButton="); 775 sb.append(tabToString(mousePressedInCloseButtonIndex)); 776 sb.append(">]"); 777 return sb.toString(); 778 } 779 780 795 protected void change(int lastTab, int currTab, int type, int changeType) { 796 lastChange = type; 797 if (changeType == CHANGE_TAB_TO_TAB) { 799 maybeRepaint(lastTab, type); 800 } else if (changeType == CHANGE_TAB_TO_NONE) { 801 maybeRepaint (lastTab, type); 802 return; 803 } else if (changeType == ALL_TABS && (getRepaintPolicy(currTab) & REPAINT_ALL_ON_MOUSE_ENTER_TABS_AREA) != 0) { 804 repaintAllTabs(); 805 return; 806 } 807 maybeRepaint(currTab, type); 808 } 809 810 protected void maybeRepaint(int tab, int type) { 811 int rpol = getRepaintPolicy (tab); 812 boolean go = false; 813 switch (type) { 814 case ACTIVE: 815 go = (rpol 816 & REPAINT_SELECTION_ON_ACTIVATION_CHANGE) 817 != 0; 818 if ((rpol 819 & REPAINT_ALL_TABS_ON_ACTIVATION_CHANGE) 820 != 0) { 821 type = ALL_TABS; 822 go = true; 823 } 824 break; 825 case ARMED: 826 go = (rpol & REPAINT_ON_MOUSE_ENTER_TAB) != 0 || 827 tab == closeButtonContainsMouseIndex; 828 closeButtonContainsMouseIndex = -1; 829 break; 830 case CLOSE_BUTTON_ARMED: 831 go = (rpol & REPAINT_ON_MOUSE_ENTER_CLOSE_BUTTON) 832 != 0; 833 break; 834 case MOUSE_IN_TABS_AREA: 835 go = (rpol 836 & REPAINT_ALL_ON_MOUSE_ENTER_TABS_AREA) 837 != 0; 838 break; 839 case MOUSE_PRESSED_IN_CLOSE_BUTTON: 840 go = (rpol & REPAINT_ON_CLOSE_BUTTON_PRESSED) 841 != 0; 842 break; 843 case PRESSED: 844 go = (rpol & REPAINT_ON_MOUSE_PRESSED) != 0; 845 break; 846 case SELECTED: 847 go = (rpol & REPAINT_ON_SELECTION_CHANGE) != 0; 848 if ((rpol & REPAINT_ALL_TABS_ON_SELECTION_CHANGE) 849 != 0) { 850 type = ALL_TABS; 851 go = true; 852 } 853 break; 854 case ATTENTION: 855 go = true; 856 } 857 if (go) { 858 if (type == ALL_TABS) { 859 repaintAllTabs(); 860 } else { 861 repaintTab(tab); 862 } 863 } 864 } 865 866 protected abstract void repaintTab(int tab); 867 868 protected abstract void repaintAllTabs(); 869 870 static final String changeToString(int change) { 871 switch (change) { 872 case NO_CHANGE: 873 return "no change"; case CHANGE_TAB_TO_TAB: 875 return "tab to tab"; case CHANGE_TAB_TO_NONE: 877 return "tab to none"; case CHANGE_NONE_TO_TAB: 879 return "none to tab"; case CHANGE_TAB_TO_SELF: 881 return "tab to self"; case ALL_TABS: 883 return "all tabs"; default : 885 return "??? " + change; } 887 } 888 889 static final String tabToString(int tab) { 890 if (tab == ALL_TABS) { 891 return "all tabs"; } else if (tab == -1) { 893 return "none"; } else { 895 return Integer.toString(tab); 896 } 897 } 898 899 902 static final String stateToString(int st) { 903 String [] states = new String []{ 904 "clip right", "clip left", "armed", "pressed", "selected", "active", "not onscreen", "leftmost", "rightmost", "in closebutton", "before selected", "after selected", "mouse in tabs area", "mouse pressed in close button" }; int[] vals = new int[]{ 909 CLIP_RIGHT, CLIP_LEFT, ARMED, PRESSED, SELECTED, ACTIVE, 910 NOT_ONSCREEN, LEFTMOST, RIGHTMOST, CLOSE_BUTTON_ARMED, 911 BEFORE_SELECTED, AFTER_SELECTED, MOUSE_IN_TABS_AREA, 912 MOUSE_PRESSED_IN_CLOSE_BUTTON}; 913 StringBuffer sb = new StringBuffer (); 914 for (int i = 0; i < vals.length; i++) { 915 if ((st & vals[i]) != 0) { 916 if (sb.length() > 0) { 917 sb.append(','); 918 } 919 sb.append(states[i]); 920 } 921 } 922 if (sb.length() == 0) { 923 sb.append("no flags set"); } 925 sb.append("="); 926 sb.append(st); 927 return sb.toString(); 928 } 929 930 static String repaintPolicyToString (int policy) { 931 if (policy == 0) { 932 return "repaint nothing"; 933 } 934 String [] names = new String [] { 935 "REPAINT_ON_MOUSE_ENTER_TAB", 936 "REPAINT_ALL_ON_MOUSE_ENTER_TABS_AREA", 937 "REPAINT_ON_MOUSE_ENTER_CLOSE_BUTTON", 938 "REPAINT_ON_MOUSE_PRESSED", 939 "REPAINT_SELECTION_ON_ACTIVATION_CHANGE", 940 "REPAINT_ALL_TABS_ON_ACTIVATION_CHANGE", 941 "REPAINT_ON_SELECTION_CHANGE", 942 "REPAINT_ALL_TABS_ON_SELECTION_CHANGE", 943 "REPAINT_ON_CLOSE_BUTTON_PRESSED", 944 }; 945 int[] vals = new int[] { 946 REPAINT_ON_MOUSE_ENTER_TAB, 947 REPAINT_ALL_ON_MOUSE_ENTER_TABS_AREA, 948 REPAINT_ON_MOUSE_ENTER_CLOSE_BUTTON, 949 REPAINT_ON_MOUSE_PRESSED, 950 REPAINT_SELECTION_ON_ACTIVATION_CHANGE, 951 REPAINT_ALL_TABS_ON_ACTIVATION_CHANGE, 952 REPAINT_ON_SELECTION_CHANGE, 953 REPAINT_ALL_TABS_ON_SELECTION_CHANGE, 954 REPAINT_ON_CLOSE_BUTTON_PRESSED, 955 }; 956 StringBuffer sb = new StringBuffer (); 957 for (int i=0; i < vals.length; i++) { 958 if ((policy & vals[i]) != 0) { 959 sb.append (names[i]); 960 if (i != vals.length-1) { 961 sb.append ('+'); 962 } 963 } 964 } 965 return sb.toString(); 966 } 967 968 976 public abstract int getRepaintPolicy(int tab); 977 } 978 | Popular Tags |