in java/form/src/org/netbeans/modules/form/layoutdesign/LayoutFeeder.java [1235:1764]
private void addToGroup(IncludeDesc iDesc1, IncludeDesc iDesc2, boolean definite) {
assert iDesc2 == null || (iDesc1.parent == iDesc2.parent
&& iDesc1.newSubGroup == iDesc2.newSubGroup
&& iDesc1.neighbor == iDesc2.neighbor);
LayoutInterval root = dragger.getTargetRoots()[dimension];
checkRoot(iDesc1.parent, root, null, dimension);
checkRoot(iDesc1.snappedParallel, root, iDesc1.parent, dimension);
if (iDesc2 != null) {
checkRoot(iDesc2.snappedParallel, root, iDesc2.parent, dimension);
}
LayoutInterval parent = iDesc1.parent;
LayoutInterval seq = null;
boolean subseq = false;
int index = 0;
if (parent.isSequential()) {
if (iDesc1.newSubGroup) {
LayoutRegion space = closedSpace == null ? addingSpace : closedSpace;
int closeAlign1 = getExtractCloseAlign(iDesc1);
int closeAlign2 = getExtractCloseAlign(iDesc2);
if (closeAlign1 == DEFAULT && closedSpace != null && iDesc1.index > 0) {
closeAlign1 = (iDesc1.alignment != TRAILING) ? LEADING : TRAILING;
}
if (closeAlign2 == DEFAULT && closedSpace != null && iDesc1.index < iDesc1.parent.getSubIntervalCount()) {
closeAlign2 = (iDesc1.alignment != TRAILING) ? TRAILING : LEADING;
}
LayoutInterval subgroup = extractParallelSequence(
parent, space, closeAlign1, closeAlign2, iDesc1.alignment, null);
if (subgroup != null) {
seq = new LayoutInterval(SEQUENTIAL);
parent = subgroup;
subseq = true;
}
}
if (seq == null) {
seq = parent;
parent = seq.getParent();
index = iDesc1.index;
}
if (iDesc2 != null && iDesc2.alignment == dragger.getResizingEdge(dimension)) {
alignWithResizingInSubgroup(seq, parent, iDesc2);
}
} else { // parallel parent
LayoutInterval neighbor = iDesc1.neighbor;
if (neighbor != null) {
checkNeighbor(neighbor, parent, dimension);
seq = new LayoutInterval(SEQUENTIAL);
layoutModel.addInterval(seq, parent, layoutModel.removeInterval(neighbor));
seq.setAlignment(neighbor.getAlignment());
layoutModel.setIntervalAlignment(neighbor, DEFAULT);
layoutModel.addInterval(neighbor, seq, 0);
if (iDesc1.index > -1) {
index = iDesc1.index;
} else if (getAddDirection(neighbor, iDesc1.alignment) == TRAILING) {
index = 1;
} // otherwise 0
} else {
seq = new LayoutInterval(SEQUENTIAL);
if (iDesc1.snapped()) {
seq.setAlignment(iDesc1.alignment);
}
}
}
assert iDesc1.alignment >= 0 || iDesc2 == null;
assert iDesc2 == null || iDesc2.alignment == (iDesc1.alignment^1);
assert parent.isParallel();
checkRoot(parent, root, iDesc1.parent, dimension);
LayoutInterval[] outBounds = new LayoutInterval[2]; // outermost boundary intervals (not gaps)
boolean[] span = new boolean[2]; // [what it really is??]
boolean[] outOfGroup = new boolean[2];
boolean[] expanded = new boolean[2];
LayoutInterval[] neighbors = new LayoutInterval[2]; // direct neighbors in the sequence (not gaps)
LayoutInterval[] gaps = new LayoutInterval[2]; // new gaps to create
LayoutInterval originalGap = null;
boolean minorOriginalGap;
int[] centerDst = new int[2]; // LEADING, TRAILING
// find the neighbors for the adding interval and determine the original gap
int count = seq.getSubIntervalCount();
if (index > count)
index = count;
for (int i = LEADING; i <= TRAILING; i++) {
int idx1 = i == LEADING ? index - 1 : index;
int idx2 = i == LEADING ? index - 2 : index + 1;
if (idx1 >= 0 && idx1 < count) {
LayoutInterval li = seq.getSubInterval(idx1);
if (li.isEmptySpace()) {
originalGap = li;
if (idx2 >= 0 && idx2 < count) {
neighbors[i] = seq.getSubInterval(idx2);
}
} else {
neighbors[i] = li;
}
}
IncludeDesc iiDesc = (iDesc1.alignment < 0 || iDesc1.alignment == i) ? iDesc1 : iDesc2;
if (iiDesc != null && iiDesc.snappedParallel != null) {
span[i] = true;
} else if (iiDesc != null && iiDesc.snappedNextTo != null) {
if (!parent.isParentOf(iiDesc.snappedNextTo)) {
LayoutInterval li = parent;
LayoutInterval gap = null;
do {
li = LayoutInterval.getNeighbor(li, i, false, true, false);
if (li != null) {
if (li.isEmptySpace()) {
gap = li;
}
}
} while (li != null && li != iiDesc.snappedNextTo && !li.isParentOf(iiDesc.snappedNextTo));
if (gap != null && (li != null || iiDesc.snappedNextTo.getParent() == null)
&& LayoutInterval.isDefaultPadding(gap)) {
span[i] = true;
}
}
}
outOfGroup[i] = stickingOutOfGroup(parent, i);
if (neighbors[i] != null) {
outBounds[i] = neighbors[i];
} else {
outBounds[i] = getPerceivedParentNeighbor(parent, addingSpace, outOfGroup[i], dimension, i);
}
if (definite && neighbors[i] == null) {
if (!subseq && parent.getParent() != null
&& outOfGroup[i]
&& (LayoutInterval.canResize(parent) || !LayoutInterval.wantResize(addingInterval))
&& shouldExpandOverGroupEdge(parent, outBounds[i], i)) {
// adding over group edge that is not apparent to the user (doesn't expect it to move)
if (seq.getParent() == null) {
layoutModel.addInterval(seq, parent, -1); // temporary
parent = separateSequence(seq, i, iDesc1, iDesc2);
checkRoot(parent, root, iDesc1.parent, dimension);
layoutModel.removeInterval(seq);
expanded[i] = true;
} else {
parent = separateSequence(seq, i, iDesc1, iDesc2);
checkRoot(parent, root, iDesc1.parent, dimension);
expanded[i] = true;
}
} else if (subseq && iDesc1.parent.getParent().getParent() != null
&& stickingOutOfGroup(iDesc1.parent.getParent(), i)
&& shouldExpandOverGroupEdge(iDesc1.parent.getParent(), outBounds[i], i)) {
// adding over group edge that is not apparent to the user (doesn't expect it to move)
boolean parentAligned = LayoutInterval.getEffectiveAlignmentInParent(parent, null, i) == i;
LayoutInterval p = separateSequence(iDesc1.parent, i, iDesc1, iDesc2);
if (parent.getSubIntervalCount() == 0 && parent.getParent() == null) {
parent = p; // optimized out during the operation
checkRoot(parent, root, iDesc1.parent, dimension);
} else {
checkRoot(parent, root, iDesc1.parent, dimension);
int outPos = p.getCurrentSpace().positions[dimension][i];
int size = (outPos - parent.getCurrentSpace().positions[dimension][i]) * (i==LEADING ? -1:1);
if (size > 0 && LayoutInterval.getEffectiveAlignmentInParent(parent, p, i) == i) {
// group gained more space by the parallelization, may need a support gap
boolean supportedInside = false;
for (int ii=0; ii < parent.getSubIntervalCount(); ii++) {
LayoutInterval sibling = parent.getSubInterval(ii);
if (LayoutInterval.isAlignedAtBorder(sibling, i)) {
LayoutInterval supportGap = new LayoutInterval(SINGLE);
supportGap.setSizes(parentAligned ? USE_PREFERRED_SIZE : NOT_EXPLICITLY_DEFINED,
size, parentAligned ? USE_PREFERRED_SIZE : Short.MAX_VALUE);
operations.insertGap(supportGap, sibling, outPos, dimension, i);
supportedInside = true;
}
}
if (!supportedInside) {
size = (outPos - addingSpace.positions[dimension][i]) * (i==LEADING ? -1:1);
if (size > 0) {
LayoutInterval supportGap = new LayoutInterval(SINGLE);
supportGap.setSizes(parentAligned ? USE_PREFERRED_SIZE : NOT_EXPLICITLY_DEFINED,
size, parentAligned ? USE_PREFERRED_SIZE : Short.MAX_VALUE);
operations.insertGap(supportGap, parent.getParent(), outPos, dimension, i);
}
}
}
setCurrentPositionToParent(parent, p, dimension, i);
}
}
}
if (iDesc1.alignment < 0) { // no alignment known
centerDst[i] = addingSpace.positions[dimension][CENTER]
- (outBounds[i] == parent || outBounds[i].isParentOf(parent) ?
outBounds[i].getCurrentSpace().positions[dimension][i] :
getPerceivedNeighborPosition(outBounds[i], addingSpace, dimension, i));
if (i == TRAILING) {
centerDst[i] *= -1;
}
}
}
minorOriginalGap = originalGap != null && !LayoutInterval.canResize(originalGap)
&& ((neighbors[LEADING] == null && LayoutInterval.getEffectiveAlignment(neighbors[TRAILING], LEADING, true) == TRAILING)
|| (neighbors[TRAILING] == null && LayoutInterval.getEffectiveAlignment(neighbors[LEADING], TRAILING, true) == LEADING));
// compute leading and trailing gaps
int edges = 2;
for (int i=LEADING; edges > 0; i^=1, edges--) {
gaps[i] = null;
LayoutInterval outerNeighbor = neighbors[i] == null ?
LayoutInterval.getNeighbor(parent, i, false, true, false) : null;
IncludeDesc iiDesc, otherDesc;
if (iDesc1.alignment < 0 || iDesc1.alignment == i) {
iiDesc = iDesc1;
otherDesc = iDesc2;
} else {
iiDesc = iDesc2;
otherDesc = iDesc1;
}
if (neighbors[i] == null && iiDesc != null) { // at the start/end of the sequence
if (iiDesc.snappedNextTo != null
&& outerNeighbor != null && LayoutInterval.isDefaultPadding(outerNeighbor))
{ // the padding is outside of the parent already
continue;
}
if (iiDesc.snappedParallel != null) {
if (seq.isParentOf(iiDesc.snappedParallel)) {
if (originalGap == null) {
continue;
}
} else if (canAlignWith(iiDesc.snappedParallel, parent, i)) {
continue;
}
}
}
boolean aligned;
if (iDesc2 == null) { // one position defined
if (iiDesc != null && !iiDesc.snapped() && dragger.isResizing() && originalPosition != null) {
// resizing - keep original alignment
aligned = originalPosition.atFixedPosition(i);
} else if (iDesc1.alignment < 0) {
// no specific alignment - decide based on distance
aligned = centerDst[i] < centerDst[i^1]
|| (centerDst[i] == centerDst[i^1] && i == LEADING);
} else {
aligned = (i == iDesc1.alignment);
if (iDesc1.snappedParallel != null) {
if (seq.isParentOf(iDesc1.snappedParallel)) {
// special case - aligning with interval in the same sequence - to subst. its position
aligned = (i == (iDesc1.alignment^1));
} else if (parent.isParentOf(iDesc1.snappedParallel)
&& originalGap != null && LayoutInterval.canResize(originalGap)) {
// follow alignment of the snapped interval (see ALT_Positioning18Test situation)
int relatedAlign = LayoutInterval.getEffectiveAlignmentInParent(iDesc1.snappedParallel, parent, iDesc1.alignment);
if (relatedAlign == LEADING || relatedAlign == TRAILING) {
aligned = (i == relatedAlign);
}
}
}
}
} else { // both positions defined
if (dragger.isResizing(dimension)) {
if (LayoutInterval.wantResize(addingInterval)) {
aligned = true;
} else if (dragger.getResizingEdge(dimension) == i
&& originalPosition != null && !originalPosition.atFixedPosition(i)
&& originalGap != null && LayoutInterval.canResize(originalGap)) {
aligned = false;
} else {
aligned = iiDesc.fixedPosition || (originalPosition != null && originalPosition.atFixedPosition(i));
}
} else {
aligned = iiDesc.fixedPosition
|| (dragger.isResizing() && originalPosition != null && originalPosition.atFixedPosition(i));
}
}
boolean minorGap = false;
boolean noMinPadding = false;
LayoutInterval otherPar = otherDesc != null ? otherDesc.snappedParallel : null;
checkRoot(parent, root, iDesc1.parent, dimension);
checkRoot(otherPar, root, iDesc1.parent, dimension);
if (!aligned && neighbors[i] == null) { // at the end of the sequence
if (originalGap == null) {
if (outerNeighbor != null && outerNeighbor.isEmptySpace()) {
//continue; // unaligned ending gap not needed - there's a gap outside the parent
minorGap = true;
noMinPadding = true;
} else if (otherPar != null && otherPar.getParent() != null) {
minorGap = parent.isParentOf(otherPar)
|| LayoutInterval.getCount(parent, i^1, true) > 0
|| (neighbors[i^1] == null && LayoutUtils.alignedIntervals(parent, otherPar, i^1));
} else if (!outOfGroup[i^1] && !expanded[i]
&& (LayoutInterval.getCount(parent, i^1, true) > 0
|| (LayoutInterval.getCount(parent, LayoutRegion.ALL_POINTS, true) > 0
&& !LayoutInterval.contentWantResize(parent)))) {
minorGap = true;
}
if (outerNeighbor == null) {
if (otherPar != null && (!otherPar.isParallel() || parent.isParentOf(otherPar))) {
// aligned directly with some component or group as a whole (not from inside)
noMinPadding = !endsWithNonZeroGap(otherPar, i, parent);
} else {
boolean wantMinPadding = (otherPar == null)
&& (seq.getSubIntervalCount() == 0 || endsWithNonZeroGap(seq, i^1, null));
// [or just neighbors[i^1] != null?]
noMinPadding = followEndingPaddingFromNeighbors(
(otherPar != null ? otherPar : parent), seq, i, wantMinPadding)
^ wantMinPadding;
}
}
} else if (minorOriginalGap) { // there is already an unaligned fixed ending gap
minorGap = true;
}
}
boolean fixedGap = aligned;
if (!aligned) {
if ((minorGap && !LayoutInterval.wantResize(parent)) || LayoutInterval.wantResize(addingInterval)) {
fixedGap = true;
} else if (originalGap != null && LayoutInterval.canResize(originalGap)) {
// i.e. fixedGap kept false
if (originalGap.getMinimumSize() == 0 && neighbors[i] == null) {
noMinPadding = true;
}
} else if (originalGap != null && !minorOriginalGap) {
if (!span[i^1]
|| (neighbors[i] == null && !LayoutInterval.canResize(originalGap))
|| (neighbors[i] != null
&& (LayoutInterval.getEffectiveAlignment(neighbors[i], i^1, true) == (i^1)
|| !tiedToParallelSnap(neighbors[i], i, otherPar)))) {
fixedGap = true;
}
} else if (LayoutInterval.wantResize(seq)) {
fixedGap = true;
} else if (neighbors[i] != null) {
if (LayoutInterval.getEffectiveAlignment(neighbors[i], i^1, true) == (i^1)) {
fixedGap = true;
}
} else if (otherPar != null) {
if (parent.isParentOf(otherPar)) {
if (LayoutInterval.getEffectiveAlignmentInParent(otherPar, parent, i^1) == i) {
fixedGap = true;
}
} else {
LayoutInterval p = LayoutInterval.getCommonParent(otherPar, parent);
if (p == parent) {
p = p.getParent();
}
if (p != null && LayoutInterval.getEffectiveAlignmentInParent(parent, p, i) == (i^1)) {
fixedGap = true;
}
}
} else if (!span[i^1]) {
LayoutInterval alignParent = LayoutInterval.getCommonParent(outBounds[LEADING], outBounds[TRAILING]);
int[] effa = new int[2];
for (int e=LEADING; e <= TRAILING; e++) {
LayoutInterval b = outBounds[e];
if (b == alignParent) {
effa[e] = e;
} else {
int edge = (b == parent || b.isParentOf(parent)) ? e : e^1; // parent or neighbor
effa[e] = LayoutInterval.getEffectiveAlignmentInParent(b, alignParent, edge);
}
}
if (effa[LEADING] == effa[TRAILING]) {
fixedGap = true;
}
}
}
if (!aligned && (!fixedGap || minorGap)
&& neighbors[i] == null && originalGap == null
&& seq.getSubIntervalCount() == 0 && seq.getRawAlignment() == DEFAULT
&& (otherPar == null || !parent.isParentOf(otherPar))) {
// this new sequence should be aligned to opposite edge
layoutModel.setIntervalAlignment(seq, i^1);
}
if (fixedGap && noMinPadding) { // minorPadding
continue;
}
LayoutInterval gap = new LayoutInterval(SINGLE);
if (!minorGap || !fixedGap) {
if (iiDesc == null || iiDesc.snappedNextTo == null) {
// the gap possibly needs an explicit size
int distance;
LayoutRegion space = iiDesc != null && iiDesc.snappedParallel != null ?
iiDesc.snappedParallel.getCurrentSpace() : addingSpace;
distance = neighbors[i] != null ?
LayoutRegion.distance(neighbors[i].getCurrentSpace(), space, dimension, i^1, i) :
LayoutRegion.distance(parent.getCurrentSpace(), space, dimension, i, i);
if (i == TRAILING) {
distance *= -1;
}
if (distance > 0) {
int pad;
if (neighbors[i] != null || outerNeighbor == null) {
int[] pads = dragger.findPaddings(neighbors[i], addingInterval, PaddingType.RELATED, dimension, i);
pad = (pads != null && pads.length > 0) ? pads[0] : 0;
} else {
pad = Short.MIN_VALUE; // has no neighbor, but is not related to container border
}
if (distance > pad || (fixedGap && distance != pad)) {
gap.setPreferredSize(distance);
if (fixedGap) {
gap.setMinimumSize(USE_PREFERRED_SIZE);
gap.setMaximumSize(USE_PREFERRED_SIZE);
}
}
} else if (noMinPadding) {
gap.setPreferredSize(0);
}
if (fixedGap && gap.getPreferredSize() == NOT_EXPLICITLY_DEFINED
&& neighbors[i] != null
&& !LayoutUtils.isDefaultGapValidForNeighbor(neighbors[i], i^1)) {
// likely a parallel neighbor group ending with gaps (could be created by mergeParallelInclusions)
continue;
}
} else {
gap.setPaddingType(iiDesc.paddingType);
}
}
if (!fixedGap) {
if (noMinPadding) {
gap.setMinimumSize(0);
}
gap.setMaximumSize(Short.MAX_VALUE);
}
gap.setAttribute(LayoutInterval.ATTR_FLEX_SIZEDEF);
gaps[i] = gap;
// if anchored towards open parent group edge, we may want to move the
// sequence out to place it independently on the rest of the group
if (definite && (otherDesc == null || otherDesc.alignment < 0)) {
if (!subseq && parent.getParent() != null) {
// a) adding into main sequence directly
if (!fixedGap && neighbors[i] != null
&& outBounds[i^1] != parent
&& !parent.isParentOf(outBounds[i^1])) {
// should not close open group by making a resizing sequence
parent = separateSequence(seq, i^1, iDesc1, iDesc2);
checkRoot(parent, root, iDesc1.parent, dimension);
if (i == TRAILING) {
edges++; // we need to revisit the LEADING gap
}
}
} else if (subseq && iDesc1.parent.getParent().getParent() != null) {
// b) adding into sub-sequence (in parallel with part of main
// sequence), iDesc1.parent is the main sequence
if (!fixedGap
&& LayoutInterval.getDirectNeighbor(parent, i, true) != null
&& outBounds[i^1] != iDesc1.parent.getParent()
&& !iDesc1.parent.getParent().isParentOf(outBounds[i^1])) {
// should not close open group by making a resizing sequence
LayoutInterval p = separateSequence(iDesc1.parent, i^1, iDesc1, iDesc2);
if (parent.getSubIntervalCount() == 0 && parent.getParent() == null) {
parent = p; // optimized out during the operation
checkRoot(parent, root, iDesc1.parent, dimension);
} else {
checkRoot(parent, root, iDesc1.parent, dimension);
setCurrentPositionToParent(parent, p, dimension, i^1);
}
if (i == TRAILING) {
edges++; // we need to revisit the LEADING gap
}
}
}
}
}
// try to determine actual positions of the sequence ends
for (int i = LEADING; i <= TRAILING; i++) {
if (neighbors[i] == null && !seq.getCurrentSpace().isSet(dimension, i)) {
int pos = LayoutRegion.UNKNOWN;
IncludeDesc iiDesc = iDesc1.alignment < 0 || iDesc1.alignment == i ? iDesc1 : iDesc2;
if (iiDesc != null && iiDesc.snappedParallel != null) {
pos = iiDesc.snappedParallel.getCurrentSpace().positions[dimension][i];
} else if (iiDesc != null && iiDesc.snappedNextTo != null) {
pos = parent.getCurrentSpace().positions[dimension][i];
} else if (gaps[i] == null || gaps[i].getPreferredSize() == 0) {
pos = addingInterval.getCurrentSpace().positions[dimension][i];
}
if (pos != LayoutRegion.UNKNOWN) {
seq.getCurrentSpace().setPos(dimension, i, pos);
}
}
}
if (seq.getParent() == null) { // newly created sequence
assert seq.getSubIntervalCount() == 0;
checkRoot(parent, root, iDesc1.parent, dimension);
if (gaps[LEADING] == null && gaps[TRAILING] == null) { // after all, the sequence is not needed
layoutModel.setIntervalAlignment(addingInterval, seq.getAlignment());
layoutModel.addInterval(addingInterval, parent, -1);
return;
} else {
layoutModel.addInterval(seq, parent, -1);
}
}
// aligning in parallel with interval in the same sequence was resolved
// by substituting its position
if (iDesc1.snappedParallel != null && seq.isParentOf(iDesc1.snappedParallel)) {
iDesc1.snappedParallel = null; // set to null not to try alignInParallel later
}
// finally add the surrounding gaps and the interval
if (originalGap != null) {
index = layoutModel.removeInterval(originalGap);
}
else if (neighbors[TRAILING] != null) {
index = seq.indexOf(neighbors[TRAILING]);
}
else if (neighbors[LEADING] != null) {
index = seq.getSubIntervalCount();
}
else index = 0;
if (gaps[LEADING] != null) {
layoutModel.addInterval(gaps[LEADING], seq, index++);
}
layoutModel.setIntervalAlignment(addingInterval, DEFAULT);
if (definite) {
index += operations.addContent(addingInterval, seq, index);
} else { // avoid optimizations
assert !addingInterval.isSequential();
layoutModel.addInterval(addingInterval, seq, index++);
}
if (gaps[TRAILING] != null) {
layoutModel.addInterval(gaps[TRAILING], seq, index);
}
}