1 19 20 package org.netbeans.modules.form.layoutdesign; 21 22 import java.util.ArrayList ; 23 import java.util.Collections ; 24 import java.util.Iterator ; 25 import java.util.LinkedList ; 26 import java.util.List ; 27 28 31 32 public final class LayoutInterval implements LayoutConstants { 33 static final int ATTRIBUTE_FILL = 1; 34 static final int ATTRIBUTE_FORMER_FILL = 2; 35 static final int ATTR_CLOSED_GROUP = 32; 36 37 static final int ATTR_DESIGN_CONTAINER_GAP = 4; 39 static final int ATTR_DESIGN_RESIZING = 8; 40 static final int ATTR_DESIGN_SUPPRESSED_RESIZING = 16; 41 42 static final int ATTR_ALIGN_PRE = 64; 44 static final int ATTR_ALIGN_POST = 128; 45 46 static final int DESIGN_ATTRS = ATTR_DESIGN_CONTAINER_GAP 47 | ATTR_DESIGN_RESIZING 48 | ATTR_DESIGN_SUPPRESSED_RESIZING 49 | ATTR_ALIGN_PRE 50 | ATTR_ALIGN_POST; 51 52 static final int ATTR_PERSISTENT_MASK = ATTRIBUTE_FILL | ATTRIBUTE_FORMER_FILL 53 | ATTR_CLOSED_GROUP; 54 55 private int type; 57 58 private int attributes; 60 61 private int alignment = DEFAULT; 63 64 private LayoutInterval parentInterval; 66 67 private int groupAlignment = LEADING; 69 70 private List subIntervals; 72 73 private LayoutComponent layoutComponent; 75 76 78 private int minSize; 80 private int prefSize; 81 private int maxSize; 82 83 private LayoutRegion currentSpace; 85 86 91 LayoutInterval(int type) { 92 this.type = type; 93 minSize = NOT_EXPLICITLY_DEFINED; 94 prefSize = NOT_EXPLICITLY_DEFINED; 95 if (type == SEQUENTIAL || type == PARALLEL) { 96 subIntervals = new ArrayList (); 97 maxSize = NOT_EXPLICITLY_DEFINED; } 99 else { 100 assert type == SINGLE; 101 maxSize = USE_PREFERRED_SIZE; 102 } 103 } 104 105 void setAlignment(int alignment) { 106 this.alignment = alignment; 107 } 108 109 void setGroupAlignment(int alignment) { 110 assert alignment != DEFAULT && type == PARALLEL; 111 groupAlignment = alignment; 112 } 113 114 void setComponent(LayoutComponent comp) { 115 this.layoutComponent = comp; 116 } 117 118 void setMinimumSize(int size) { 119 assert isSingle() || (size == USE_PREFERRED_SIZE || size == NOT_EXPLICITLY_DEFINED); 121 minSize = size; 122 } 123 124 void setPreferredSize(int size) { 125 assert (size != USE_PREFERRED_SIZE && isSingle()) || (size == NOT_EXPLICITLY_DEFINED); prefSize = size; 127 } 128 129 void setMaximumSize(int size) { 130 assert (isSingle() && size != NOT_EXPLICITLY_DEFINED) 133 || (isGroup() && (size == USE_PREFERRED_SIZE || size == NOT_EXPLICITLY_DEFINED)); 134 maxSize = size; 135 } 136 137 void setSize(int size) { 138 setMinimumSize(size); 139 setPreferredSize(size); 140 setMaximumSize(size); 141 } 142 143 void setSizes(int min, int pref, int max) { 144 setMinimumSize(min); 145 setPreferredSize(pref); 146 setMaximumSize(max); 147 } 148 149 int getMinimumSize() { 150 return minSize; 151 } 152 153 int getPreferredSize() { 154 return prefSize; 155 } 156 157 int getMaximumSize() { 158 return maxSize; 159 } 160 161 164 170 public int getType() { 171 return type; 172 } 173 174 180 public int getAlignment() { 181 return alignment == DEFAULT && parentInterval != null 182 && parentInterval.isParallel() ? 183 parentInterval.getGroupAlignment() : alignment; 184 } 185 186 191 public int getGroupAlignment() { 192 return groupAlignment; 193 } 194 195 204 public int getMinimumSize(boolean designTime) { 205 if (!designTime) { 206 return minSize; 207 } 208 if (hasAttribute(ATTR_DESIGN_SUPPRESSED_RESIZING)) { 209 assert !hasAttribute(ATTR_DESIGN_RESIZING); 210 return USE_PREFERRED_SIZE; 211 } 212 if (hasAttribute(ATTR_DESIGN_RESIZING)) { 213 return isEmptySpace() && (getPreferredSize(designTime) != 0) ? NOT_EXPLICITLY_DEFINED : 0; 214 } 215 return minSize; 216 } 217 218 225 public int getPreferredSize(boolean designTime) { 226 return prefSize; 227 } 228 229 238 public int getMaximumSize(boolean designTime) { 239 if (!designTime) { 240 return maxSize; 241 } 242 if (hasAttribute(ATTR_DESIGN_SUPPRESSED_RESIZING)) { 243 assert !hasAttribute(ATTR_DESIGN_RESIZING); 244 return USE_PREFERRED_SIZE; 245 } 246 if (hasAttribute(ATTR_DESIGN_RESIZING)) { 247 return Short.MAX_VALUE; 248 } 249 return maxSize; 250 } 251 252 256 public int getSubIntervalCount() { 257 return subIntervals != null ? subIntervals.size() : 0; 258 } 259 260 264 public Iterator getSubIntervals() { 265 return subIntervals != null ? subIntervals.iterator() : 266 Collections.EMPTY_LIST.iterator(); 267 } 268 269 275 public LayoutComponent getComponent() { 276 return layoutComponent; 277 } 278 279 281 public boolean isParallel() { 282 return type == PARALLEL; 283 } 284 285 public boolean isSequential() { 286 return type == SEQUENTIAL; 287 } 288 289 294 public boolean isComponent() { 295 return layoutComponent != null; 296 } 297 298 304 public boolean isEmptySpace() { 305 return type == SINGLE && layoutComponent == null; 306 } 307 308 public boolean isDefaultPadding(boolean designTime) { 309 return isEmptySpace() && (getMinimumSize(designTime) == NOT_EXPLICITLY_DEFINED 310 || getPreferredSize(designTime) == NOT_EXPLICITLY_DEFINED); 311 } 312 313 public boolean isSingle() { 314 return type == SINGLE; 315 } 316 317 322 public boolean isGroup() { 323 return type == SEQUENTIAL || type == PARALLEL; 324 } 325 326 331 338 343 350 353 boolean hasAttribute(int attr) { 354 return (attributes & attr) == attr; 355 } 356 357 void setAttribute(int attr) { 358 attributes |= attr; 359 } 360 361 void unsetAttribute(int attr) { 362 attributes &= ~attr; 363 } 364 365 370 void setAttributes(int attrs) { 371 attributes = attrs; 372 } 373 374 379 int getAttributes() { 380 return attributes; 381 } 382 383 387 int getRawAlignment() { 388 return alignment; 389 } 390 391 393 public LayoutInterval getParent() { 394 return parentInterval; 395 } 396 397 int add(LayoutInterval interval, int index) { 398 if (index < 0) { 399 index = subIntervals.size(); 400 } 401 subIntervals.add(index, interval); 402 interval.parentInterval = this; 403 return index; 404 } 405 406 int remove(LayoutInterval interval) { 407 int index = subIntervals.indexOf(interval); 408 if (index >= 0) { 409 subIntervals.remove(index); 410 interval.parentInterval = null; 411 } 412 return index; 413 } 414 415 LayoutInterval remove(int index) { 416 LayoutInterval interval = (LayoutInterval) subIntervals.get(index); 417 subIntervals.remove(index); 418 interval.parentInterval = null; 419 return interval; 420 } 421 422 LayoutInterval getSubInterval(int index) { 423 return subIntervals != null ? 424 (LayoutInterval) subIntervals.get(index) : null; 425 } 426 427 int indexOf(LayoutInterval interval) { 428 return subIntervals != null ? subIntervals.indexOf(interval) : -1; 429 } 430 431 boolean isParentOf(LayoutInterval interval) { 432 if (isGroup()) { 433 do { 434 interval = interval.getParent(); 435 if (interval == this) 436 return true; 437 } 438 while (interval != null); 439 } 440 return false; 441 } 442 443 447 LayoutRegion getCurrentSpace() { 448 assert !isEmptySpace(); if (currentSpace == null) { 450 currentSpace = new LayoutRegion(); 451 } 452 return currentSpace; 453 } 454 455 void setCurrentSpace(LayoutRegion space) { 456 currentSpace = space; 457 } 458 459 462 465 static LayoutInterval getFirstParent(LayoutInterval interval, int type) { 466 LayoutInterval parent = interval.getParent(); 467 while (parent != null && parent.getType() != type) { 468 parent = parent.getParent(); 469 } 470 return parent; 471 } 472 473 static LayoutInterval getRoot(LayoutInterval interval) { 474 while (interval.getParent() != null) { 475 interval = interval.getParent(); 476 } 477 return interval; 479 } 480 481 487 static LayoutInterval getCommonParent(LayoutInterval[] intervals) { 488 assert (intervals != null) && (intervals.length > 0); 489 LayoutInterval parent = intervals[0].getParent(); 490 for (int i=1; i<intervals.length; i++) { 491 parent = getCommonParent(parent, intervals[i]); 492 } 493 return parent; 494 } 495 496 503 static LayoutInterval getCommonParent(LayoutInterval interval1, LayoutInterval interval2) { 504 Iterator parents1 = parentsOfInterval(interval1).iterator(); 506 Iterator parents2 = parentsOfInterval(interval2).iterator(); 507 LayoutInterval parent1 = (LayoutInterval)parents1.next(); 508 LayoutInterval parent2 = (LayoutInterval)parents2.next(); 509 assert (parent1 == parent2); 510 511 LayoutInterval parent = null; 513 while (parent1 == parent2) { 514 parent = parent1; 515 if (parents1.hasNext()) { 516 parent1 = (LayoutInterval)parents1.next(); 517 } else { 518 break; 519 } 520 if (parents2.hasNext()) { 521 parent2 = (LayoutInterval)parents2.next(); 522 } else { 523 break; 524 } 525 } 526 return parent; 527 } 528 529 537 private static List parentsOfInterval(LayoutInterval interval) { 538 List parents = new LinkedList (); 539 while (interval != null) { 540 parents.add(0, interval); 541 interval = interval.getParent(); 542 } 543 return parents; 544 } 545 546 static int getCount(LayoutInterval group, int alignment, boolean nonEmpty) { 547 int n = 0; 548 Iterator it = group.getSubIntervals(); 549 while (it.hasNext()) { 550 LayoutInterval li = (LayoutInterval) it.next(); 551 if ((group.isSequential() 552 || alignment == LayoutRegion.ALL_POINTS 553 || li.getAlignment() == alignment 554 || wantResize(li)) 555 && (!nonEmpty || !li.isEmptySpace())) 556 { n++; 558 } 559 } 560 return n; 561 } 562 563 static LayoutInterval getDirectNeighbor(LayoutInterval interval, int alignment, boolean nonEmpty) { 564 LayoutInterval parent = interval.getParent(); 565 if (parent == null || parent.isParallel()) 566 return null; 567 568 LayoutInterval neighbor = null; 569 int d = (alignment == LEADING ? -1 : 1); 570 int n = parent.getSubIntervalCount(); 571 int index = parent.indexOf(interval) + d; 572 while (index >= 0 && index < n && neighbor == null) { 573 LayoutInterval li = parent.getSubInterval(index); 574 index += d; 575 if (!nonEmpty || !li.isEmptySpace()) { 576 neighbor = li; 577 } 578 } 579 return neighbor; 580 } 581 582 590 static LayoutInterval getNeighbor(LayoutInterval interval, 591 int alignment, 592 boolean nonEmpty, 593 boolean outOfParent, 594 boolean aligned) 595 { 596 assert alignment == LEADING || alignment == TRAILING; 597 598 LayoutInterval neighbor = null; 599 LayoutInterval parent = interval; 600 int d = (alignment == LEADING ? -1 : 1); 601 602 do { 603 do { interval = parent; 605 parent = interval.getParent(); 606 if (aligned && parent != null && parent.isParallel() 607 && !isAlignedAtBorder(interval, alignment)) 608 { parent = null; 610 } 611 } 612 while (parent != null && parent.isParallel()); 613 614 if (parent != null) { neighbor = getDirectNeighbor(interval, alignment, nonEmpty); 616 } 617 } 618 while (neighbor == null && parent != null && outOfParent); 619 620 return neighbor; 621 } 622 623 static LayoutInterval getNeighbor(LayoutInterval interval, int parentType, int alignment) { 624 assert alignment == LEADING || alignment == TRAILING; 625 LayoutInterval sibling = null; 626 LayoutInterval parent = interval; 627 do { 628 do { 629 interval = parent; 630 parent = parent.getParent(); 631 } while ((parent != null) && (parent.getType() != parentType)); 632 if (parent != null) { 633 List subs = parent.subIntervals; 634 int index = subs.indexOf(interval); 635 if ((alignment == LEADING) && (index > 0)) { 636 sibling = (LayoutInterval)subs.get(index-1); 637 } 638 else if ((alignment == TRAILING) && (index+1 < subs.size())) { 639 sibling = (LayoutInterval)subs.get(index+1); 640 } 641 } 642 } while ((parent != null) && (sibling == null)); 643 return sibling; 644 } 645 646 static boolean startsWithEmptySpace(LayoutInterval interval, int alignment) { 647 assert alignment == LEADING || alignment == TRAILING; 648 if (interval.isSingle()) { 649 return interval.isEmptySpace(); 650 } 651 if (interval.isSequential()) { 652 int index = alignment == LEADING ? 0 : interval.getSubIntervalCount()-1; 653 return startsWithEmptySpace(interval.getSubInterval(index), alignment); 654 } 655 else { for (Iterator it=interval.getSubIntervals(); it.hasNext(); ) { 657 LayoutInterval li = (LayoutInterval) it.next(); 658 if (startsWithEmptySpace(li, alignment)) { 659 return true; 660 } 661 } 662 } 663 return false; 664 } 665 666 673 static boolean isAlignedAtBorder(LayoutInterval interval, int alignment) { 674 if (alignment != LEADING && alignment != TRAILING) { 675 return false; 676 } 677 LayoutInterval parent = interval.getParent(); 678 if (parent == null) { 679 return false; 680 } 681 if (parent.isSequential()) { 682 int index = alignment == LEADING ? 0 : parent.getSubIntervalCount()-1; 683 return interval == parent.getSubInterval(index); 684 } 685 else { return interval.getAlignment() == alignment 687 || wantResize(interval); 688 } 689 } 690 691 696 static boolean isAlignedAtBorder(LayoutInterval interval, LayoutInterval parent, int alignment) { 697 do { 698 if (!isAlignedAtBorder(interval, alignment)) { 699 return false; 700 } 701 interval = interval.getParent(); 702 } 703 while (interval != parent); 704 return true; 705 } 706 707 714 static boolean isPlacedAtBorder(LayoutInterval interval, int dimension, int alignment) { 715 if (alignment != LEADING && alignment != TRAILING) { 716 return false; 717 } 718 LayoutInterval parent = interval.getParent(); 719 if (parent == null) { 720 return false; 721 } 722 if (interval.isEmptySpace()) { 723 if (parent.isSequential()) { 724 int index = alignment == LEADING ? 0 : parent.getSubIntervalCount()-1; 725 return interval == parent.getSubInterval(index); 726 } 727 else { return true; 729 } 730 } 731 else { return LayoutRegion.distance(interval.getCurrentSpace(), parent.getCurrentSpace(), 733 dimension, alignment, alignment) == 0; 734 } 735 } 736 737 744 static boolean isPlacedAtBorder(LayoutInterval interval, LayoutInterval parent, int dimension, int alignment) { 745 if (alignment != LEADING && alignment != TRAILING) { 746 return false; 747 } 748 if (interval.isEmptySpace()) { 749 LayoutInterval p = interval.getParent(); 750 if (p.isSequential()) { 751 int index = alignment == LEADING ? 0 : p.getSubIntervalCount()-1; 752 if (interval != p.getSubInterval(index)) { 753 return false; 754 } 755 } 756 if (p == parent) { 757 return true; 758 } 759 interval = p; 760 } 761 return LayoutRegion.distance(interval.getCurrentSpace(), parent.getCurrentSpace(), 762 dimension, alignment, alignment) == 0 763 && parent.isParentOf(interval); 764 } 765 766 static boolean isBorderInterval(LayoutInterval interval, int alignment, boolean attached) { 768 LayoutInterval parent = interval.getParent(); 769 if (parent != null && (alignment == LEADING || alignment == TRAILING)) { 770 if (parent.isSequential()) { 771 int index = alignment == LEADING ? 0 : parent.getSubIntervalCount()-1; 772 while (index >= 0 && index < parent.getSubIntervalCount()) { 773 LayoutInterval li = parent.getSubInterval(index); 774 if (li == interval) { 775 return true; 776 } 777 else if (attached || !li.isEmptySpace()) { 778 return false; 779 } 780 index += alignment == LEADING ? 1 : -1; 781 } 782 } 783 else { 784 return !attached 785 || interval.getAlignment() == alignment 786 || wantResize(interval); 787 } 788 } 792 return false; 793 } 794 795 static boolean isClosedGroup(LayoutInterval group, int alignment) { 796 assert group.isParallel(); 797 798 if (group.hasAttribute(ATTR_CLOSED_GROUP) 799 || group.getGroupAlignment() == CENTER 800 || group.getGroupAlignment() == BASELINE) 801 { 802 return true; 803 } 804 805 Iterator it = group.getSubIntervals(); 806 while (it.hasNext()) { 807 LayoutInterval li = (LayoutInterval) it.next(); 808 if (li.getAlignment() == alignment || wantResize(li)) { 809 return true; 810 } 811 } 812 return false; 813 } 814 815 static boolean isExplicitlyClosedGroup(LayoutInterval group) { 816 return group.hasAttribute(ATTR_CLOSED_GROUP); 817 } 818 819 static boolean isDefaultPadding(LayoutInterval interval) { 820 return interval.isEmptySpace() && (interval.getMinimumSize() == NOT_EXPLICITLY_DEFINED 821 || interval.getPreferredSize() == NOT_EXPLICITLY_DEFINED); 822 } 823 824 static boolean isFixedDefaultPadding(LayoutInterval interval) { 825 return interval.isEmptySpace() 826 && (interval.getMinimumSize() == NOT_EXPLICITLY_DEFINED || interval.getMinimumSize() == USE_PREFERRED_SIZE) 827 && interval.getPreferredSize() == NOT_EXPLICITLY_DEFINED 828 && (interval.getMaximumSize() == NOT_EXPLICITLY_DEFINED || interval.getMaximumSize() == USE_PREFERRED_SIZE); 829 } 830 831 834 static boolean canResize(LayoutInterval interval) { 835 int max = interval.getMaximumSize(); 837 int pref = interval.getPreferredSize(); 838 assert interval.isGroup() || max != NOT_EXPLICITLY_DEFINED; 839 return (max != pref && max != USE_PREFERRED_SIZE) 840 || max == NOT_EXPLICITLY_DEFINED; 841 } 842 843 848 static boolean wantResize(LayoutInterval interval) { 849 return canResize(interval) 850 && (!interval.isGroup() || contentWantResize(interval)); 851 } 852 853 859 static boolean wantResizeInLayout(LayoutInterval interval) { 860 if (!wantResize(interval)) 861 return false; 862 863 while (interval.getParent() != null) { 864 interval = interval.getParent(); 865 if (!canResize(interval)) 866 return false; 867 } 868 return true; 869 } 870 871 static boolean contentWantResize(LayoutInterval group) { 872 boolean subres = false; 873 Iterator it = group.getSubIntervals(); 874 while (it.hasNext()) { 875 if (wantResize((LayoutInterval)it.next())) { 876 subres = true; 877 break; 878 } 879 } 880 return subres; 881 } 882 883 static int getIntervalCurrentSize(LayoutInterval interval, int dimension) { 884 if (!interval.isEmptySpace()) { 885 return interval.getCurrentSpace().size(dimension); 886 } 887 888 int posL; 889 int posT; 890 891 LayoutInterval parent = interval.getParent(); 892 if (parent.isSequential()) { 893 int index = parent.indexOf(interval); 894 posL = index > 0 ? 895 parent.getSubInterval(index-1).getCurrentSpace().positions[dimension][TRAILING] : 896 parent.getCurrentSpace().positions[dimension][LEADING]; 897 posT = index+1 < parent.getSubIntervalCount() ? 898 parent.getSubInterval(index+1).getCurrentSpace().positions[dimension][LEADING] : 899 parent.getCurrentSpace().positions[dimension][TRAILING]; 900 } 901 else { 902 posL = parent.getCurrentSpace().positions[dimension][LEADING]; 903 posT = parent.getCurrentSpace().positions[dimension][TRAILING]; 904 } 905 906 return posT - posL; 907 } 908 909 919 static int getEffectiveAlignment(LayoutInterval interval) { 920 LayoutInterval parent = interval.getParent(); 921 if (parent.isParallel()) 922 return interval.getAlignment(); 923 924 if (LayoutInterval.wantResize(interval)) 925 return DEFAULT; 926 927 boolean before = true; 928 boolean leadingFixed = true; 929 boolean trailingFixed = true; 930 Iterator it = parent.getSubIntervals(); 931 do { 932 LayoutInterval li = (LayoutInterval) it.next(); 933 if (li == interval) { 934 before = false; 935 } 936 else if (LayoutInterval.wantResize(li)) { 937 if (before) 938 leadingFixed = false; 939 else 940 trailingFixed = false; 941 } 942 } 943 while (it.hasNext()); 944 945 if (leadingFixed && !trailingFixed) 946 return LEADING; 947 if (!leadingFixed && trailingFixed) 948 return TRAILING; 949 if (leadingFixed && trailingFixed) 950 return parent.getAlignment(); 951 952 return DEFAULT; } 954 955 962 static int getEffectiveAlignment(LayoutInterval interval, int edge) { 963 assert edge == LEADING || edge == TRAILING; 964 965 boolean wantResize = LayoutInterval.wantResize(interval); 966 967 LayoutInterval parent = interval.getParent(); 968 if (parent.isParallel()) 969 return wantResize ? edge : interval.getAlignment(); 970 971 int n = parent.getSubIntervalCount(); 972 int i = edge == LEADING ? 0 : n-1; 973 int d = edge == LEADING ? 1 : -1; 974 boolean before = true; 975 boolean beforeFixed = true; 976 boolean afterFixed = true; 977 while (i >=0 && i < n) { 978 LayoutInterval li = parent.getSubInterval(i); 979 if (li == interval) { 980 before = false; 981 } 982 else if (LayoutInterval.wantResize(li)) { 983 if (before) 984 beforeFixed = false; 985 else 986 afterFixed = false; 987 } 988 i += d; 989 } 990 991 if (beforeFixed && !afterFixed) 992 return edge; 993 if (!beforeFixed && afterFixed) 994 return edge^1; 995 if (beforeFixed && afterFixed) 996 return wantResize ? edge : parent.getAlignment(); 997 998 return DEFAULT; } 1000 1001 1007 static int getEffectiveAlignmentInParent(LayoutInterval interval, LayoutInterval parent, int edge) { 1008 assert parent.isParentOf(interval); 1009 int alignment = edge; 1010 do { 1011 alignment = getEffectiveAlignment(interval, alignment); 1012 interval = interval.getParent(); 1013 if (alignment != LEADING && alignment != TRAILING) { 1014 while (interval != parent) { 1015 if (getEffectiveAlignment(interval) != alignment) 1016 return DEFAULT; 1017 interval = interval.getParent(); 1018 } 1019 } 1020 } 1021 while (interval != parent); 1022 return alignment; 1023 } 1024 1025 1032 static LayoutInterval cloneInterval(LayoutInterval interval, LayoutInterval clone) { 1033 clone = (clone == null) ? new LayoutInterval(interval.getType()) : clone; 1034 clone.setAlignment(interval.getAlignment()); 1035 clone.setAttributes(interval.getAttributes()); 1036 if (interval.getType() == PARALLEL) { 1037 clone.setGroupAlignment(interval.getGroupAlignment()); 1038 } 1039 clone.setSizes(interval.getMinimumSize(), interval.getPreferredSize(), interval.getMaximumSize()); 1040 return clone; 1041 } 1042} 1043 | Popular Tags |