private void addToGroup()

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);
        }
    }