KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > form > layoutdesign > LayoutInterval


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.form.layoutdesign;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.LinkedList JavaDoc;
26 import java.util.List JavaDoc;
27
28 /**
29  * @author Tomas Pavek
30  */

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     // attributes denoting intervals with different size behavior in design time
38
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     // attributes used during aligning
43
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     // type of the interval - SINGLE, SEQUENTIAL, PARALLEL
56
private int type;
57
58     // additional attributes set on the interval as bit flags
59
private int attributes;
60
61     // alignment of the interval (if in a parallel group)
62
private int alignment = DEFAULT;
63
64     // parent interval (group )
65
private LayoutInterval parentInterval;
66
67     // internall alignment of a group (if this is a parallel group)
68
private int groupAlignment = LEADING;
69
70     // contained sub-intervals (if this is a group)
71
private List JavaDoc subIntervals;
72
73     // associated LayoutComponent (if any)
74
private LayoutComponent layoutComponent;
75
76 // private boolean defaultPadding; // String[] surroundingComps
77

78     // minimum, preferred, and maximum size definitions
79
private int minSize;
80     private int prefSize;
81     private int maxSize;
82
83     // current position and size of the interval in the visual representation
84
private LayoutRegion currentSpace;
85
86     // -----
87
// setup methods - each setter should be called max. once after creation,
88
// other changes should be done via LayoutModel to be fired and recorded
89
// for undo/redo
90

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 JavaDoc();
97             maxSize = NOT_EXPLICITLY_DEFINED; // group can resize by default
98
}
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         // for groups we expect only two states - shrinking suppressed/allowed
120
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); // groups should not have explicit size
126
prefSize = size;
127     }
128
129     void setMaximumSize(int size) {
130         // for single interval the max size must be defined
131
// for groups only two states - growing suppressed or allowed
132
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     // ---------
162
// public methods
163

164     /**
165      * Returns the type of the structure of the interval. It can be a single
166      * interval or a group with sub-intervals arranged either sequentially
167      * or parallelly.
168      * @return type of the interval: SINGLE, SEQUENTIAL, or PARALLEL
169      */

170     public int getType() {
171         return type;
172     }
173
174     /**
175      * Returns alignment of the interval within a parallel group. If the
176      * interval is not part of a parallel group, the alignment is meaningless.
177      * @return alignment of the interval within a parallel group (LEADING,
178      * TRAILING, CENTER, or BASELINE); DEFAULT if in a sequential group
179      */

180     public int getAlignment() {
181         return alignment == DEFAULT && parentInterval != null
182                                     && parentInterval.isParallel() ?
183             parentInterval.getGroupAlignment() : alignment;
184     }
185
186     /**
187      * Returns the common alignment of sub-intervals within a group (makes
188      * sense only for a parallel group).
189      * @return alignment of the group (LEADING, TRAILING, CENTER, or BASELINE)
190      */

191     public int getGroupAlignment() {
192         return groupAlignment;
193     }
194
195     /**
196      * Returns the minimum size of the interval. Instead of a specific size
197      * it may return also one of the constants NOT_EXPLICITLY_DEFINED or
198      * USE_PREFERRED_SIZE.
199      * @param designTime if true, size for design time layout is returned
200      * (design time behavior may be different in terms of resizing)
201      * @return minimum interval size, or one of the constants:
202      * NOT_EXPLICITLY_DEFINED or USE_PREFERRED_SIZE
203      */

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     /**
219      * Returns the preferred size of the interval. If no specific size was set,
220      * it returns NOT_EXPLICITLY_DEFINED constant.
221      * @param designTime if true, size for design time layout is returned
222      * (design time behavior may be different in terms of resizing)
223      * @return preferred size of the interval, or NOT_EXPLICITLY_DEFINED constant
224      */

225     public int getPreferredSize(boolean designTime) {
226         return prefSize;
227     }
228
229     /**
230      * Returns the maximum size of the interval. Instead of a specific size
231      * it may return also one of the constants NOT_EXPLICITLY_DEFINED or
232      * USE_PREFERRED_SIZE.
233      * @param designTime if true, size for design time layout is returned
234      * (design time behavior may be different in terms of resizing)
235      * @return maximum interval size, or one of the constants:
236      * NOT_EXPLICITLY_DEFINED or USE_PREFERRED_SIZE
237      */

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     /**
253      * Returns number of sub-intervals of this interval.
254      * @return number of sub-intervals of this interval, 0 if it is not a group
255      */

256     public int getSubIntervalCount() {
257         return subIntervals != null ? subIntervals.size() : 0;
258     }
259
260     /**
261      * Returns an iterator of sub-intervals.
262      * @return iterator of sub-intervals, empty if there are no sub-intervals
263      */

264     public Iterator JavaDoc getSubIntervals() {
265         return subIntervals != null ? subIntervals.iterator() :
266                                       Collections.EMPTY_LIST.iterator();
267     }
268
269     /**
270      * If this interval represents a component's width or height, this methods
271      * returns the component.
272      * @return LayoutComponent instance representing the associated component.
273      * Null if this interval does not represent a component.
274      */

275     public LayoutComponent getComponent() {
276         return layoutComponent;
277     }
278
279     // helper methods (redundant - based on derived information)
280

281     public boolean isParallel() {
282         return type == PARALLEL;
283     }
284
285     public boolean isSequential() {
286         return type == SEQUENTIAL;
287     }
288
289     /**
290      * Returns whether this interval defines a lyout component.
291      * @return true if this interval represents a layout component,
292      * false otherwise
293      */

294     public boolean isComponent() {
295         return layoutComponent != null;
296     }
297
298     /**
299      * Returns whether this interval defines an "empty" space (gap) in the
300      * layout, not including nor being able to include any component.
301      * @return true if this is a single interval not representing a component,
302      * false otherwise
303      */

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     /**
318      * Returns whether this interval represents a group structure that can have
319      * have sub-intervals.
320      * @return whether this interval is a group, either sequential or parallel
321      */

322     public boolean isGroup() {
323         return type == SEQUENTIAL || type == PARALLEL;
324     }
325
326     /**
327      * @return whether the interval is allowed to grow (according to its
328      * definition); if allowed, the real growing possibility may still
329      * depend on the associated component
330      */

331 // public boolean isAllowedToGrow() {
332
// return maxSize != USE_PREFERRED_SIZE
333
// && (prefSize == NOT_EXPLICITLY_DEFINED
334
// || maxSize == NOT_EXPLICITLY_DEFINED
335
// || maxSize > prefSize);
336
// }
337

338     /**
339      * @return whether the interval is allowed to shrink (according to its
340      * definition); if allowed, the real growing possibility may still
341      * depend on the associated component
342      */

343 // public boolean isAllowedToShrink() {
344
// return minSize != USE_PREFERRED_SIZE
345
// && (prefSize == NOT_EXPLICITLY_DEFINED
346
// || minSize == NOT_EXPLICITLY_DEFINED
347
// || minSize < prefSize);
348
// }
349

350     // end of public methods
351
// -----
352

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     /**
366      * Sets attributes of the layout interval. Should be used by persistence manager only!
367      *
368      * @param attrs attributes.
369      */

370     void setAttributes(int attrs) {
371         attributes = attrs;
372     }
373     
374     /**
375      * Returns attributes of this layout interval. You should use
376      * <code>hasAttribute()</code> when you are interested in one
377      * particular attribute.
378      */

379     int getAttributes() {
380         return attributes;
381     }
382
383     /**
384      * @return the value of the alignment field of the interval - unlike
385      * getAlignment() it does not ask the parent if not set (DEFAULT)
386      */

387     int getRawAlignment() {
388         return alignment;
389     }
390
391     // -----
392

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     // -----
444
// current state of the layout - current position and size of layout
445
// interval kept to be available quickly for the layout designer
446

447     LayoutRegion getCurrentSpace() {
448         assert !isEmptySpace(); // [temporary - nobody should be interested in gap positions]
449
if (currentSpace == null) {
450             currentSpace = new LayoutRegion();
451         }
452         return currentSpace;
453     }
454
455     void setCurrentSpace(LayoutRegion space) {
456         currentSpace = space;
457     }
458
459     // -----
460
// static helper methods
461

462     /**
463      * @return the closest parent interval that matches given type
464      */

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 // assert interval.isParallel();
478
return interval;
479     }
480
481     /**
482      * Finds common parent of the given intervals.
483      *
484      * @param intervals intervals whose parent should be found.
485      * @return common parent of the given intervals.
486      */

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     /**
497      * Finds common parent of two given intervals.
498      *
499      * @param interval1 interval whose parent should be found.
500      * @param interval2 interval whose parent should be found.
501      * @return common parent of two given intervals.
502      */

