2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.modules.form.layoutdesign;
47
* This class serves as a library of various useful and well-defined operations
48
* on the layout model.
53
class LayoutOperations implements LayoutConstants {
55
private LayoutModel layoutModel;
57
private VisualMapper visualMapper;
59
LayoutOperations(LayoutModel model, VisualMapper mapper) {
61
visualMapper = mapper;
64
LayoutModel getModel() {
68
VisualMapper getMapper() {
75
* Extracts surroundings of given interval (placed in a sequential group).
76
* Extracted intervals are removed and go to the 'restLeading' and
77
* 'restTrailing' lists. Does not extract/remove the interval itself.
79
int extract(LayoutInterval interval, int alignment, boolean closed,
80
List restLeading, List restTrailing) {
81
return extract(interval, interval, alignment, closed, restLeading, restTrailing);
84
int extract(LayoutInterval leading, LayoutInterval trailing, int alignment, boolean closed,
85
List restLeading, List restTrailing)
87
LayoutInterval seq = leading.getParent();
88
assert seq.isSequential();
90
int leadingIndex = seq.indexOf(leading);
91
int trailingIndex = seq.indexOf(trailing);
92
int count = seq.getSubIntervalCount();
95
extractCount = trailingIndex - leadingIndex + 1;
96
} else if (alignment != LEADING && alignment != TRAILING) {
100
extractCount = alignment == LEADING ? count - leadingIndex : leadingIndex + 1;
103
if (extractCount < seq.getSubIntervalCount()) {
104
List toRemainL = null;
105
List toRemainT = null;
106
int startIndex = alignment == LEADING ? leadingIndex : leadingIndex - extractCount + 1;
107
int endIndex = alignment == LEADING ? trailingIndex + extractCount - 1 : trailingIndex;
108
Iterator it = seq.getSubIntervals();
109
for (int idx=0; it.hasNext(); idx++) {
110
LayoutInterval li = (LayoutInterval) it.next();
111
if (idx < startIndex) {
112
if (toRemainL == null) {
113
toRemainL = new LinkedList();
114
toRemainL.add(new Integer(LayoutInterval.getEffectiveAlignment(li)));
118
else if (idx > endIndex) {
119
if (toRemainT == null) {
120
toRemainT = new LinkedList();
121
toRemainT.add(new Integer(LayoutInterval.getEffectiveAlignment(li)));
126
if (toRemainL != null) {
127
it = toRemainL.iterator();
130
layoutModel.removeInterval((LayoutInterval)it.next());
132
while (it.hasNext());
133
restLeading.add(toRemainL);
135
if (toRemainT != null) {
136
it = toRemainT.iterator();
139
layoutModel.removeInterval((LayoutInterval)it.next());
141
while (it.hasNext());
142
restTrailing.add(toRemainT);
150
* Adds parallel content of a group specified in List to given sequence.
151
* Used to create a remainder parallel group to a group of aligned intervals.
152
* @param list the content of the group, output from 'extract' method
153
* @param seq a sequential group where to add to
154
* @param index the index in the sequence where to add
156
* @param position the position of the remainder group relative to the main
157
* group (LEADING or TRAILING)
158
// * @param mainAlignment effective alignment of the main group (LEADING or
159
// * TRAILING or something else meaning not aligned)
160
* @return parallel group if it has been created, or null
162
LayoutInterval addGroupContent(List list, LayoutInterval seq,
163
int index, int dimension, int position/*, int mainAlignment*/)
165
assert seq.isSequential() && (position == LEADING || position == TRAILING);
166
boolean resizingFillGap = false;
167
LayoutInterval commonGap = null;
168
boolean onlyGaps = true;
170
// Remove sequences just with one gap
171
for (int i=list.size()-1; i >= 0; i--) {
172
List subList = (List)list.get(i);
173
assert subList.size() >= 2;
174
if (subList.size() == 2) { // there is just one interval
175
LayoutInterval li = (LayoutInterval) subList.get(1);
176
if (li.isEmptySpace()) {
177
if (commonGap == null || li.getPreferredSize() > commonGap.getPreferredSize())
179
if (LayoutInterval.canResize(li))
180
resizingFillGap = true;
183
else onlyGaps = false;
185
else onlyGaps = false;
188
if (onlyGaps) { // just one gap
189
if (resizingFillGap && !LayoutInterval.canResize(commonGap))
190
layoutModel.setIntervalSize(commonGap, NOT_EXPLICITLY_DEFINED,
191
commonGap.getPreferredSize(),
193
insertGapIntoSequence(commonGap, seq, index, dimension);
197
if (list.size() == 1) { // just one sequence
198
List subList = (List) list.get(0);
199
for (int n=subList.size(),i=n-1; i > 0; i--) { // skip alignment at 0
200
LayoutInterval li = (LayoutInterval) subList.get(i);
201
if (resizingFillGap && li.isEmptySpace() && !LayoutInterval.canResize(li)
202
&& ((i == 1 && position == TRAILING) || (i == n-1 && position == LEADING)))
203
{ // make the end gap resizing
204
layoutModel.setIntervalSize(
205
li, NOT_EXPLICITLY_DEFINED, li.getPreferredSize(), Short.MAX_VALUE);
207
if (i == 1 && li.isEmptySpace()) // first gap
208
insertGapIntoSequence(li, seq, index, dimension);
210
layoutModel.addInterval(li, seq, index);
215
// create parallel group for multiple intervals/sequences
216
LayoutInterval group = new LayoutInterval(PARALLEL);
217
// if (position == mainAlignment) {
218
// // [but this should eliminate resizability only for gaps...]
219
// group.setMinimumSize(USE_PREFERRED_SIZE);
220
// group.setMaximumSize(USE_PREFERRED_SIZE);
222
//// group.setGroupAlignment(alignment);
225
for (Iterator it=list.iterator(); it.hasNext(); ) {
226
List subList = (List) it.next();
227
LayoutInterval interval;
228
if (subList.size() == 2) { // there is just one interval - use it directly
229
int alignment = ((Integer)subList.get(0)).intValue();
230
interval = (LayoutInterval) subList.get(1);
231
if (alignment == LEADING || alignment == TRAILING)
232
layoutModel.setIntervalAlignment(interval, alignment);
234
else { // there are more intervals - create sequence
235
interval = new LayoutInterval(SEQUENTIAL);
236
int alignment = ((Integer)subList.get(0)).intValue();
237
if (alignment == LEADING || alignment == TRAILING)
238
interval.setAlignment(alignment);
239
for (int i=1,n=subList.size(); i < n; i++) {
240
LayoutInterval li = (LayoutInterval) subList.get(i);
241
if (resizingFillGap && li.isEmptySpace() && !LayoutInterval.canResize(li)
242
&& ((i == 1 && position == TRAILING) || (i == n-1 && position == LEADING)))
243
{ // make the end gap resizing
244
layoutModel.setIntervalSize(
245
li, NOT_EXPLICITLY_DEFINED, li.getPreferredSize(), Short.MAX_VALUE);
247
layoutModel.addInterval(li, interval, -1);
250
layoutModel.addInterval(interval, group, -1);
253
layoutModel.addInterval(group, seq, index);
259
* Adds 'interval' to 'target'. In case of 'interval' is a group, it is
260
* dismounted to individual intervals if needed (e.g. if adding sequence to
261
* sequence), or if producing equal result with less nesting (e.g. when
262
* adding parallel group to parallel group with same alignment).
263
* Also redundant groups are canceled (containing just one interval).
265
boolean addContent(LayoutInterval interval, LayoutInterval target, int index) {
266
if (interval.isGroup() && interval.getSubIntervalCount() == 1) {
267
return addContent(layoutModel.removeInterval(interval, 0), target, index);
270
if (interval.isSequential() && target.isSequential()) {
272
index = target.getSubIntervalCount();
274
while (interval.getSubIntervalCount() > 0) {
275
LayoutInterval li = layoutModel.removeInterval(interval, 0);
276
layoutModel.addInterval(li, target, index++);
280
else if (interval.isParallel() && target.isParallel()) {
281
int align = interval.getAlignment();
282
if (align == DEFAULT) {
283
align = target.getGroupAlignment();
285
boolean sameAlign = true;
286
Iterator it = interval.getSubIntervals();
287
while (it.hasNext()) {
288
LayoutInterval li = (LayoutInterval) it.next();
289
if (LayoutInterval.wantResize(li)) { // will span over whole target group
293
if (li.getAlignment() != align) {
299
&& (LayoutInterval.canResize(interval) || !LayoutInterval.canResize(target) || !LayoutInterval.wantResize(target)))
300
{ // can dismantle the group
301
assert interval.getParent() == null;
302
while (interval.getSubIntervalCount() > 0) {
303
LayoutInterval li = interval.getSubInterval(0);
304
if (li.getRawAlignment() == DEFAULT
305
&& interval.getGroupAlignment() != target.getGroupAlignment())
306
{ // force alignment explicitly
307
layoutModel.setIntervalAlignment(li, li.getAlignment());
309
layoutModel.removeInterval(li);
310
layoutModel.addInterval(li, target, index);
314
if (!LayoutInterval.canResize(interval) && LayoutInterval.canResize(target)) {
315
suppressGroupResizing(target);
319
else { // need to add the group as a whole
320
layoutModel.addInterval(interval, target, index);
324
if (target.isSequential() && interval.getRawAlignment() != DEFAULT) {
325
layoutModel.setIntervalAlignment(interval, DEFAULT);
327
layoutModel.addInterval(interval, target, index);
332
void resizeInterval(LayoutInterval interval, int size) {
333
assert size >= 0 || size == NOT_EXPLICITLY_DEFINED;
334
int min = (interval.getMinimumSize() == interval.getPreferredSize()
335
&& interval.getMaximumSize() < Short.MAX_VALUE) ?
336
size : interval.getMinimumSize();
337
int max = interval.getMaximumSize() == interval.getPreferredSize() ?
338
((size == NOT_EXPLICITLY_DEFINED) ? USE_PREFERRED_SIZE : size) : interval.getMaximumSize();
339
layoutModel.setIntervalSize(interval, min, size, max);
342
void suppressGroupResizing(LayoutInterval group) {
343
// don't for root group
344
if (group.getParent() != null) {
345
layoutModel.setIntervalSize(group, group.getMinimumSize(),
346
group.getPreferredSize(),
351
void enableGroupResizing(LayoutInterval group) {
352
layoutModel.setIntervalSize(group, group.getMinimumSize(),
353
group.getPreferredSize(),
354
NOT_EXPLICITLY_DEFINED);
357
void mergeParallelGroups(LayoutInterval group) {
358
assert group.isParallel();
359
if (!group.isParallel())
362
for (int i=group.getSubIntervalCount()-1; i >= 0; i--) {
363
LayoutInterval sub = group.getSubInterval(i);
364
if (sub.isParallel()) {
365
mergeParallelGroups(sub);
366
dissolveRedundantGroup(sub);
372
* Dissolves given group to parent group in case it is redundant.
373
* @return true if the group was dissolved
375
boolean dissolveRedundantGroup(LayoutInterval group) {
376
LayoutInterval parent = group.getParent();
380
boolean dissolve = false;
381
if (group.getSubIntervalCount() == 1) {
384
else if (group.isSequential() && parent.isSequential()) {
387
else if (group.isParallel() && parent.isParallel()) {
388
// check for compatible alignment and resizability
389
int align = group.getAlignment();
390
boolean sameAlign = true;
391
boolean subResizing = false;
392
Iterator it = group.getSubIntervals();
393
while (it.hasNext()) {
394
LayoutInterval li = (LayoutInterval) it.next();
395
if (!subResizing && LayoutInterval.wantResize(li)) {
398
if (li.getAlignment() != align && group.getSubIntervalCount() > 1) {
403
if (subResizing && (sameAlign || group.getGroupAlignment() != BASELINE)) {
405
if (LayoutInterval.canResize(group) || !LayoutInterval.canResize(parent)) {
406
it = parent.getSubIntervals();
407
while (it.hasNext()) {
408
LayoutInterval li = (LayoutInterval) it.next();
409
if (li != group && LayoutInterval.wantResize(li)) {
415
LayoutInterval neighbor = LayoutInterval.getNeighbor(
416
parent, group.getAlignment()^1, false, true, true);
417
if (neighbor != null && neighbor.isEmptySpace()
418
&& neighbor.getPreferredSize() == NOT_EXPLICITLY_DEFINED)
419
{ // default fixed padding means there is no space for
420
// independent size change, so the subgroup can be merged
426
else compatible = sameAlign;
428
dissolve = compatible;
431
if (dissolve) { // the sub-group can be dissolved into parent group
432
int index = layoutModel.removeInterval(group);
433
while (group.getSubIntervalCount() > 0) {
434
LayoutInterval li = group.getSubInterval(0);
435
if (parent.isParallel()) { // moving to parallel group
436
if (group.isParallel()) { // from parallel group
437
if (li.getRawAlignment() == DEFAULT
438
&& group.getGroupAlignment() != parent.getGroupAlignment())
439
{ // force alignment explicitly
440
layoutModel.setIntervalAlignment(li, li.getAlignment());
443
else { // from sequential group
444
layoutModel.setIntervalAlignment(li, group.getRawAlignment());
447
else { // moving to sequential group
448
if (li.getRawAlignment() != DEFAULT)
449
layoutModel.setIntervalAlignment(li, DEFAULT);
451
layoutModel.removeInterval(li);
452
layoutModel.addInterval(li, parent, index++);
460
* This method goes through a sequential group and moves each interval next
461
* to an open edge of a parallel group into the group.
462
* @param parent sequential group to process
465
void moveInsideSequential(LayoutInterval parent, int dimension) {
466
assert parent.isSequential();
467
if (!parent.isSequential())
470
int alignment = LEADING;
472
LayoutInterval extend = findIntervalToExtend(parent, dimension, alignment);
473
if (extend == null) {
474
if (alignment == LEADING) {
475
alignment = TRAILING;
476
extend = findIntervalToExtend(parent, dimension, alignment);
482
LayoutInterval inGroup = extend.getParent(); // group to infiltrate
483
LayoutInterval outGroup = inGroup;
484
while (outGroup.getParent() != parent) {
485
outGroup = outGroup.getParent();
487
int index = parent.indexOf(outGroup);
488
int d = alignment == LEADING ? -1 : 1;
490
// will the group remain open at the opposite edge?
491
boolean commonEndingGap = true;
492
for (int i=index-d, n=parent.getSubIntervalCount(); i >= 0 && i < n; i-=d) {
493
LayoutInterval li = parent.getSubInterval(i);
494
if ((!li.isEmptySpace() || (i-d >= 0 && i-d < n)) // ignore last gap
495
&& LayoutInterval.wantResize(li))
496
{ // resizing interval will close the group
497
// possibly need to separate the rest of the group not to be influenced
498
LayoutInterval endGap = parent.getSubInterval(alignment == LEADING ? n-1 : 0);
499
if (endGap == null || endGap.getPreferredSize() != NOT_EXPLICITLY_DEFINED) {
500
commonEndingGap = false;
501
LayoutInterval closing = extend;
502
int borderPos = parent.getCurrentSpace().positions[dimension][alignment^1];
504
LayoutInterval par = closing.getParent();
505
if (par.isParallel()) {
506
separateGroupContent(closing, borderPos, dimension, alignment^1);
510
while (closing != outGroup);
516
int extendPos = extend.getCurrentSpace().positions[dimension][alignment^1];
517
if (!extend.isSequential()) {
518
LayoutInterval seq = new LayoutInterval(SEQUENTIAL);
519
seq.setAlignment(extend.getAlignment());
520
layoutModel.addInterval(seq, inGroup, layoutModel.removeInterval(extend));
521
layoutModel.setIntervalAlignment(extend, DEFAULT);
522
layoutModel.addInterval(extend, seq, 0);
526
// move the intervals from outside inside the group, next to found interval (extend)
527
LayoutInterval connectingGap = null;
529
if (alignment == LEADING) {
530
idx = index + 1; // start behind the group
531
addIdx = extend.getSubIntervalCount(); // add behind the interval
534
idx = index - 1; // start before the group
535
addIdx = 0; // add before the interval
537
while (idx >= 0 && idx < parent.getSubIntervalCount()) {
538
LayoutInterval li = parent.getSubInterval(idx);
539
if (li.isEmptySpace()) {
540
if (connectingGap == null) { // first gap
541
if (extendPos != outGroup.getCurrentSpace().positions[dimension][alignment^1]) {
542
// need to extend the first gap (extended interval inside group is smaller than the group)
543
int neighborPos = parent.getSubInterval(idx-d).getCurrentSpace().positions[dimension][alignment];
544
int distance = d * (extendPos - neighborPos);
546
resizeInterval(li, distance);
550
else if ((idx == 0 || idx == parent.getSubIntervalCount()-1)
552
{ // keep the last gap out
556
layoutModel.removeInterval(li);
557
layoutModel.addInterval(li, extend, addIdx);
558
if (alignment == LEADING)
564
// check if the sequence was not whole moved into the group
565
if (parent.getSubIntervalCount() == 1) { // only neighborGroup remained, eliminate the parent group
566
assert outGroup == parent.getSubInterval(0);
567
layoutModel.removeInterval(outGroup);
568
LayoutInterval superParent = parent.getParent();
569
addContent(outGroup, superParent, layoutModel.removeInterval(parent));
576
private LayoutInterval findIntervalToExtend(LayoutInterval parent, int dimension, int alignment) {
577
int d = alignment == LEADING ? -1 : 1;
578
int count = parent.getSubIntervalCount();
579
int idx = alignment == LEADING ? count-1 : 0;
580
boolean atBorder = true;
583
while (idx >= 0 && idx < parent.getSubIntervalCount()) {
584
LayoutInterval sub = parent.getSubInterval(idx);
585
if (sub.isEmptySpace()) {
589
if (!atBorder && gap && sub.isParallel()
590
&& !LayoutInterval.isClosedGroup(sub, alignment^1))
591
{ // this open parallel sub-group might be a candidate to move inside to
592
int startIndex, endIndex;
593
if (alignment == LEADING) {
594
startIndex = idx + 1;
595
endIndex = parent.getSubIntervalCount() - 1;
601
LayoutInterval extend = prepareGroupExtension(
602
sub, parent, startIndex, endIndex, dimension, alignment^1);
614
private LayoutInterval prepareGroupExtension(LayoutInterval group,
615
LayoutInterval parent, int startIndex, int endIndex,
616
int dimension, int alignment)
618
boolean allOverlapping = true;
619
LayoutInterval singleOverlap = null;
620
List overlapList = null;
622
// looking for all intervals the given space is located next to
623
Iterator it = group.getSubIntervals();
624
while (it.hasNext()) {
625
LayoutInterval li = (LayoutInterval) it.next();
626
if (!li.isEmptySpace()) {
627
if (LayoutUtils.contentOverlap(li, parent, startIndex, endIndex, dimension^1)) {
628
// interval overlaps orthogonally
629
if (singleOverlap == null) {
633
if (overlapList == null) {
634
overlapList = new LinkedList();
635
overlapList.add(singleOverlap);
640
else allOverlapping = false;
644
if (allOverlapping || singleOverlap == null)
645
return null; // spans whole group or nothing
647
if (overlapList != null) { // overlaps multiple intervals
648
LayoutInterval subGroup = new LayoutInterval(PARALLEL);
649
subGroup.setGroupAlignment(alignment^1);
650
subGroup.setAlignment(alignment^1);
653
LayoutInterval li = (LayoutInterval) overlapList.remove(0);
654
int idx = layoutModel.removeInterval(li);
658
layoutModel.addInterval(li, subGroup, -1);
659
subGroup.getCurrentSpace().expand(li.getCurrentSpace());
661
while (overlapList.size() > 0);
663
layoutModel.addInterval(subGroup, group, index);
664
singleOverlap = subGroup;
667
LayoutInterval subParallel;
668
if (singleOverlap.isSequential()) {
669
subParallel = singleOverlap.getSubInterval(
670
alignment == LEADING ? 0 : singleOverlap.getSubIntervalCount()-1);
671
if (!subParallel.isParallel())
674
else if (singleOverlap.isParallel()) {
675
subParallel = singleOverlap;
677
else subParallel = null;
679
if (subParallel != null && !LayoutInterval.isClosedGroup(subParallel, alignment)) {
680
LayoutInterval subOverlap = prepareGroupExtension(
681
subParallel, parent, startIndex, endIndex, dimension, alignment);
682
if (subOverlap != null)
683
singleOverlap = subOverlap;
687
return singleOverlap;
690
// [couldn't parallelizeWithParentSequence be used instead? or LayoutFeeder.separateSequence?]
691
private void separateGroupContent(LayoutInterval separate, int outPos, int dimension, int alignment) {
692
LayoutInterval group = separate.getParent();
693
assert group.isParallel();
694
LayoutInterval remainder = null;
695
LayoutInterval remainderGroup = null;
696
LayoutRegion remainderSpace = null;
698
for (int i=0; i < group.getSubIntervalCount(); ) {
699
LayoutInterval li = group.getSubInterval(i);
700
if (li != separate) {
701
assert li.getAlignment() == (alignment^1);
702
layoutModel.removeInterval(li);
703
if (remainder == null) {
707
if (remainderGroup == null) {
708
remainderGroup = new LayoutInterval(PARALLEL);
709
remainderGroup.setAlignment(alignment^1);
710
remainderGroup.setGroupAlignment(alignment^1);
711
layoutModel.addInterval(remainder, remainderGroup, 0);
712
remainder = remainderGroup;
714
layoutModel.addInterval(li, remainderGroup, -1);
716
if (!li.isEmptySpace()) {
717
if (remainderSpace == null) {
718
remainderSpace = new LayoutRegion();
720
remainderSpace.expand(li.getCurrentSpace());
725
remainder.setCurrentSpace(remainderSpace);
727
LayoutInterval remainderGap;
728
int remainderPos = remainderSpace.positions[dimension][alignment];
729
if (LayoutRegion.isValidCoordinate(outPos)) {
730
int gapSize = alignment == LEADING ? remainderPos - outPos : outPos - remainderPos;
731
remainderGap = new LayoutInterval(SINGLE);
732
remainderGap.setSizes(NOT_EXPLICITLY_DEFINED, gapSize, Short.MAX_VALUE);
734
else { // take the existing gap next to group [this case is not used currently]
735
remainderGap = LayoutInterval.getDirectNeighbor(group, alignment, false);
736
if (remainderGap != null && remainderGap.isEmptySpace()) {
737
layoutModel.removeInterval(remainderGap);
738
// [should check for last interval in parent]
739
LayoutInterval neighbor = LayoutInterval.getDirectNeighbor(group, alignment, true);
740
outPos = neighbor != null ?
741
neighbor.getCurrentSpace().positions[dimension][alignment^1] :
742
group.getParent().getCurrentSpace().positions[dimension][alignment];
743
int gapSize = alignment == LEADING ? remainderPos - outPos : outPos - remainderPos;
744
resizeInterval(remainderGap, gapSize);
746
else remainderGap = null;
748
if (remainderGap != null) {
750
if (remainder.isSequential()) {
754
seq = new LayoutInterval(SEQUENTIAL);
755
layoutModel.setIntervalAlignment(remainder, DEFAULT);
756
layoutModel.addInterval(remainder, seq, 0);
758
layoutModel.addInterval(remainderGap, seq, alignment == LEADING ? 0 : -1);
759
layoutModel.addInterval(seq, group, -1);
760
group.getCurrentSpace().positions[dimension][alignment] = outPos;
763
layoutModel.addInterval(remainder, group, -1);
768
* Makes given interval parallel with part of its parent sequence.
770
void parallelizeWithParentSequence(LayoutInterval interval, int endIndex, int dimension) {
771
LayoutInterval parent = interval.getParent();
772
assert parent.isParallel();
773
LayoutInterval parParent = parent;
774
while (!parParent.getParent().isSequential()) {
775
parParent = parParent.getParent();
777
LayoutInterval parentSeq = parParent.getParent();
779
int startIndex = parentSeq.indexOf(parParent);
781
endIndex = parentSeq.getSubIntervalCount() - 1;
782
else if (startIndex > endIndex) {
783
int temp = startIndex;
784
startIndex = endIndex;
788
layoutModel.removeInterval(interval);
789
if (interval.getAlignment() == DEFAULT) {
790
layoutModel.setIntervalAlignment(interval, parent.getGroupAlignment());
792
addParallelWithSequence(interval, parentSeq, startIndex, endIndex, dimension);
794
if (parent.getSubIntervalCount() == 1) {
795
addContent(layoutModel.removeInterval(parent, 0),
797
layoutModel.removeInterval(parent));
799
else if (parent.getSubIntervalCount() == 0) {
800
layoutModel.removeInterval(parent);
804
void addParallelWithSequence(LayoutInterval interval, LayoutInterval seq, int startIndex, int endIndex, int dimension) {
805
LayoutInterval group;
806
if (startIndex > 0 || endIndex < seq.getSubIntervalCount()-1) {
807
group = new LayoutInterval(PARALLEL);
808
if (interval.getAlignment() != DEFAULT) {
809
group.setGroupAlignment(interval.getAlignment());
811
int startPos = LayoutUtils.getVisualPosition(seq.getSubInterval(startIndex), dimension, LEADING);
812
int endPos = LayoutUtils.getVisualPosition(seq.getSubInterval(endIndex), dimension, TRAILING);
813
group.getCurrentSpace().set(dimension, startPos, endPos);
815
if (startIndex != endIndex) {
816
LayoutInterval subSeq = new LayoutInterval(SEQUENTIAL);
817
subSeq.setAlignment(seq.getAlignment());
818
for (int n=endIndex-startIndex+1; n > 0; n--) {
819
layoutModel.addInterval(layoutModel.removeInterval(seq, startIndex), subSeq, -1);
821
layoutModel.addInterval(subSeq, group, 0);
824
layoutModel.addInterval(layoutModel.removeInterval(seq, startIndex), group, 0);
826
layoutModel.addInterval(group, seq, startIndex);
829
group = seq.getParent();
831
layoutModel.addInterval(interval, group, -1);
834
int optimizeGaps(LayoutInterval group, int dimension) {
835
boolean anyAlignedLeading = false; // if false the group is open at leading edge
836
boolean anyAlignedTrailing = false; // if false the group is open at trailing edge
837
boolean anyAlignedBoth = false;
838
boolean anyGapLeading = false; // if true there is some gap at the leading edge
839
boolean anyGapTrailing = false; // if true there is some gap at the trailing edge
840
boolean sameMinGapLeading = true; // if true all intervals are aligned with the same gap at leading edge
841
boolean sameMinGapTrailing = true; // if true all intervals are aligned with the same gap at trailing edge
842
int commonGapLeadingSize = Integer.MIN_VALUE;
843
int commonGapTrailingSize = Integer.MIN_VALUE;
845
// first analyze the group
846
for (int i=0; i < group.getSubIntervalCount(); i++) {
847
LayoutInterval li = group.getSubInterval(i);
848
if (li.isEmptySpace()) { // remove container supporting gap
849
if (group.getSubIntervalCount() > 1) {
850
layoutModel.removeInterval(group, i);
856
boolean leadingAlign = false;
857
boolean trailingAlign = false;
858
LayoutInterval leadingGap = null;
859
LayoutInterval trailingGap = null;
860
boolean contentResizing = false;
861
boolean noResizing = false;
862
if (li.isSequential()) {
863
// find out effective alignment of the sequence content without border gaps
864
boolean leadGapRes = false;
865
boolean trailGapRes = false;
866
for (int j=0; j < li.getSubIntervalCount(); j++) {
867
LayoutInterval sub = li.getSubInterval(j);
868
if (j == 0 && sub.isEmptySpace()) {
870
leadGapRes = LayoutInterval.wantResize(sub);
872
else if (j+1 == li.getSubIntervalCount() && sub.isEmptySpace()) {
874
trailGapRes = LayoutInterval.wantResize(sub);
876
else if (!contentResizing && LayoutInterval.wantResize(sub)) {
877
contentResizing = true;
880
if (!contentResizing) {
881
if (leadGapRes || trailGapRes) {
882
leadingAlign = trailGapRes && !leadGapRes;
883
trailingAlign = leadGapRes && !trailGapRes;
885
else noResizing = true;
888
else if (LayoutInterval.wantResize(li))
889
contentResizing = true;
894
leadingAlign = trailingAlign = true;
895
else if (noResizing) {
896
int alignment = li.getAlignment();
897
leadingAlign = alignment == LEADING;
898
trailingAlign = alignment == TRAILING;
902
anyAlignedLeading = true;
904
anyAlignedBoth = true;
907
anyAlignedTrailing = true;
910
if (leadingGap != null) {
911
anyGapLeading = true;
912
if (sameMinGapLeading) {
913
int size = leadingAlign || leadingGap.getMinimumSize() == USE_PREFERRED_SIZE ?
914
leadingGap.getPreferredSize() : leadingGap.getMinimumSize();
915
if (commonGapLeadingSize != Integer.MIN_VALUE) {
916
if (size != commonGapLeadingSize)
917
sameMinGapLeading = false;
919
else commonGapLeadingSize = size;
922
else sameMinGapLeading = false;
924
if (trailingGap != null) {
925
anyGapTrailing = true;
926
if (sameMinGapTrailing) {
927
int size = trailingAlign || trailingGap.getMinimumSize() == USE_PREFERRED_SIZE ?
928
trailingGap.getPreferredSize() : trailingGap.getMinimumSize();
929
if (commonGapTrailingSize != Integer.MIN_VALUE) {
930
if (size != commonGapTrailingSize)
931
sameMinGapTrailing = false;
933
else commonGapTrailingSize = size;
936
else sameMinGapTrailing = false;
939
if (group.getSubIntervalCount() <= 1 || (!anyGapLeading && !anyGapTrailing)) {
943
if (!anyAlignedBoth) {
944
// can't reduce common minimum gap if anything aligned to opposite egde
945
if (anyAlignedTrailing)
946
sameMinGapLeading = false;
947
if (anyAlignedLeading)
948
sameMinGapTrailing = false;
951
int[] groupOuterPos = group.getCurrentSpace().positions[dimension];
952
assert groupOuterPos[LEADING] > Short.MIN_VALUE && groupOuterPos[TRAILING] > Short.MIN_VALUE;
953
int groupInnerPosLeading = LayoutUtils.getOutermostComponent(group, dimension, LEADING)
954
.getCurrentSpace().positions[dimension][LEADING];
955
int groupInnerPosTrailing = LayoutUtils.getOutermostComponent(group, dimension, TRAILING)
956
.getCurrentSpace().positions[dimension][TRAILING];
958
boolean defaultPaddingLeading = false; // if true, the leading padding has default preferred size
959
boolean defaultPaddingTrailing = false; // if true, the trailing padding has default preferred size
960
boolean resizingGapLeading = false;
961
boolean resizingGapTrailing = false;
963
// remove gaps where needed
964
for (int i=0; i < group.getSubIntervalCount(); i++) {
965
LayoutInterval li = group.getSubInterval(i);
966
if (li.isSequential()) {
967
if (anyGapLeading && (!anyAlignedLeading || sameMinGapLeading)) {
968
LayoutInterval gap = li.getSubInterval(0);
969
if (gap.isEmptySpace()) {
970
if (gap.getPreferredSize() == NOT_EXPLICITLY_DEFINED
971
&& isEndingDefaultGapEffective(li, dimension, LEADING))
972
{ // default padding to be used as common gap
973
defaultPaddingLeading = true;
975
if (gap.getMaximumSize() >= Short.MAX_VALUE) {
976
if (li.getAlignment() == LEADING) // need to change alignment as we removed resizing gap
977
layoutModel.setIntervalAlignment(li, TRAILING);
978
if (!anyAlignedLeading) // resizability goes out of the group
979
resizingGapLeading = true;
981
layoutModel.removeInterval(gap);
985
if (anyGapTrailing && (!anyAlignedTrailing || sameMinGapTrailing)) {
986
LayoutInterval gap = li.getSubInterval(li.getSubIntervalCount() - 1);
987
if (gap.isEmptySpace()) {
988
if (gap.getPreferredSize() == NOT_EXPLICITLY_DEFINED
989
&& isEndingDefaultGapEffective(li, dimension, TRAILING))
990
{ // default padding to be used as common gap
991
defaultPaddingTrailing = true;
993
if (gap.getMaximumSize() >= Short.MAX_VALUE) {
994
if (li.getAlignment() == TRAILING) // need to change alignment as we removed resizing gap
995
layoutModel.setIntervalAlignment(li, LEADING);
996
if (!anyAlignedTrailing) // resizability goes out of the group
997
resizingGapTrailing = true;
999
layoutModel.removeInterval(gap);
1003
if (li.getSubIntervalCount() == 1) {
1004
// only one interval remained in sequence - cancel the sequence
1005
layoutModel.removeInterval(group, i); // removes li from group
1006
LayoutInterval sub = layoutModel.removeInterval(li, 0); // removes last interval from li
1007
layoutModel.setIntervalAlignment(sub, li.getRawAlignment());
1008
layoutModel.addInterval(sub, group, i);
1013
LayoutInterval leadingGap = null;
1014
LayoutInterval trailingGap = null;
1016
if (anyGapLeading) {
1017
if (!anyAlignedLeading) { // group is open at leading edge
1018
int size = groupInnerPosLeading - groupOuterPos[LEADING];
1019
if (size > 0 || defaultPaddingLeading) {
1020
leadingGap = new LayoutInterval(SINGLE);
1021
if (!defaultPaddingLeading) {
1022
leadingGap.setPreferredSize(size);
1023
if (!resizingGapLeading)
1024
leadingGap.setMinimumSize(USE_PREFERRED_SIZE);
1026
if (resizingGapLeading) {
1027
leadingGap.setMaximumSize(Short.MAX_VALUE);
1031
else if (sameMinGapLeading) {
1032
leadingGap = new LayoutInterval(SINGLE);
1033
// int size = commonGapLeading.getMinimumSize();
1034
// if (size == USE_PREFERRED_SIZE)
1035
// size = commonGapLeading.getPreferredSize();
1036
// leadingGap.setSizes(size, size, USE_PREFERRED_SIZE);
1037
leadingGap.setSizes(commonGapLeadingSize, commonGapLeadingSize, USE_PREFERRED_SIZE);
1040
if (anyGapTrailing) {
1041
if (!anyAlignedTrailing) { // group is open at trailing edge
1042
int size = groupOuterPos[TRAILING] - groupInnerPosTrailing;
1043
if (size > 0 || defaultPaddingTrailing) {
1044
trailingGap = new LayoutInterval(SINGLE);
1045
if (!defaultPaddingTrailing) {
1046
trailingGap.setPreferredSize(size);
1047
if (!resizingGapTrailing)
1048
trailingGap.setMinimumSize(USE_PREFERRED_SIZE);
1050
if (resizingGapTrailing) {
1051
trailingGap.setMaximumSize(Short.MAX_VALUE);
1055
else if (sameMinGapTrailing) {
1056
trailingGap = new LayoutInterval(SINGLE);
1057
// int size = commonGapTrailing.getMinimumSize();
1058
// if (size == USE_PREFERRED_SIZE)
1059
// size = commonGapTrailing.getPreferredSize();
1060
// trailingGap.setSizes(size, size, USE_PREFERRED_SIZE);
1061
trailingGap.setSizes(commonGapTrailingSize, commonGapTrailingSize, USE_PREFERRED_SIZE);
1065
if (leadingGap != null || trailingGap != null) {
1066
if (leadingGap != null || !LayoutRegion.isValidCoordinate(groupOuterPos[LEADING])) {
1067
groupOuterPos[LEADING] = groupInnerPosLeading;
1069
if (trailingGap != null || !LayoutRegion.isValidCoordinate(groupOuterPos[TRAILING])) {
1070
groupOuterPos[TRAILING] = groupInnerPosTrailing;
1072
groupOuterPos[CENTER] = (groupInnerPosLeading + groupInnerPosTrailing) / 2;
1073
if (leadingGap != null) {
1074
group = insertGap(leadingGap, group, groupInnerPosLeading, dimension, LEADING);
1076
if (trailingGap != null) {
1077
group = insertGap(trailingGap, group, groupInnerPosTrailing, dimension, TRAILING);
1079
LayoutInterval parent = group.getParent();
1080
return parent != null ? parent.indexOf(group) : -1;//idx;
1085
private boolean isEndingDefaultGapEffective(LayoutInterval seq, int dimension, int alignment) {
1086
assert seq.isSequential() && (alignment == LEADING || alignment == TRAILING);
1087
int idx = alignment == LEADING ? 0 : seq.getSubIntervalCount() - 1;
1088
int d = alignment == LEADING ? 1 : -1;
1089
LayoutInterval gap = seq.getSubInterval(idx);
1090
LayoutInterval neighbor = seq.getSubInterval(idx+d);
1092
if (LayoutInterval.getEffectiveAlignment(neighbor, alignment) == alignment) {
1093
return true; // aligned
1096
int prefDistance = LayoutUtils.getSizeOfDefaultGap(gap, visualMapper);
1097
int pos1 = neighbor.getCurrentSpace().positions[dimension][alignment];
1098
LayoutInterval outerNeighbor = LayoutInterval.getNeighbor(gap, alignment, true, true, false);
1099
int pos2 = outerNeighbor != null ?
1100
outerNeighbor.getCurrentSpace().positions[dimension][alignment^1] :
1101
LayoutInterval.getRoot(seq).getCurrentSpace().positions[dimension][alignment];
1102
int currentDistance = (pos1 - pos2) * d;
1103
return currentDistance <= prefDistance;
1107
boolean cutStartingGap(LayoutInterval group, int size, int dimension, int alignment) {
1108
assert group.isGroup() && size > 0 && (alignment == LEADING || alignment == TRAILING);
1109
// [just very simple impl. for now - considering just one sequence...]
1110
LayoutInterval seq = null;
1111
if (group.isSequential()) {
1114
else if (group.getSubIntervalCount() == 1) {
1115
LayoutInterval li = group.getSubInterval(0);
1116
if (li.isSequential() && LayoutInterval.isAlignedAtBorder(li, alignment))
1119
if (seq != null && seq.getSubIntervalCount() > 1) {
1120
LayoutInterval gap = seq.getSubInterval(alignment == LEADING ? 0 : seq.getSubIntervalCount()-1);
1121
LayoutInterval neighbor = LayoutInterval.getDirectNeighbor(gap, alignment^1, true);
1122
if (gap != null && gap.isEmptySpace() && neighbor != null) {
1123
int currentSize = gap.getPreferredSize();
1124
if (currentSize == NOT_EXPLICITLY_DEFINED) {
1125
currentSize = LayoutRegion.distance(group.getCurrentSpace(), neighbor.getCurrentSpace(),
1126
dimension, alignment, alignment)
1127
* (alignment == TRAILING ? -1 : 1);
1129
if (currentSize >= size) {
1130
if (currentSize > size)
1131
resizeInterval(gap, currentSize - size);
1133
layoutModel.removeInterval(gap);
1142
* Inserts a gap before or after specified interval. If in a sequence, the
1143
* method takes care about merging gaps if there is already some as neighbor.
1144
* Expects the actual positions of the sequence are up-to-date.
1145
* @param gap the gap to be inserted
1146
* @param interval the interval before or after which the gap is added
1147
* @param pos expected real position of the end of the interval where the gap
1148
* is added (need not correspond to that stored in the interval)
1150
* @param alignment at which side of the interval the gap is added (LEADING or TRAILING)
1152
LayoutInterval insertGap(LayoutInterval gap, LayoutInterval interval, int pos, int dimension, int alignment) {
1153
assert alignment == LEADING || alignment == TRAILING;
1154
assert !interval.isSequential();
1155
assert gap.isEmptySpace();
1157
LayoutInterval parent = interval.getParent();
1158
if (parent == null) {
1159
assert interval.isParallel();
1161
if (parent.getSubIntervalCount() > 1) {
1162
LayoutInterval seq = new LayoutInterval(SEQUENTIAL);
1163
seq.getCurrentSpace().set(dimension,
1164
(alignment == LEADING) ? pos : interval.getCurrentSpace().positions[dimension][LEADING],
1165
(alignment == LEADING) ? interval.getCurrentSpace().positions[dimension][TRAILING] : pos);
1166
layoutModel.addInterval(seq, parent, -1);
1167
interval = new LayoutInterval(PARALLEL);
1168
interval.getCurrentSpace().set(dimension, parent.getCurrentSpace());
1169
layoutModel.addInterval(interval, seq, 0);
1170
while (parent.getSubIntervalCount() > 1) {
1171
layoutModel.addInterval(layoutModel.removeInterval(parent, 0), interval, -1);
1176
interval = parent.getSubInterval(0);
1177
if (interval.isSequential()) {
1179
int subIdx = alignment == LEADING ? 0 : parent.getSubIntervalCount()-1;
1180
interval = parent.getSubInterval(subIdx);
1181
if (interval.isEmptySpace()) {
1182
subIdx += alignment == LEADING ? 1 : -1;
1183
LayoutInterval neighbor = subIdx >= 0 && subIdx < parent.getSubIntervalCount() ?
1184
parent.getSubInterval(subIdx) : null;
1185
int[] outerSpace = parent.getParent().getCurrentSpace().positions[dimension];
1186
int otherPos = neighbor != null ? neighbor.getCurrentSpace().positions[dimension][alignment] :
1187
outerSpace[alignment^1];
1188
int mergedSize = (outerSpace[alignment] - otherPos) * (alignment == LEADING ? -1 : 1);
1189
eatGap(interval, gap, mergedSize);
1190
return neighbor != null ? neighbor : interval;
1194
LayoutInterval seq = new LayoutInterval(SEQUENTIAL);
1195
seq.getCurrentSpace().set(dimension,
1196
(alignment == LEADING) ? pos : interval.getCurrentSpace().positions[dimension][LEADING],
1197
(alignment == LEADING) ? interval.getCurrentSpace().positions[dimension][TRAILING] : pos);
1198
layoutModel.addInterval(seq, parent, -1);
1199
layoutModel.removeInterval(interval);
1200
layoutModel.addInterval(interval, seq, -1);
1205
if (parent.isSequential()) {
1206
// we can't use insertGapIntoSequence here because 'pos' can be special
1207
LayoutInterval neighbor = LayoutInterval.getDirectNeighbor(interval, alignment, false);
1208
if (neighbor != null && neighbor.isEmptySpace()) {
1209
LayoutInterval next = LayoutInterval.getDirectNeighbor(neighbor, alignment, false);
1210
int otherPos = next != null ? next.getCurrentSpace().positions[dimension][alignment^1] :
1211
parent.getCurrentSpace().positions[dimension][alignment];
1212
int mergedSize = (pos - otherPos) * (alignment == LEADING ? 1 : -1);
1213
eatGap(neighbor, gap, mergedSize);
1216
int idx = parent.indexOf(interval) + (alignment == LEADING ? 0 : 1);
1217
layoutModel.addInterval(gap, parent, idx);
1220
else { // parallel parent
1221
LayoutInterval seq = new LayoutInterval(SEQUENTIAL);
1222
int idx = layoutModel.removeInterval(interval);
1223
seq.setAlignment(interval.getAlignment());
1224
seq.getCurrentSpace().set(dimension,
1225
(alignment == LEADING) ? pos : interval.getCurrentSpace().positions[dimension][LEADING],
1226
(alignment == LEADING) ? interval.getCurrentSpace().positions[dimension][TRAILING] : pos);
1227
layoutModel.addInterval(seq, parent, idx);
1228
layoutModel.setIntervalAlignment(interval, DEFAULT);
1229
layoutModel.addInterval(interval, seq, 0);
1230
layoutModel.addInterval(gap, seq, alignment == LEADING ? 0 : 1);
1236
int insertGapIntoSequence(LayoutInterval gap, LayoutInterval seq, int index, int dimension) {
1237
assert gap.isEmptySpace();
1238
LayoutInterval otherGap = null;
1239
int alignment = DEFAULT;
1240
if (index >= 0 && index < seq.getSubIntervalCount()) {
1241
otherGap = seq.getSubInterval(index);
1242
if (otherGap.isEmptySpace())
1243
alignment = TRAILING;
1245
if (alignment == DEFAULT && index > 0) {
1246
otherGap = seq.getSubInterval(index-1);
1247
if (otherGap.isEmptySpace())
1248
alignment = LEADING;
1250
if (alignment == DEFAULT) {
1251
layoutModel.addInterval(gap, seq, index);
1252
return index; // gap was added normally
1256
LayoutInterval neighbor = LayoutInterval.getDirectNeighbor(otherGap, alignment, true);
1257
pos1 = neighbor != null ?
1258
neighbor.getCurrentSpace().positions[dimension][alignment^1] :
1259
seq.getCurrentSpace().positions[dimension][alignment];
1260
neighbor = LayoutInterval.getDirectNeighbor(otherGap, alignment^1, true);
1261
pos2 = neighbor != null ?
1262
neighbor.getCurrentSpace().positions[dimension][alignment] :
1263
seq.getCurrentSpace().positions[dimension][alignment^1];
1265
eatGap(otherGap, gap, Math.abs(pos2 - pos1));
1266
return alignment == LEADING ? index-1 : index; // gap was eaten
1269
void eatGap(LayoutInterval main, LayoutInterval eaten, int currentMergedSize) {
1271
int min1 = main.getMinimumSize();
1272
if (min1 == USE_PREFERRED_SIZE)
1273
min1 = main.getPreferredSize();
1274
int min2 = eaten.getMinimumSize();
1275
if (min2 == USE_PREFERRED_SIZE)
1276
min2 = eaten.getPreferredSize();
1282
else if (!LayoutInterval.canResize(main) && !LayoutInterval.canResize(eaten))
1283
min = USE_PREFERRED_SIZE;
1284
else if (min1 == NOT_EXPLICITLY_DEFINED || min2 == NOT_EXPLICITLY_DEFINED)
1285
min = NOT_EXPLICITLY_DEFINED;
1290
int pref1 = main.getPreferredSize();
1291
int pref2 = eaten.getPreferredSize();
1295
else if (pref2 == 0)
1297
else if (pref1 == NOT_EXPLICITLY_DEFINED || pref2 == NOT_EXPLICITLY_DEFINED)
1298
pref = currentMergedSize;
1300
pref = pref1 + pref2;
1302
int max = main.getMaximumSize() >= Short.MAX_VALUE || eaten.getMaximumSize() >= Short.MAX_VALUE ?
1303
Short.MAX_VALUE : USE_PREFERRED_SIZE;
1305
layoutModel.setIntervalSize(main, min, pref, max);
1306
if (eaten.getParent() != null) {
1307
layoutModel.removeInterval(eaten);
1311
void mergeAdjacentGaps(Set updatedContainers) {
1312
Iterator it = layoutModel.getAllComponents();
1313
while (it.hasNext()) {
1314
LayoutComponent comp = (LayoutComponent) it.next();
1315
if (!comp.isLayoutContainer())
1318
boolean updated = false;
1319
for (LayoutInterval[] roots : comp.getLayoutRoots()) {
1320
for (int dim=0; dim<DIM_COUNT; dim++) {
1321
updated = mergeAdjacentGaps(roots[dim], dim) || updated;
1325
updatedContainers.add(comp);
1330
boolean mergeAdjacentGaps(LayoutInterval root, int dimension) {
1331
assert root.isGroup();
1332
boolean updated = false;
1333
if (root.isSequential()) {
1334
for (int i=0; i<root.getSubIntervalCount(); i++) {
1335
LayoutInterval interval = root.getSubInterval(i);
1336
if (interval.isEmptySpace() && ((i+1) < root.getSubIntervalCount())) {
1337
LayoutInterval next = root.getSubInterval(i+1);
1338
if (next.isEmptySpace()) {
1339
if ((i+2) < root.getSubIntervalCount()) {
1340
LayoutInterval nextNext = root.getSubInterval(i+2);
1341
if (nextNext.isEmptySpace()) {
1342
i--; // The merged gap should be merged with nextNext gap
1346
eatGap(interval, next, NOT_EXPLICITLY_DEFINED);
1351
Iterator iter = root.getSubIntervals();
1352
while (iter.hasNext()) {
1353
LayoutInterval subInterval = (LayoutInterval)iter.next();
1354
if (subInterval.isGroup()) {
1355
updated = updated || mergeAdjacentGaps(subInterval, dimension);
1361
void suppressResizingOfSurroundingGaps(LayoutInterval interval) {
1362
LayoutInterval parent = interval.getParent();
1363
while (parent != null) {
1364
if (parent.isSequential()) {
1365
for (Iterator it=parent.getSubIntervals(); it.hasNext(); ) {
1366
LayoutInterval sub = (LayoutInterval) it.next();
1367
if (sub != interval && sub.isEmptySpace() && LayoutInterval.canResize(sub)) {
1368
int pref = sub.getPreferredSize();
1369
int min = sub.getMinimumSize() != pref ? USE_PREFERRED_SIZE : pref;
1370
int max = USE_PREFERRED_SIZE;
1371
layoutModel.setIntervalSize(sub, min, pref, max);
1375
else if (!LayoutInterval.canResize(parent))
1378
parent = interval.getParent();