1 19 20 package org.netbeans.modules.form.layoutdesign; 21 22 import java.util.*; 23 24 30 31 class LayoutOperations implements LayoutConstants { 32 33 private LayoutModel layoutModel; 34 35 private VisualMapper visualMapper; 36 37 LayoutOperations(LayoutModel model, VisualMapper mapper) { 38 layoutModel = model; 39 visualMapper = mapper; 40 } 41 42 LayoutModel getModel() { 43 return layoutModel; 44 } 45 46 VisualMapper getMapper() { 47 return visualMapper; 48 } 49 50 52 57 int extract(LayoutInterval interval, int alignment, boolean closed, 58 List restLeading, List restTrailing) { 59 return extract(interval, interval, alignment, closed, restLeading, restTrailing); 60 } 61 62 int extract(LayoutInterval leading, LayoutInterval trailing, int alignment, boolean closed, 63 List restLeading, List restTrailing) 64 { 65 LayoutInterval seq = leading.getParent(); 66 assert seq.isSequential(); 67 68 int leadingIndex = seq.indexOf(leading); 69 int trailingIndex = seq.indexOf(trailing); 70 int count = seq.getSubIntervalCount(); 71 int extractCount; 72 if (closed) { 73 extractCount = trailingIndex - leadingIndex + 1; 74 } else if (alignment != LEADING && alignment != TRAILING) { 75 extractCount = 1; 76 } 77 else { 78 extractCount = alignment == LEADING ? count - leadingIndex : leadingIndex + 1; 79 } 80 81 if (extractCount < seq.getSubIntervalCount()) { 82 List toRemainL = null; 83 List toRemainT = null; 84 int startIndex = alignment == LEADING ? leadingIndex : leadingIndex - extractCount + 1; 85 int endIndex = alignment == LEADING ? trailingIndex + extractCount - 1 : trailingIndex; 86 Iterator it = seq.getSubIntervals(); 87 for (int idx=0; it.hasNext(); idx++) { 88 LayoutInterval li = (LayoutInterval) it.next(); 89 if (idx < startIndex) { 90 if (toRemainL == null) { 91 toRemainL = new LinkedList(); 92 toRemainL.add(new Integer (LayoutInterval.getEffectiveAlignment(li))); 93 } 94 toRemainL.add(li); 95 } 96 else if (idx > endIndex) { 97 if (toRemainT == null) { 98 toRemainT = new LinkedList(); 99 toRemainT.add(new Integer (LayoutInterval.getEffectiveAlignment(li))); 100 } 101 toRemainT.add(li); 102 } 103 } 104 if (toRemainL != null) { 105 it = toRemainL.iterator(); 106 it.next(); 107 do { 108 layoutModel.removeInterval((LayoutInterval)it.next()); 109 } 110 while (it.hasNext()); 111 restLeading.add(toRemainL); 112 } 113 if (toRemainT != null) { 114 it = toRemainT.iterator(); 115 it.next(); 116 do { 117 layoutModel.removeInterval((LayoutInterval)it.next()); 118 } 119 while (it.hasNext()); 120 restTrailing.add(toRemainT); 121 } 122 } 123 124 return extractCount; 125 } 126 127 140 LayoutInterval addGroupContent(List list, LayoutInterval seq, 141 int index, int dimension, int position) 142 { 143 assert seq.isSequential() && (position == LEADING || position == TRAILING); 144 boolean resizingFillGap = false; 145 LayoutInterval commonGap = null; 146 boolean onlyGaps = true; 147 148 for (int i=list.size()-1; i >= 0; i--) { 150 List subList = (List)list.get(i); 151 assert subList.size() >= 2; 152 if (subList.size() == 2) { LayoutInterval li = (LayoutInterval) subList.get(1); 154 if (li.isEmptySpace()) { 155 if (commonGap == null || li.getPreferredSize() > commonGap.getPreferredSize()) 156 commonGap = li; 157 if (LayoutInterval.canResize(li)) 158 resizingFillGap = true; 159 list.remove(i); 160 } 161 else onlyGaps = false; 162 } 163 else onlyGaps = false; 164 } 165 166 if (onlyGaps) { if (resizingFillGap && !LayoutInterval.canResize(commonGap)) 168 layoutModel.setIntervalSize(commonGap, NOT_EXPLICITLY_DEFINED, 169 commonGap.getPreferredSize(), 170 Short.MAX_VALUE); 171 insertGapIntoSequence(commonGap, seq, index, dimension); 172 return null; 173 } 174 175 if (list.size() == 1) { List subList = (List) list.get(0); 177 for (int n=subList.size(),i=n-1; i > 0; i--) { LayoutInterval li = (LayoutInterval) subList.get(i); 179 if (resizingFillGap && li.isEmptySpace() && !LayoutInterval.canResize(li) 180 && ((i == 1 && position == TRAILING) || (i == n-1 && position == LEADING))) 181 { layoutModel.setIntervalSize( 183 li, NOT_EXPLICITLY_DEFINED, li.getPreferredSize(), Short.MAX_VALUE); 184 } 185 if (i == 1 && li.isEmptySpace()) insertGapIntoSequence(li, seq, index, dimension); 187 else 188 layoutModel.addInterval(li, seq, index); 189 } 190 return null; 191 } 192 193 LayoutInterval group = new LayoutInterval(PARALLEL); 195 202 for (Iterator it=list.iterator(); it.hasNext(); ) { 204 List subList = (List) it.next(); 205 LayoutInterval interval; 206 if (subList.size() == 2) { int alignment = ((Integer )subList.get(0)).intValue(); 208 interval = (LayoutInterval) subList.get(1); 209 if (alignment == LEADING || alignment == TRAILING) 210 layoutModel.setIntervalAlignment(interval, alignment); 211 } 212 else { interval = new LayoutInterval(SEQUENTIAL); 214 int alignment = ((Integer )subList.get(0)).intValue(); 215 if (alignment == LEADING || alignment == TRAILING) 216 interval.setAlignment(alignment); 217 for (int i=1,n=subList.size(); i < n; i++) { 218 LayoutInterval li = (LayoutInterval) subList.get(i); 219 if (resizingFillGap && li.isEmptySpace() && !LayoutInterval.canResize(li) 220 && ((i == 1 && position == TRAILING) || (i == n-1 && position == LEADING))) 221 { layoutModel.setIntervalSize( 223 li, NOT_EXPLICITLY_DEFINED, li.getPreferredSize(), Short.MAX_VALUE); 224 } 225 layoutModel.addInterval(li, interval, -1); 226 } 227 } 228 layoutModel.addInterval(interval, group, -1); 229 } 230 231 layoutModel.addInterval(group, seq, index); 232 233 return group; 234 } 235 236 243 boolean addContent(LayoutInterval interval, LayoutInterval target, int index) { 244 if (interval.isGroup() && interval.getSubIntervalCount() == 1) { 245 return addContent(layoutModel.removeInterval(interval, 0), target, index); 246 } 247 248 if (interval.isSequential() && target.isSequential()) { 249 if (index < 0) { 250 index = target.getSubIntervalCount(); 251 } 252 while (interval.getSubIntervalCount() > 0) { 253 LayoutInterval li = layoutModel.removeInterval(interval, 0); 254 layoutModel.addInterval(li, target, index++); 255 } 256 return true; 257 } 258 else if (interval.isParallel() && target.isParallel()) { 259 int align = interval.getAlignment(); 260 if (align == DEFAULT) { 261 align = target.getGroupAlignment(); 262 } 263 boolean sameAlign = true; 264 Iterator it = interval.getSubIntervals(); 265 while (it.hasNext()) { 266 LayoutInterval li = (LayoutInterval) it.next(); 267 if (LayoutInterval.wantResize(li)) { sameAlign = true; 269 break; 270 } 271 if (li.getAlignment() != align) { 272 sameAlign = false; 273 } 274 } 275 276 if (sameAlign 277 && (LayoutInterval.canResize(interval) || !LayoutInterval.canResize(target) || !LayoutInterval.wantResize(target))) 278 { assert interval.getParent() == null; 280 while (interval.getSubIntervalCount() > 0) { 281 LayoutInterval li = interval.getSubInterval(0); 282 if (li.getRawAlignment() == DEFAULT 283 && interval.getGroupAlignment() != target.getGroupAlignment()) 284 { layoutModel.setIntervalAlignment(li, li.getAlignment()); 286 } 287 layoutModel.removeInterval(li); 288 layoutModel.addInterval(li, target, index); 289 if (index >= 0) 290 index++; 291 } 292 if (!LayoutInterval.canResize(interval) && LayoutInterval.canResize(target)) { 293 suppressGroupResizing(target); 294 } 295 return true; 296 } 297 else { layoutModel.addInterval(interval, target, index); 299 } 300 } 301 else { 302 if (target.isSequential() && interval.getRawAlignment() != DEFAULT) { 303 layoutModel.setIntervalAlignment(interval, DEFAULT); 304 } 305 layoutModel.addInterval(interval, target, index); 306 } 307 return false; 308 } 309 310 void resizeInterval(LayoutInterval interval, int size) { 311 assert size >= 0 || size == NOT_EXPLICITLY_DEFINED; 312 int min = (interval.getMinimumSize() == interval.getPreferredSize() 313 && interval.getMaximumSize() < Short.MAX_VALUE) ? 314 size : interval.getMinimumSize(); 315 int max = interval.getMaximumSize() == interval.getPreferredSize() ? 316 ((size == NOT_EXPLICITLY_DEFINED) ? USE_PREFERRED_SIZE : size) : interval.getMaximumSize(); 317 layoutModel.setIntervalSize(interval, min, size, max); 318 } 319 320 void suppressGroupResizing(LayoutInterval group) { 321 if (group.getParent() != null) { 323 layoutModel.setIntervalSize(group, group.getMinimumSize(), 324 group.getPreferredSize(), 325 USE_PREFERRED_SIZE); 326 } 327 } 328 329 void enableGroupResizing(LayoutInterval group) { 330 layoutModel.setIntervalSize(group, group.getMinimumSize(), 331 group.getPreferredSize(), 332 NOT_EXPLICITLY_DEFINED); 333 } 334 335 void mergeParallelGroups(LayoutInterval group) { 336 assert group.isParallel(); 337 if (!group.isParallel()) 338 return; 339 340 for (int i=group.getSubIntervalCount()-1; i >= 0; i--) { 341 LayoutInterval sub = group.getSubInterval(i); 342 if (sub.isParallel()) { 343 mergeParallelGroups(sub); 344 dissolveRedundantGroup(sub); 345 } 346 } 347 } 348 349 353 boolean dissolveRedundantGroup(LayoutInterval group) { 354 LayoutInterval parent = group.getParent(); 355 if (parent == null) 356 return false; 357 358 boolean dissolve = false; 359 if (group.getSubIntervalCount() == 1) { 360 dissolve = true; 361 } 362 else if (group.isSequential() && parent.isSequential()) { 363 dissolve = true; 364 } 365 else if (group.isParallel() && parent.isParallel()) { 366 int align = group.getAlignment(); 368 boolean sameAlign = true; 369 boolean subResizing = false; 370 Iterator it = group.getSubIntervals(); 371 while (it.hasNext()) { 372 LayoutInterval li = (LayoutInterval) it.next(); 373 if (!subResizing && LayoutInterval.wantResize(li)) { 374 subResizing = true; 375 } 376 if (li.getAlignment() != align && group.getSubIntervalCount() > 1) { 377 sameAlign = false; 378 } 379 } 380 boolean compatible; 381 if (subResizing && (sameAlign || group.getGroupAlignment() != BASELINE)) { 382 compatible = false; 383 if (LayoutInterval.canResize(group) || !LayoutInterval.canResize(parent)) { 384 it = parent.getSubIntervals(); 385 while (it.hasNext()) { 386 LayoutInterval li = (LayoutInterval) it.next(); 387 if (li != group && LayoutInterval.wantResize(li)) { 388 compatible = true; 389 break; 390 } 391 } 392 if (!compatible) { 393 LayoutInterval neighbor = LayoutInterval.getNeighbor( 394 parent, group.getAlignment()^1, false, true, true); 395 if (neighbor != null && neighbor.isEmptySpace() 396 && neighbor.getPreferredSize() == NOT_EXPLICITLY_DEFINED) 397 { compatible = true; 400 } 401 } 402 } 403 } 404 else compatible = sameAlign; 405 406 dissolve = compatible; 407 } 408 409 if (dissolve) { int index = layoutModel.removeInterval(group); 411 while (group.getSubIntervalCount() > 0) { 412 LayoutInterval li = group.getSubInterval(0); 413 if (parent.isParallel()) { if (group.isParallel()) { if (li.getRawAlignment() == DEFAULT 416 && group.getGroupAlignment() != parent.getGroupAlignment()) 417 { layoutModel.setIntervalAlignment(li, li.getAlignment()); 419 } 420 } 421 else { layoutModel.setIntervalAlignment(li, group.getRawAlignment()); 423 } 424 } 425 else { if (li.getRawAlignment() != DEFAULT) 427 layoutModel.setIntervalAlignment(li, DEFAULT); 428 } 429 layoutModel.removeInterval(li); 430 layoutModel.addInterval(li, parent, index++); 431 } 432 return true; 433 } 434 return false; 435 } 436 437 443 void moveInsideSequential(LayoutInterval parent, int dimension) { 444 assert parent.isSequential(); 445 if (!parent.isSequential()) 446 return; 447 448 int alignment = LEADING; 449 do { 450 LayoutInterval extend = findIntervalToExtend(parent, dimension, alignment); 451 if (extend == null) { 452 if (alignment == LEADING) { 453 alignment = TRAILING; 454 extend = findIntervalToExtend(parent, dimension, alignment); 455 } 456 if (extend == null) 457 break; 458 } 459 460 LayoutInterval inGroup = extend.getParent(); LayoutInterval outGroup = inGroup; 462 while (outGroup.getParent() != parent) { 463 outGroup = outGroup.getParent(); 464 } 465 int index = parent.indexOf(outGroup); 466 int d = alignment == LEADING ? -1 : 1; 467 468 boolean commonEndingGap = true; 470 for (int i=index-d, n=parent.getSubIntervalCount(); i >= 0 && i < n; i-=d) { 471 LayoutInterval li = parent.getSubInterval(i); 472 if ((!li.isEmptySpace() || (i-d >= 0 && i-d < n)) && LayoutInterval.wantResize(li)) 474 { LayoutInterval endGap = parent.getSubInterval(alignment == LEADING ? n-1 : 0); 477 if (endGap == null || endGap.getPreferredSize() != NOT_EXPLICITLY_DEFINED) { 478 commonEndingGap = false; 479 LayoutInterval closing = extend; 480 int borderPos = parent.getCurrentSpace().positions[dimension][alignment^1]; 481 do { 482 LayoutInterval par = closing.getParent(); 483 if (par.isParallel()) { 484 separateGroupContent(closing, borderPos, dimension, alignment^1); 485 } 486 closing = par; 487 } 488 while (closing != outGroup); 489 } 490 break; 491 } 492 } 493 494 int extendPos = extend.getCurrentSpace().positions[dimension][alignment^1]; 495 if (!extend.isSequential()) { 496 LayoutInterval seq = new LayoutInterval(SEQUENTIAL); 497 seq.setAlignment(extend.getAlignment()); 498 layoutModel.addInterval(seq, inGroup, layoutModel.removeInterval(extend)); 499 layoutModel.setIntervalAlignment(extend, DEFAULT); 500 layoutModel.addInterval(extend, seq, 0); 501 extend = seq; 502 } 503 504 LayoutInterval connectingGap = null; 506 int idx, addIdx; 507 if (alignment == LEADING) { 508 idx = index + 1; addIdx = extend.getSubIntervalCount(); } 511 else { 512 idx = index - 1; addIdx = 0; } 515 while (idx >= 0 && idx < parent.getSubIntervalCount()) { 516 LayoutInterval li = parent.getSubInterval(idx); 517 if (li.isEmptySpace()) { 518 if (connectingGap == null) { if (extendPos != outGroup.getCurrentSpace().positions[dimension][alignment^1]) { 520 int neighborPos = parent.getSubInterval(idx-d).getCurrentSpace().positions[dimension][alignment]; 522 int distance = d * (extendPos - neighborPos); 523 if (distance > 0) 524 resizeInterval(li, distance); 525 } 526 connectingGap = li; 527 } 528 else if ((idx == 0 || idx == parent.getSubIntervalCount()-1) 529 && commonEndingGap) 530 { break; 532 } 533 } 534 layoutModel.removeInterval(li); 535 layoutModel.addInterval(li, extend, addIdx); 536 if (alignment == LEADING) 537 addIdx++; 538 else 539 idx--; 540 } 541 542 if (parent.getSubIntervalCount() == 1) { assert outGroup == parent.getSubInterval(0); 545 layoutModel.removeInterval(outGroup); 546 LayoutInterval superParent = parent.getParent(); 547 addContent(outGroup, superParent, layoutModel.removeInterval(parent)); 548 break; 549 } 550 } 551 while (true); 552 } 553 554 private LayoutInterval findIntervalToExtend(LayoutInterval parent, int dimension, int alignment) { 555 int d = alignment == LEADING ? -1 : 1; 556 int count = parent.getSubIntervalCount(); 557 int idx = alignment == LEADING ? count-1 : 0; 558 boolean atBorder = true; 559 boolean gap = false; 560 561 while (idx >= 0 && idx < parent.getSubIntervalCount()) { 562 LayoutInterval sub = parent.getSubInterval(idx); 563 if (sub.isEmptySpace()) { 564 gap = true; 565 } 566 else { 567 if (!atBorder && gap && sub.isParallel() 568 && !LayoutInterval.isClosedGroup(sub, alignment^1)) 569 { int startIndex, endIndex; 571 if (alignment == LEADING) { 572 startIndex = idx + 1; 573 endIndex = parent.getSubIntervalCount() - 1; 574 } 575 else { 576 startIndex = 0; 577 endIndex = idx - 1; 578 } 579 LayoutInterval extend = prepareGroupExtension( 580 sub, parent, startIndex, endIndex, dimension, alignment^1); 581 if (extend != null) 582 return extend; 583 } 584 gap = false; 585 atBorder = false; 586 } 587 idx += d; 588 } 589 return null; 590 } 591 592 private LayoutInterval prepareGroupExtension(LayoutInterval group, 593 LayoutInterval parent, int startIndex, int endIndex, 594 int dimension, int alignment) 595 { 596 boolean allOverlapping = true; 597 LayoutInterval singleOverlap = null; 598 List overlapList = null; 599 600 Iterator it = group.getSubIntervals(); 602 while (it.hasNext()) { 603 LayoutInterval li = (LayoutInterval) it.next(); 604 if (!li.isEmptySpace()) { 605 if (LayoutUtils.contentOverlap(li, parent, startIndex, endIndex, dimension^1)) { 606 if (singleOverlap == null) { 608 singleOverlap = li; 609 } 610 else { 611 if (overlapList == null) { 612 overlapList = new LinkedList(); 613 overlapList.add(singleOverlap); 614 } 615 overlapList.add(li); 616 } 617 } 618 else allOverlapping = false; 619 } 620 } 621 622 if (allOverlapping || singleOverlap == null) 623 return null; 625 if (overlapList != null) { LayoutInterval subGroup = new LayoutInterval(PARALLEL); 627 subGroup.setGroupAlignment(alignment^1); 628 subGroup.setAlignment(alignment^1); 629 int index = -1; 630 do { 631 LayoutInterval li = (LayoutInterval) overlapList.remove(0); 632 int idx = layoutModel.removeInterval(li); 633 if (index < 0) { 634 index = idx; 635 } 636 layoutModel.addInterval(li, subGroup, -1); 637 subGroup.getCurrentSpace().expand(li.getCurrentSpace()); 638 } 639 while (overlapList.size() > 0); 640 641 layoutModel.addInterval(subGroup, group, index); 642 singleOverlap = subGroup; 643 } 644 else { 645 LayoutInterval subParallel; 646 if (singleOverlap.isSequential()) { 647 subParallel = singleOverlap.getSubInterval( 648 alignment == LEADING ? 0 : singleOverlap.getSubIntervalCount()-1); 649 if (!subParallel.isParallel()) 650 subParallel = null; 651 } 652 else if (singleOverlap.isParallel()) { 653 subParallel = singleOverlap; 654 } 655 else subParallel = null; 656 657 if (subParallel != null && !LayoutInterval.isClosedGroup(subParallel, alignment)) { 658 LayoutInterval subOverlap = prepareGroupExtension( 659 subParallel, parent, startIndex, endIndex, dimension, alignment); 660 if (subOverlap != null) 661 singleOverlap = subOverlap; 662 } 663 } 664 665 return singleOverlap; 666 } 667 668 private void separateGroupContent(LayoutInterval separate, int outPos, int dimension, int alignment) { 670 LayoutInterval group = separate.getParent(); 671 assert group.isParallel(); 672 LayoutInterval remainder = null; 673 LayoutInterval remainderGroup = null; 674 LayoutRegion remainderSpace = null; 675 676 for (int i=0; i < group.getSubIntervalCount(); ) { 677 LayoutInterval li = group.getSubInterval(i); 678 if (li != separate) { 679 assert li.getAlignment() == (alignment^1); 680 layoutModel.removeInterval(li); 681 if (remainder == null) { 682 remainder = li; 683 } 684 else { 685 if (remainderGroup == null) { 686 remainderGroup = new LayoutInterval(PARALLEL); 687 remainderGroup.setAlignment(alignment^1); 688 remainderGroup.setGroupAlignment(alignment^1); 689 layoutModel.addInterval(remainder, remainderGroup, 0); 690 remainder = remainderGroup; 691 } 692 layoutModel.addInterval(li, remainderGroup, -1); 693 } 694 if (!li.isEmptySpace()) { 695 if (remainderSpace == null) { 696 remainderSpace = new LayoutRegion(); 697 } 698 remainderSpace.expand(li.getCurrentSpace()); 699 } 700 } 701 else i++; 702 } 703 remainder.setCurrentSpace(remainderSpace); 704 705 LayoutInterval remainderGap; 706 int remainderPos = remainderSpace.positions[dimension][alignment]; 707 if (LayoutRegion.isValidCoordinate(outPos)) { 708 int gapSize = alignment == LEADING ? remainderPos - outPos : outPos - remainderPos; 709 remainderGap = new LayoutInterval(SINGLE); 710 remainderGap.setSizes(NOT_EXPLICITLY_DEFINED, gapSize, Short.MAX_VALUE); 711 } 712 else { remainderGap = LayoutInterval.getDirectNeighbor(group, alignment, false); 714 if (remainderGap != null && remainderGap.isEmptySpace()) { 715 layoutModel.removeInterval(remainderGap); 716 LayoutInterval neighbor = LayoutInterval.getDirectNeighbor(group, alignment, true); 718 outPos = neighbor != null ? 719 neighbor.getCurrentSpace().positions[dimension][alignment^1] : 720 group.getParent().getCurrentSpace().positions[dimension][alignment]; 721 int gapSize = alignment == LEADING ? remainderPos - outPos : outPos - remainderPos; 722 resizeInterval(remainderGap, gapSize); 723 } 724 else remainderGap = null; 725 } 726 if (remainderGap != null) { 727 LayoutInterval seq; 728 if (remainder.isSequential()) { 729 seq = remainder; 730 } 731 else { 732 seq = new LayoutInterval(SEQUENTIAL); 733 layoutModel.setIntervalAlignment(remainder, DEFAULT); 734 layoutModel.addInterval(remainder, seq, 0); 735 } 736 layoutModel.addInterval(remainderGap, seq, alignment == LEADING ? 0 : -1); 737 layoutModel.addInterval(seq, group, -1); 738 group.getCurrentSpace().positions[dimension][alignment] = outPos; 739 } 740 else { 741 layoutModel.addInterval(remainder, group, -1); 742 } 743 } 744 745 748 void parallelizeWithParentSequence(LayoutInterval interval, int endIndex, int dimension) { 749 LayoutInterval parent = interval.getParent(); 750 assert parent.isParallel(); 751 LayoutInterval parParent = parent; 752 while (!parParent.getParent().isSequential()) { 753 parParent = parParent.getParent(); 754 } 755 LayoutInterval parentSeq = parParent.getParent(); 756 757 int startIndex = parentSeq.indexOf(parParent); 758 if (endIndex < 0) 759 endIndex = parentSeq.getSubIntervalCount() - 1; 760 else if (startIndex > endIndex) { 761 int temp = startIndex; 762 startIndex = endIndex; 763 endIndex = temp; 764 } 765 766 layoutModel.removeInterval(interval); 767 if (interval.getAlignment() == DEFAULT) { 768 layoutModel.setIntervalAlignment(interval, parent.getGroupAlignment()); 769 } 770 addParallelWithSequence(interval, parentSeq, startIndex, endIndex, dimension); 771 772 if (parent.getSubIntervalCount() == 1) { 773 addContent(layoutModel.removeInterval(parent, 0), 774 parent.getParent(), 775 layoutModel.removeInterval(parent)); 776 } 777 else if (parent.getSubIntervalCount() == 0) { 778 layoutModel.removeInterval(parent); 779 } 780 } 781 782 void addParallelWithSequence(LayoutInterval interval, LayoutInterval seq, int startIndex, int endIndex, int dimension) { 783 LayoutInterval group; 784 if (startIndex > 0 || endIndex < seq.getSubIntervalCount()-1) { 785 group = new LayoutInterval(PARALLEL); 786 if (interval.getAlignment() != DEFAULT) { 787 group.setGroupAlignment(interval.getAlignment()); 788 } 789 int startPos = LayoutUtils.getVisualPosition(seq.getSubInterval(startIndex), dimension, LEADING); 790 int endPos = LayoutUtils.getVisualPosition(seq.getSubInterval(endIndex), dimension, TRAILING); 791 group.getCurrentSpace().set(dimension, startPos, endPos); 792 793 if (startIndex != endIndex) { 794 LayoutInterval subSeq = new LayoutInterval(SEQUENTIAL); 795 subSeq.setAlignment(seq.getAlignment()); 796 for (int n=endIndex-startIndex+1; n > 0; n--) { 797 layoutModel.addInterval(layoutModel.removeInterval(seq, startIndex), subSeq, -1); 798 } 799 layoutModel.addInterval(subSeq, group, 0); 800 } 801 else { 802 layoutModel.addInterval(layoutModel.removeInterval(seq, startIndex), group, 0); 803 } 804 layoutModel.addInterval(group, seq, startIndex); 805 } 806 else { 807 group = seq.getParent(); 808 } 809 layoutModel.addInterval(interval, group, -1); 810 } 811 812 int optimizeGaps(LayoutInterval group, int dimension) { 813 boolean anyAlignedLeading = false; boolean anyAlignedTrailing = false; boolean anyAlignedBoth = false; 816 boolean anyGapLeading = false; boolean anyGapTrailing = false; boolean sameMinGapLeading = true; boolean sameMinGapTrailing = true; int commonGapLeadingSize = Integer.MIN_VALUE; 821 int commonGapTrailingSize = Integer.MIN_VALUE; 822 823 for (int i=0; i < group.getSubIntervalCount(); i++) { 825 LayoutInterval li = group.getSubInterval(i); 826 if (li.isEmptySpace()) { if (group.getSubIntervalCount() > 1) { 828 layoutModel.removeInterval(group, i); 829 i--; 830 continue; 831 } 832 } 833 834 boolean leadingAlign = false; 835 boolean trailingAlign = false; 836 LayoutInterval leadingGap = null; 837 LayoutInterval trailingGap = null; 838 boolean contentResizing = false; 839 boolean noResizing = false; 840 if (li.isSequential()) { 841 boolean leadGapRes = false; 843 boolean trailGapRes = false; 844 for (int j=0; j < li.getSubIntervalCount(); j++) { 845 LayoutInterval sub = li.getSubInterval(j); 846 if (j == 0 && sub.isEmptySpace()) { 847 leadingGap = sub; 848 leadGapRes = LayoutInterval.wantResize(sub); 849 } 850 else if (j+1 == li.getSubIntervalCount() && sub.isEmptySpace()) { 851 trailingGap = sub; 852 trailGapRes = LayoutInterval.wantResize(sub); 853 } 854 else if (!contentResizing && LayoutInterval.wantResize(sub)) { 855 contentResizing = true; 856 } 857 } 858 if (!contentResizing) { 859 if (leadGapRes || trailGapRes) { 860 leadingAlign = trailGapRes && !leadGapRes; 861 trailingAlign = leadGapRes && !trailGapRes; 862 } 863 else noResizing = true; 864 } 865 } 866 else if (LayoutInterval.wantResize(li)) 867 contentResizing = true; 868 else 869 noResizing = true; 870 871 if (contentResizing) 872 leadingAlign = trailingAlign = true; 873 else if (noResizing) { 874 int alignment = li.getAlignment(); 875 leadingAlign = alignment == LEADING; 876 trailingAlign = alignment == TRAILING; 877 } 878 879 if (leadingAlign) { 880 anyAlignedLeading = true; 881 if (trailingAlign) 882 anyAlignedBoth = true; 883 } 884 if (trailingAlign) { 885 anyAlignedTrailing = true; 886 } 887 888 if (leadingGap != null) { 889 anyGapLeading = true; 890 if (sameMinGapLeading) { 891 int size = leadingAlign || leadingGap.getMinimumSize() == USE_PREFERRED_SIZE ? 892 leadingGap.getPreferredSize() : leadingGap.getMinimumSize(); 893 if (commonGapLeadingSize != Integer.MIN_VALUE) { 894 if (size != commonGapLeadingSize) 895 sameMinGapLeading = false; 896 } 897 else commonGapLeadingSize = size; 898 } 899 } 900 else sameMinGapLeading = false; 901 902 if (trailingGap != null) { 903 anyGapTrailing = true; 904 if (sameMinGapTrailing) { 905 int size = trailingAlign || trailingGap.getMinimumSize() == USE_PREFERRED_SIZE ? 906 trailingGap.getPreferredSize() : trailingGap.getMinimumSize(); 907 if (commonGapTrailingSize != Integer.MIN_VALUE) { 908 if (size != commonGapTrailingSize) 909 sameMinGapTrailing = false; 910 } 911 else commonGapTrailingSize = size; 912 } 913 } 914 else sameMinGapTrailing = false; 915 } 916 917 if (group.getSubIntervalCount() <= 1 || (!anyGapLeading && !anyGapTrailing)) { 918 return -1; 919 } 920 921 if (!anyAlignedBoth) { 922 if (anyAlignedTrailing) 924 sameMinGapLeading = false; 925 if (anyAlignedLeading) 926 sameMinGapTrailing = false; 927 } 928 929 int[] groupOuterPos = group.getCurrentSpace().positions[dimension]; 930 assert groupOuterPos[LEADING] > Short.MIN_VALUE && groupOuterPos[TRAILING] > Short.MIN_VALUE; 931 int groupInnerPosLeading = LayoutUtils.getOutermostComponent(group, dimension, LEADING) 932 .getCurrentSpace().positions[dimension][LEADING]; 933 int groupInnerPosTrailing = LayoutUtils.getOutermostComponent(group, dimension, TRAILING) 934 .getCurrentSpace().positions[dimension][TRAILING]; 935 936 boolean defaultPaddingLeading = false; boolean defaultPaddingTrailing = false; boolean resizingGapLeading = false; 939 boolean resizingGapTrailing = false; 940 941 for (int i=0; i < group.getSubIntervalCount(); i++) { 943 LayoutInterval li = group.getSubInterval(i); 944 if (li.isSequential()) { 945 if (anyGapLeading && (!anyAlignedLeading || sameMinGapLeading)) { 946 LayoutInterval gap = li.getSubInterval(0); 947 if (gap.isEmptySpace()) { 948 if (gap.getPreferredSize() == NOT_EXPLICITLY_DEFINED 949 && isEndingDefaultGapEffective(li, dimension, LEADING)) 950 { defaultPaddingLeading = true; 952 } 953 if (gap.getMaximumSize() >= Short.MAX_VALUE) { 954 if (li.getAlignment() == LEADING) layoutModel.setIntervalAlignment(li, TRAILING); 956 if (!anyAlignedLeading) resizingGapLeading = true; 958 } 959 layoutModel.removeInterval(gap); 960 } 961 } 962 963 if (anyGapTrailing && (!anyAlignedTrailing || sameMinGapTrailing)) { 964 LayoutInterval gap = li.getSubInterval(li.getSubIntervalCount() - 1); 965 if (gap.isEmptySpace()) { 966 if (gap.getPreferredSize() == NOT_EXPLICITLY_DEFINED 967 && isEndingDefaultGapEffective(li, dimension, TRAILING)) 968 { defaultPaddingTrailing = true; 970 } 971 if (gap.getMaximumSize() >= Short.MAX_VALUE) { 972 if (li.getAlignment() == TRAILING) layoutModel.setIntervalAlignment(li, LEADING); 974 if (!anyAlignedTrailing) resizingGapTrailing = true; 976 } 977 layoutModel.removeInterval(gap); 978 } 979 } 980 981 if (li.getSubIntervalCount() == 1) { 982 layoutModel.removeInterval(group, i); LayoutInterval sub = layoutModel.removeInterval(li, 0); layoutModel.setIntervalAlignment(sub, li.getRawAlignment()); 986 layoutModel.addInterval(sub, group, i); 987 } 988 } 989 } 990 991 LayoutInterval leadingGap = null; 992 LayoutInterval trailingGap = null; 993 994 if (anyGapLeading) { 995 if (!anyAlignedLeading) { int size = groupInnerPosLeading - groupOuterPos[LEADING]; 997 if (size > 0 || defaultPaddingLeading) { 998 leadingGap = new LayoutInterval(SINGLE); 999 if (!defaultPaddingLeading) { 1000 leadingGap.setPreferredSize(size); 1001 if (!resizingGapLeading) 1002 leadingGap.setMinimumSize(USE_PREFERRED_SIZE); 1003 } 1004 if (resizingGapLeading) { 1005 leadingGap.setMaximumSize(Short.MAX_VALUE); 1006 } 1007 } 1008 } 1009 else if (sameMinGapLeading) { 1010 leadingGap = new LayoutInterval(SINGLE); 1011 leadingGap.setSizes(commonGapLeadingSize, commonGapLeadingSize, USE_PREFERRED_SIZE); 1016 } 1017 } 1018 if (anyGapTrailing) { 1019 if (!anyAlignedTrailing) { int size = groupOuterPos[TRAILING] - groupInnerPosTrailing; 1021 if (size > 0 || defaultPaddingTrailing) { 1022 trailingGap = new LayoutInterval(SINGLE); 1023 if (!defaultPaddingTrailing) { 1024 trailingGap.setPreferredSize(size); 1025 if (!resizingGapTrailing) 1026 trailingGap.setMinimumSize(USE_PREFERRED_SIZE); 1027 } 1028 if (resizingGapTrailing) { 1029 trailingGap.setMaximumSize(Short.MAX_VALUE); 1030 } 1031 } 1032 } 1033 else if (sameMinGapTrailing) { 1034 trailingGap = new LayoutInterval(SINGLE); 1035 trailingGap.setSizes(commonGapTrailingSize, commonGapTrailingSize, USE_PREFERRED_SIZE); 1040 } 1041 } 1042 1043 if (leadingGap != null || trailingGap != null) { 1044 if (leadingGap != null || !LayoutRegion.isValidCoordinate(groupOuterPos[LEADING])) { 1045 groupOuterPos[LEADING] = groupInnerPosLeading; 1046 } 1047 if (trailingGap != null || !LayoutRegion.isValidCoordinate(groupOuterPos[TRAILING])) { 1048 groupOuterPos[TRAILING] = groupInnerPosTrailing; 1049 } 1050 groupOuterPos[CENTER] = (groupInnerPosLeading + groupInnerPosTrailing) / 2; 1051 if (leadingGap != null) { 1052 group = insertGap(leadingGap, group, groupInnerPosLeading, dimension, LEADING); 1053 } 1054 if (trailingGap != null) { 1055 group = insertGap(trailingGap, group, groupInnerPosTrailing, dimension, TRAILING); 1056 } 1057 LayoutInterval parent = group.getParent(); 1058 return parent != null ? parent.indexOf(group) : -1; } 1060 return -1; 1061 } 1062 1063 private boolean isEndingDefaultGapEffective(LayoutInterval seq, int dimension, int alignment) { 1064 assert seq.isSequential() && (alignment == LEADING || alignment == TRAILING); 1065 int idx = alignment == LEADING ? 0 : seq.getSubIntervalCount() - 1; 1066 int d = alignment == LEADING ? 1 : -1; 1067 LayoutInterval gap = seq.getSubInterval(idx); 1068 LayoutInterval neighbor = seq.getSubInterval(idx+d); 1069 1070 if (LayoutInterval.getEffectiveAlignment(neighbor, alignment) == alignment) { 1071 return true; } 1073 else { 1074 int prefDistance = LayoutUtils.getSizeOfDefaultGap(gap, visualMapper); 1075 int pos1 = neighbor.getCurrentSpace().positions[dimension][alignment]; 1076 LayoutInterval outerNeighbor = LayoutInterval.getNeighbor(gap, alignment, true, true, false); 1077 int pos2 = outerNeighbor != null ? 1078 outerNeighbor.getCurrentSpace().positions[dimension][alignment^1] : 1079 LayoutInterval.getRoot(seq).getCurrentSpace().positions[dimension][alignment]; 1080 int currentDistance = (pos1 - pos2) * d; 1081 return currentDistance <= prefDistance; 1082 } 1083 } 1084 1085 boolean cutStartingGap(LayoutInterval group, int size, int dimension, int alignment) { 1086 assert group.isGroup() && size > 0 && (alignment == LEADING || alignment == TRAILING); 1087 LayoutInterval seq = null; 1089 if (group.isSequential()) { 1090 seq = group; 1091 } 1092 else if (group.getSubIntervalCount() == 1) { 1093 LayoutInterval li = group.getSubInterval(0); 1094 if (li.isSequential() && LayoutInterval.isAlignedAtBorder(li, alignment)) 1095 seq = li; 1096 } 1097 if (seq != null && seq.getSubIntervalCount() > 1) { 1098 LayoutInterval gap = seq.getSubInterval(alignment == LEADING ? 0 : seq.getSubIntervalCount()-1); 1099 LayoutInterval neighbor = LayoutInterval.getDirectNeighbor(gap, alignment^1, true); 1100 if (gap != null && gap.isEmptySpace() && neighbor != null) { 1101 int currentSize = gap.getPreferredSize(); 1102 if (currentSize == NOT_EXPLICITLY_DEFINED) { 1103 currentSize = LayoutRegion.distance(group.getCurrentSpace(), neighbor.getCurrentSpace(), 1104 dimension, alignment, alignment) 1105 * (alignment == TRAILING ? -1 : 1); 1106 } 1107 if (currentSize >= size) { 1108 if (currentSize > size) 1109 resizeInterval(gap, currentSize - size); 1110 else 1111 layoutModel.removeInterval(gap); 1112 return true; 1113 } 1114 } 1115 } 1116 return false; 1117 } 1118 1119 1130 LayoutInterval insertGap(LayoutInterval gap, LayoutInterval interval, int pos, int dimension, int alignment) { 1131 assert alignment == LEADING || alignment == TRAILING; 1132 assert !interval.isSequential(); 1133 assert gap.isEmptySpace(); 1134 1135 LayoutInterval parent = interval.getParent(); 1136 if (parent == null) { 1137 assert interval.isParallel(); 1138 parent = interval; 1139 if (parent.getSubIntervalCount() > 1) { 1140 LayoutInterval seq = new LayoutInterval(SEQUENTIAL); 1141 seq.getCurrentSpace().set(dimension, 1142 (alignment == LEADING) ? pos : interval.getCurrentSpace().positions[dimension][LEADING], 1143 (alignment == LEADING) ? interval.getCurrentSpace().positions[dimension][TRAILING] : pos); 1144 layoutModel.addInterval(seq, parent, -1); 1145 interval = new LayoutInterval(PARALLEL); 1146 interval.getCurrentSpace().set(dimension, parent.getCurrentSpace()); 1147 layoutModel.addInterval(interval, seq, 0); 1148 while (parent.getSubIntervalCount() > 1) { 1149 layoutModel.addInterval(layoutModel.removeInterval(parent, 0), interval, -1); 1150 } 1151 parent = seq; 1152 } 1153 else { 1154 interval = parent.getSubInterval(0); 1155 if (interval.isSequential()) { 1156 parent = interval; 1157 int subIdx = alignment == LEADING ? 0 : parent.getSubIntervalCount()-1; 1158 interval = parent.getSubInterval(subIdx); 1159 if (interval.isEmptySpace()) { 1160 subIdx += alignment == LEADING ? 1 : -1; 1161 LayoutInterval neighbor = subIdx >= 0 && subIdx < parent.getSubIntervalCount() ? 1162 parent.getSubInterval(subIdx) : null; 1163 int[] outerSpace = parent.getParent().getCurrentSpace().positions[dimension]; 1164 int otherPos = neighbor != null ? neighbor.getCurrentSpace().positions[dimension][alignment] : 1165 outerSpace[alignment^1]; 1166 int mergedSize = (outerSpace[alignment] - otherPos) * (alignment == LEADING ? -1 : 1); 1167 eatGap(interval, gap, mergedSize); 1168 return neighbor != null ? neighbor : interval; 1169 } 1170 } 1171 else { 1172 LayoutInterval seq = new LayoutInterval(SEQUENTIAL); 1173 seq.getCurrentSpace().set(dimension, 1174 (alignment == LEADING) ? pos : interval.getCurrentSpace().positions[dimension][LEADING], 1175 (alignment == LEADING) ? interval.getCurrentSpace().positions[dimension][TRAILING] : pos); 1176 layoutModel.addInterval(seq, parent, -1); 1177 layoutModel.removeInterval(interval); 1178 layoutModel.addInterval(interval, seq, -1); 1179 parent = seq; 1180 } 1181 } 1182 } 1183 if (parent.isSequential()) { 1184 LayoutInterval neighbor = LayoutInterval.getDirectNeighbor(interval, alignment, false); 1186 if (neighbor != null && neighbor.isEmptySpace()) { 1187 LayoutInterval next = LayoutInterval.getDirectNeighbor(neighbor, alignment, false); 1188 int otherPos = next != null ? next.getCurrentSpace().positions[dimension][alignment^1] : 1189 parent.getCurrentSpace().positions[dimension][alignment]; 1190 int mergedSize = (pos - otherPos) * (alignment == LEADING ? 1 : -1); 1191 eatGap(neighbor, gap, mergedSize); 1192 } 1193 else { 1194 int idx = parent.indexOf(interval) + (alignment == LEADING ? 0 : 1); 1195 layoutModel.addInterval(gap, parent, idx); 1196 } 1197 } 1198 else { LayoutInterval seq = new LayoutInterval(SEQUENTIAL); 1200 int idx = layoutModel.removeInterval(interval); 1201 seq.setAlignment(interval.getAlignment()); 1202 seq.getCurrentSpace().set(dimension, 1203 (alignment == LEADING) ? pos : interval.getCurrentSpace().positions[dimension][LEADING], 1204 (alignment == LEADING) ? interval.getCurrentSpace().positions[dimension][TRAILING] : pos); 1205 layoutModel.addInterval(seq, parent, idx); 1206 layoutModel.setIntervalAlignment(interval, DEFAULT); 1207 layoutModel.addInterval(interval, seq, 0); 1208 layoutModel.addInterval(gap, seq, alignment == LEADING ? 0 : 1); 1209 } 1210 1211 return interval; 1212 } 1213 1214 int insertGapIntoSequence(LayoutInterval gap, LayoutInterval seq, int index, int dimension) { 1215 assert gap.isEmptySpace(); 1216 LayoutInterval otherGap = null; 1217 int alignment = DEFAULT; 1218 if (index >= 0 && index < seq.getSubIntervalCount()) { 1219 otherGap = seq.getSubInterval(index); 1220 if (otherGap.isEmptySpace()) 1221 alignment = TRAILING; 1222 } 1223 if (alignment == DEFAULT && index > 0) { 1224 otherGap = seq.getSubInterval(index-1); 1225 if (otherGap.isEmptySpace()) 1226 alignment = LEADING; 1227 } 1228 if (alignment == DEFAULT) { 1229 layoutModel.addInterval(gap, seq, index); 1230 return index; } 1232 1233 int pos1, pos2; 1234 LayoutInterval neighbor = LayoutInterval.getDirectNeighbor(otherGap, alignment, true); 1235 pos1 = neighbor != null ? 1236 neighbor.getCurrentSpace().positions[dimension][alignment^1] : 1237 seq.getCurrentSpace().positions[dimension][alignment]; 1238 neighbor = LayoutInterval.getDirectNeighbor(otherGap, alignment^1, true); 1239 pos2 = neighbor != null ? 1240 neighbor.getCurrentSpace().positions[dimension][alignment] : 1241 seq.getCurrentSpace().positions[dimension][alignment^1]; 1242 1243 eatGap(otherGap, gap, Math.abs(pos2 - pos1)); 1244 return alignment == LEADING ? index-1 : index; } 1246 1247 void eatGap(LayoutInterval main, LayoutInterval eaten, int currentMergedSize) { 1248 int min; 1249 int min1 = main.getMinimumSize(); 1250 if (min1 == USE_PREFERRED_SIZE) 1251 min1 = main.getPreferredSize(); 1252 int min2 = eaten.getMinimumSize(); 1253 if (min2 == USE_PREFERRED_SIZE) 1254 min2 = eaten.getPreferredSize(); 1255 1256 if (min1 == 0) 1257 min = min2; 1258 else if (min2 == 0) 1259 min = min1; 1260 else if (!LayoutInterval.canResize(main) && !LayoutInterval.canResize(eaten)) 1261 min = USE_PREFERRED_SIZE; 1262 else if (min1 == NOT_EXPLICITLY_DEFINED || min2 == NOT_EXPLICITLY_DEFINED) 1263 min = NOT_EXPLICITLY_DEFINED; 1264 else 1265 min = min1 + min2; 1266 1267 int pref; 1268 int pref1 = main.getPreferredSize(); 1269 int pref2 = eaten.getPreferredSize(); 1270 1271 if (pref1 == 0) 1272 pref = pref2; 1273 else if (pref2 == 0) 1274 pref = pref1; 1275 else if (pref1 == NOT_EXPLICITLY_DEFINED || pref2 == NOT_EXPLICITLY_DEFINED) 1276 pref = currentMergedSize; 1277 else 1278 pref = pref1 + pref2; 1279 1280 int max = main.getMaximumSize() >= Short.MAX_VALUE || eaten.getMaximumSize() >= Short.MAX_VALUE ? 1281 Short.MAX_VALUE : USE_PREFERRED_SIZE; 1282 1283 layoutModel.setIntervalSize(main, min, pref, max); 1284 if (eaten.getParent() != null) { 1285 layoutModel.removeInterval(eaten); 1286 } 1287 } 1288 1289 void mergeAdjacentGaps(Set updatedContainers) { 1290 Iterator it = layoutModel.getAllComponents(); 1291 while (it.hasNext()) { 1292 LayoutComponent comp = (LayoutComponent) it.next(); 1293 if (!comp.isLayoutContainer()) 1294 continue; 1295 1296 boolean updated = false; 1297 for (int dim=0; dim<DIM_COUNT; dim++) { 1298 LayoutInterval interval = comp.getLayoutRoot(dim); 1299 updated = updated || mergeAdjacentGaps(interval, dim); 1300 } 1301 if (updated) { 1302 updatedContainers.add(comp); 1303 } 1304 } 1305 } 1306 1307 boolean mergeAdjacentGaps(LayoutInterval root, int dimension) { 1308 assert root.isGroup(); 1309 boolean updated = false; 1310 if (root.isSequential()) { 1311 for (int i=0; i<root.getSubIntervalCount(); i++) { 1312 LayoutInterval interval = root.getSubInterval(i); 1313 if (interval.isEmptySpace() && ((i+1) < root.getSubIntervalCount())) { 1314 LayoutInterval next = root.getSubInterval(i+1); 1315 if (next.isEmptySpace()) { 1316 if ((i+2) < root.getSubIntervalCount()) { 1317 LayoutInterval nextNext = root.getSubInterval(i+2); 1318 if (nextNext.isEmptySpace()) { 1319 i--; } 1321 } 1322 updated = true; 1323 eatGap(interval, next, NOT_EXPLICITLY_DEFINED); 1324 } 1325 } 1326 } 1327 } 1328 Iterator iter = root.getSubIntervals(); 1329 while (iter.hasNext()) { 1330 LayoutInterval subInterval = (LayoutInterval)iter.next(); 1331 if (subInterval.isGroup()) { 1332 updated = updated || mergeAdjacentGaps(subInterval, dimension); 1333 } 1334 } 1335 return updated; 1336 } 1337 1338 void suppressResizingOfSurroundingGaps(LayoutInterval interval) { 1339 LayoutInterval parent = interval.getParent(); 1340 while (parent != null) { 1341 if (parent.isSequential()) { 1342 for (Iterator it=parent.getSubIntervals(); it.hasNext(); ) { 1343 LayoutInterval sub = (LayoutInterval) it.next(); 1344 if (sub != interval && sub.isEmptySpace() && LayoutInterval.canResize(sub)) { 1345 int pref = sub.getPreferredSize(); 1346 int min = sub.getMinimumSize() != pref ? USE_PREFERRED_SIZE : pref; 1347 int max = USE_PREFERRED_SIZE; 1348 layoutModel.setIntervalSize(sub, min, pref, max); 1349 } 1350 } 1351 } 1352 else if (!LayoutInterval.canResize(parent)) 1353 break; 1354 interval = parent; 1355 parent = interval.getParent(); 1356 } 1357 } 1358} 1359 | Popular Tags |