503     static LayoutInterval getCommonParent(LayoutInterval interval1, LayoutInterval interval2) {
504         // Find all parents of given intervals
505
Iterator JavaDoc parents1 = parentsOfInterval(interval1).iterator();
506         Iterator JavaDoc parents2 = parentsOfInterval(interval2).iterator();
507         LayoutInterval parent1 = (LayoutInterval)parents1.next();
508         LayoutInterval parent2 = (LayoutInterval)parents2.next();
509         assert (parent1 == parent2);
510         
511         // Candidate for the common parent
512
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     /**
530      * Calculates all parents of the given interval.
531      *
532      * @param interval interval whose parents should be found.
533      * @return <code>List</code> of <code>LayoutInterval</code> objects that
534      * are parents of the given interval. The immediate parent of the interval
535      * is at the end of the list.
536      */

537     private static List JavaDoc parentsOfInterval(LayoutInterval interval) {
538         List JavaDoc parents = new LinkedList JavaDoc();
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 JavaDoc 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             { // count in
557
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     /**
583      * @param alignment direction in which the neighbor is looked for (LEADING or TRAILING)
584      * @param nonEmpty true if empty spaces (gaps) should be skipped
585      * @param outOfParent true if can go up (out of the first sequential parent)
586      * for an indirect neighbor
587      * @param aligned true if the indirect neighbor must be in contact with the
588      * given interval
589      */

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 { // find sequential parent first
604
interval = parent;
605                 parent = interval.getParent();
606                 if (aligned && parent != null && parent.isParallel()
607                     && !isAlignedAtBorder(interval, alignment))
608                 { // interval not aligned in parent
609
parent = null;
610                 }
611             }
612             while (parent != null && parent.isParallel());
613
614             if (parent != null) { // look for the neighbor in the sequence
615
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 JavaDoc 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 { // parallel group
656
for (Iterator JavaDoc 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     /**
667      * Checks whether an interval is permanently aligned to its parent at given
668      * border. (The asked relation is hard, always maintained by the layout.)
669      * For a sequential parent the interval is aligned if it is first or last.
670      * For parallel parent the interval must have the given alignment in the
671      * group, or be resizing.
672      */

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 { // parallel parent
686
return interval.getAlignment() == alignment
687                    || wantResize(interval);
688         }
689     }
690
691     /**
692      * Checks whether an interval is permanently aligned with a given parent
693      * interval - need not be the direct parent. This is a multi-level version
694      * of the other (simple) isAlignedAtBorder method.
695      */

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     /**
708      * Checks whether given interval is placed at border side of its parent.
709      * Cares about the current visual situation only - the place may change if
710      * the alignment is not backed by the layout structure.
711      * Note this method requires the current visual state (positions) of the
712      * relevant intervals to be up-to-date.
713      */

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 { // gap in parallel parent
728
return true;
729             }
730         }
731         else { // check visual position
732
return LayoutRegion.distance(interval.getCurrentSpace(), parent.getCurrentSpace(),
733                                         dimension, alignment, alignment) == 0;
734         }
735     }
736
737     /**
738      * Checks whether an interval is placed at border side of given parent
739      * (need not be the direct parent). This is a multi-level version of the
740      * simpler isPlacededAtBorder method.
741      * Note this method requires the current visual state (positions) of the
742      * relevant intervals to be up-to-date.
743      */

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     // [to be replaced by separate methods like isAlignedAtBorder, isPlacedBorder, isLastInterval]
767
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 // if (interval.getAlignment() == alignment) {
789
// return interval.getCurrentSpace().positions[dimension][alignment]
790
// == parent.getCurrentSpace().positions[dimension][alignment];
791
}
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 JavaDoc 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     /**
832      * @return whether given interval is allowed to resize (not defined as fixed)
833      */

834     static boolean canResize(LayoutInterval interval) {
835         // [don't care about shrinking, assuming min possibly not defined - is it ok?]
836
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     /**
844      * Finds out whether given interval would resize if allowed (given more
845      * space by its parent).
846      * @return whether given interval would resize if given opportunity
847      */

848     static boolean wantResize(LayoutInterval interval) {
849         return canResize(interval)
850                && (!interval.isGroup() || contentWantResize(interval));
851     }
852
853     /**
854      * Finds out whether given interval would resize if allowed (given more
855      * space by its parent). This method also considers resizing of the whole
856      * layout (some parent of the interval could block the resizing).
857      * @return whether given interval would resize if given opportunity
858      */

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 JavaDoc 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     /**
910      * Computes effective alignment of an interval in its parent. In case of
911      * a sequential parent, the effective interval alignment depends on other
912      * intervals and their resizability. E.g. if a preceding interval is
913      * resizing then the interval is effectivelly "pushed" to the trailing end.
914      * If there are no other intervals resizing then the parent alignment is
915      * returned. If there are resizing intervals on both sides, or the interval
916      * itself is resizing, then the there is no (positive) effective alignment.
917      * @return LEADING, TRAILING, or DEFAULT
918      */

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 JavaDoc 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; // !leadingFixed && !trailingFixed
953
}
954
955     /**
956      * Computes effective alignment of given interval's edge in its direct
957      * parent. In case of a sequential parent, the effective interval alignment
958      * depends on other intervals and their resizability.
959      * @return effective alignment within parent, or DEFAULT in case of
960      * ambiguous alignment in sequential parent
961      */

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; // !leadingFixed && !trailingFixed
999
}
1000
1001    /**
1002     * Computes effective alignment of an interval's edge relatively to given
1003     * parent.
1004     * @return effective alignment within parent, or DEFAULT in case of
1005     * ambiguous alignment in sequential parent
1006     */

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    /**
1026     * Creates clone of the given interval. Doesn't clone content of groups.
1027     *
1028     * @param interval interval to be cloned.
1029     * @param clone interval that should contain cloned data. Can be <code>null</code>.
1030     * @return shallow clone of the interval.
1031     */

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