private void mergeInclusionsInCommonSequence()

in java/form/src/org/netbeans/modules/form/layoutdesign/LayoutFeeder.java [4447:4791]


    private void mergeInclusionsInCommonSequence(IncludeDesc iDesc1, IncludeDesc iDesc2, LayoutInterval commonGroup) {
        boolean more;
        do {
            more = false;
            int startIndex = 0;
            LayoutInterval ext1 = null;
            int depth1 = 0;
            boolean startGap = false;
            int endIndex = 0;
            LayoutInterval ext2 = null;
            int depth2 = 0;
            boolean endGap = false;
            boolean goingParallel = false;

            if (commonGroup.isSequential()) {
                if (commonGroup.isParentOf(iDesc1.parent)) {
                    startIndex = LayoutInterval.getIndexInParent(iDesc1.parent, commonGroup);
                    depth1 = 1;
                    ext1 = intervalToExtractIntoCommonSequence(iDesc1, commonGroup);
                    if (ext1 != null) {
                        int d = LayoutInterval.getDepthInParent(iDesc1.parent, ext1);
                        if (d > 0) {
                            depth1 += d;
                        }
                    }
                    if (dragger.isResizing(dimension)) {
                        LayoutInterval inSequence = (iDesc1.parent.isSequential() && !iDesc1.newSubGroup)
                                ? iDesc1.parent : iDesc1.neighbor;
                        if (inSequence != null && LayoutUtils.contentOverlap(addingSpace, inSequence, dimension)) {
                            goingParallel = true; // resizing in parallel with original sequence
                        }
                    }
                } else {
                    startIndex = iDesc1.index;
                    if (iDesc1.snappedParallel != null && commonGroup.isParentOf(iDesc1.snappedParallel)
                            && iDesc1.newSubGroup && dragger.isResizing(dimension)) {
                        startIndex = LayoutInterval.getIndexInParent(iDesc1.snappedParallel, commonGroup);
                    } else {
                        if (startIndex == commonGroup.getSubIntervalCount()) {
                            startIndex--;
                        }
                        startGap = commonGroup.getSubInterval(startIndex).isEmptySpace();
                    }
                }

                if (commonGroup.isParentOf(iDesc2.parent)) {
                    endIndex = LayoutInterval.getIndexInParent(iDesc2.parent, commonGroup);
                    depth2 = 1;
                    ext2 = intervalToExtractIntoCommonSequence(iDesc2, commonGroup);
                    if (ext2 != null) {
                        int d = LayoutInterval.getDepthInParent(iDesc2.parent, ext2);
                        if (d > 0) {
                            depth2 += d;
                        }
                    }
                    if (dragger.isResizing(dimension)) {
                        LayoutInterval inSequence = (iDesc2.parent.isSequential() && !iDesc2.newSubGroup)
                                ? iDesc2.parent : iDesc2.neighbor;
                        if (inSequence != null && LayoutUtils.contentOverlap(addingSpace, inSequence, dimension)) {
                            goingParallel = true; // resizing in parallel with original sequence
                        }
                    }
                } else {
                    endIndex = iDesc2.index;
                    if (iDesc2.snappedParallel != null && commonGroup.isParentOf(iDesc2.snappedParallel)) {
                        if (iDesc2.newSubGroup && dragger.isResizing(dimension)) {
                            endIndex = LayoutInterval.getIndexInParent(iDesc2.snappedParallel, commonGroup);
                        }
                        if (endIndex == commonGroup.getSubIntervalCount()) {
                            endIndex--;
                        }
                    } else if (endIndex > 0) {
                        endGap = commonGroup.getSubInterval(--endIndex).isEmptySpace();
                    }
                }
            }

            boolean validSection = (endIndex > startIndex + 1 || (endIndex == startIndex+1
                    && (!startGap || iDesc1.snappedParallel != null) && (!endGap || iDesc2.snappedParallel != null)));
            if (validSection && (ext1 != null || ext2 != null)) {
                // there is a significant part of the common sequence to be parallelized
                LayoutInterval extSeq = new LayoutInterval(SEQUENTIAL);
                LayoutInterval startInt = commonGroup.getSubInterval(startIndex);
                LayoutInterval endInt = commonGroup.getSubInterval(endIndex);
                int posL = LayoutUtils.getVisualPosition(startInt, dimension, LEADING);
                int posT = LayoutUtils.getVisualPosition(endInt, dimension, TRAILING);

                // check visual overlap of the extracted intervals with the part of the sequence
                LayoutInterval parConnectingGap = null;
                LayoutInterval extConnectingGap = null;
                // temporarily remove ext1 and ext2 for analysis
                LayoutInterval parent1, parent2;
                int idx1, idx2;
                if (ext1 != null) {
                    parent1 = ext1.getParent();
                    idx1 = parent1.remove(ext1);
                } else {
                    parent1 = null; idx1 = -1;
                }
                if (ext2 != null) {
                    parent2 = ext2.getParent();
                    idx2 = parent2.remove(ext2);
                } else {
                    parent2 = null; idx2 = -1;
                }
                // Check if can extract ext1 and ext2 in parallel with whole sub-sequence
                // from startIndex to endIndex, or just with the first/last interval at
                // startIndex or endIndex (due to orthogonal overlap of ext1/ext2 with
                // something from the sequence).
                if (ext1 != null
                        && !LayoutInterval.isClosedGroup(startInt, TRAILING)
                        && LayoutUtils.contentOverlap(ext1, commonGroup, startIndex+1, endIndex, dimension^1)
                        && !LayoutUtils.contentOverlap(startInt, commonGroup, startIndex+1, endIndex, dimension^1)) {
                    while (startIndex < endIndex) {
                        layoutModel.addInterval(layoutModel.removeInterval(commonGroup, startIndex+1), extSeq, -1);
                        endIndex--;
                    }
                    if (extSeq.getSubIntervalCount() > 0) {
                        LayoutInterval li = extSeq.getSubInterval(extSeq.getSubIntervalCount()-1);
                        if (li.isEmptySpace()) { // cut everything after startInt, so at least clone the last gap
                            parConnectingGap = LayoutInterval.cloneInterval(li, null);
                        }
                        li = extSeq.getSubInterval(0);
                        if (li.isEmptySpace()) {
                            extConnectingGap = li;
                        }
                    }
                    if (ext2 != null) {
                        parent2.add(ext2, idx2);
                        ext2 = null; // don't extract ext2 in this round (its parent just moved to extSeq)
                        if (depth2 == 1) {
                            depth2 = 2; // don't adjust iDesc2 and do one more round
                        }
                    }
                } else if (ext2 != null
                           && !LayoutInterval.isClosedGroup(endInt, LEADING)
                           && LayoutUtils.contentOverlap(ext2, commonGroup, startIndex, endIndex-1, dimension^1)
                           && !LayoutUtils.contentOverlap(endInt, commonGroup, startIndex, endIndex-1, dimension^1)) {
                    while (startIndex < endIndex) {
                        layoutModel.addInterval(layoutModel.removeInterval(commonGroup, startIndex), extSeq, -1);
                        endIndex--;
                    }
                    if (extSeq.getSubIntervalCount() > 0) {
                        LayoutInterval li = extSeq.getSubInterval(0);
                        if (li.isEmptySpace()) { // cut everything before endInt, so at least clone the first gap
                            parConnectingGap = LayoutInterval.cloneInterval(li, null);
                        }
                        li = extSeq.getSubInterval(extSeq.getSubIntervalCount()-1);
                        if (li.isEmptySpace()) {
                            extConnectingGap = li;
                        }
                    }
                    if (ext1 != null) {
                        parent1.add(ext1, idx1);
                        ext1 = null; // don't extract ext1 in this round (its parent just moved to extSeq)
                        if (depth1 == 1) {
                            depth1 = 2; // don't adjust iDesc1 and do one more round
                        }
                    }
                }
                // return back ext1 and ext2
                if (ext1 != null) {
                    parent1.add(ext1, idx1);
                }
                if (ext2 != null) {
                    parent2.add(ext2, idx2);
                }

                LayoutInterval parGroup;
                if (startIndex == 0 && endIndex == commonGroup.getSubIntervalCount()-1) {
                    // parallel with whole sequence
                    parGroup = commonGroup.getParent();
                } else { // separate part of the original sequence
                    parGroup = new LayoutInterval(PARALLEL);
                    LayoutInterval parSeq = new LayoutInterval(SEQUENTIAL);
                    parGroup.add(parSeq, 0);
                    parGroup.getCurrentSpace().set(dimension, posL, posT);
                    while (startIndex <= endIndex) {
                        layoutModel.addInterval(layoutModel.removeInterval(commonGroup, startIndex), parSeq, -1);
                        endIndex--;
                    }
                    layoutModel.addInterval(parGroup, commonGroup, startIndex);
                }
                layoutModel.addInterval(extSeq, parGroup, -1);
                if (ext1 != null) {
                    LayoutInterval parent = ext1.getParent();
                    layoutModel.removeInterval(ext1);
                    if (LayoutInterval.hasAnyResizingNeighbor(parent, TRAILING)
                            && LayoutInterval.getCount(parent, TRAILING, true) > 0
                            && !LayoutInterval.wantResize(parent)) {
                        operations.maintainSize(parent, LayoutInterval.wantResize(ext1), dimension, false);
                    }
                    if (parent.getSubIntervalCount() == 1) {
                        LayoutInterval last = layoutModel.removeInterval(parent, 0);
                        operations.addContent(last, parent.getParent(), layoutModel.removeInterval(parent), dimension);
                        if (parent == startInt) {
                            startInt = last;
                        }
                    }
                    int beforeCount = extSeq.getSubIntervalCount();
                    operations.addContent(ext1, extSeq, 0, dimension);
                    if (depth1 == 1 && !iDesc1.parent.isSequential()) {
                        iDesc1.index = extSeq.getSubIntervalCount() - beforeCount;
                    }
                    if (depth2 <= 1) {
                        if (ext2 == null || !iDesc2.parent.isSequential()) {
                            iDesc2.index = extSeq.getSubIntervalCount();
                        } else {
                            iDesc2.index += extSeq.getSubIntervalCount();
                        }
                    }
                    if (ext2 != null) {
                        LayoutInterval gap = new LayoutInterval(SINGLE);
                        int size = LayoutRegion.distance(ext1.getCurrentSpace(), ext2.getCurrentSpace(), dimension, LEADING, TRAILING);
                        gap.setSize(size);
                        layoutModel.addInterval(gap, extSeq, -1);
                    } else { // could have moved things next to startInt to extSeq
                        if (parConnectingGap != null) {
                            parent = startInt.getParent();
                            if (!parent.isSequential()) {
                                LayoutInterval seq = new LayoutInterval(SEQUENTIAL);
                                layoutModel.addInterval(seq, parent, layoutModel.removeInterval(startInt));
                                layoutModel.addInterval(startInt, seq, 0);
                                parent = seq;
                            }
                            assert parent.indexOf(startInt) == 0;
                            layoutModel.addInterval(parConnectingGap, parent, 1);
                        }
                        if (extConnectingGap != null) {
                            operations.accommodateGap(extConnectingGap, dimension);
                            if (LayoutInterval.wantResize(startInt) && !LayoutInterval.wantResize(extSeq)) {
                                operations.setIntervalResizing(extConnectingGap, true);
                            }
                        }
                    }
                } else {
                    iDesc1.index = 0;
                    if (depth2 <= 1 && !iDesc2.parent.isSequential()) {
                        iDesc2.index = extSeq.getSubIntervalCount();
                    }
                }
                if (ext2 != null) {
                    LayoutInterval parent = ext2.getParent();
                    if (ext2.getAlignment() == TRAILING) {
                        extSeq.setAlignment(TRAILING);
                    }
                    layoutModel.removeInterval(ext2);
                    if (LayoutInterval.hasAnyResizingNeighbor(parent, LEADING)
                            && LayoutInterval.getCount(parent, LEADING, true) > 0
                            && !LayoutInterval.wantResize(parent)) {
                        operations.maintainSize(parent, LayoutInterval.wantResize(ext2), dimension, false);
                    }
                    if (parent.getSubIntervalCount() == 1) {
                        LayoutInterval last = layoutModel.removeInterval(parent, 0);
                        operations.addContent(last, parent.getParent(), layoutModel.removeInterval(parent), dimension);
                        if (parent == endInt) {
                            endInt = last;
                        }
                    }
                    operations.addContent(ext2, extSeq, -1, dimension);
                    if (ext1 == null) { // could have moved things next to endInt to extSeq
                        if (parConnectingGap != null) {
                            parent = endInt.getParent();
                            if (!parent.isSequential()) {
                                LayoutInterval seq = new LayoutInterval(SEQUENTIAL);
                                layoutModel.addInterval(seq, parent, layoutModel.removeInterval(endInt));
                                layoutModel.addInterval(endInt, seq, 0);
                                parent = seq;
                            }
                            assert parent.indexOf(endInt) == 0;
                            layoutModel.addInterval(parConnectingGap, parent, 0);
                        }
                        if (extConnectingGap != null) {
                            operations.accommodateGap(extConnectingGap, dimension);
                            if (LayoutInterval.wantResize(endInt) && !LayoutInterval.wantResize(extSeq)) {
                                operations.setIntervalResizing(extConnectingGap, true);
                            }
                        }
                    }
                }

                if (depth1 <= 1) {
                    boolean newSubGroupBeforeMerge = iDesc1.parent == commonGroup && iDesc1.newSubGroup;
                    iDesc1.parent = extSeq;
                    if (iDesc2.newSubGroup) {
                        iDesc1.newSubGroup = true;
                    } else if (newSubGroupBeforeMerge) {
                        iDesc1.newSubGroup = false; // actually just created the sub-group
                    }
                    iDesc1.neighbor = null;
                }
                if (depth2 <= 1) {
                    iDesc2.parent = extSeq;
                    if (iDesc1.newSubGroup) {
                        iDesc2.newSubGroup = true;
                    }
                    iDesc2.neighbor = null;
                }
                commonGroup = extSeq;
                more = depth1 > 1 || depth2 > 1;
                optimizeStructure = true;
            } else if (ext1 == null && ext2 == null && validSection) {
                // nothing to extract, but the resizing interval still to be in
                // parallel with part of the sequence
                if (commonGroup.isParentOf(iDesc1.parent)) {
                    iDesc1.index = startIndex;
                }
                if (commonGroup.isParentOf(iDesc2.parent)) {
                    iDesc2.index = endIndex;
                }
                iDesc1.parent = iDesc2.parent = commonGroup;
                iDesc1.newSubGroup = iDesc2.newSubGroup = true;
                iDesc1.neighbor = iDesc2.neighbor = null;
            } else {
                // prefer sub-group in case of end position, outer group in case
                // of resizing in parallel with sub-group
                boolean p1 = iDesc1.parent.isParentOf(iDesc2.parent);
                boolean p2 = iDesc2.parent.isParentOf(iDesc1.parent);
                if ((p2 && !goingParallel) || (p1 && goingParallel)) {
                    iDesc2.parent = iDesc1.parent;
                    iDesc2.index = iDesc1.index;
                    iDesc2.newSubGroup = iDesc1.newSubGroup;
                    iDesc2.neighbor = iDesc1.neighbor;
                    if (endGap) // there's an outer gap
                        iDesc2.fixedPosition = false;
                } else if ((p1 && !goingParallel) || (p2 && goingParallel)) {
                    iDesc1.parent = iDesc2.parent;
                    iDesc1.index = iDesc2.index;
                    iDesc1.newSubGroup = iDesc2.newSubGroup;
                    iDesc1.neighbor = iDesc2.neighbor;
                    if (startGap) // there's an outer gap
                        iDesc1.fixedPosition = false;
                }
            }
        } while (more);

        // might originally be snapped to a group that has just been optimized out
        // [TODO better would be to subst. it with a representative component]
        if (iDesc1.snappedParallel != null && iDesc1.snappedParallel.isParallel() && iDesc1.snappedParallel.getSubIntervalCount() == 0) {
            iDesc1.snappedParallel = null;
        }
        if (iDesc2.snappedParallel != null && iDesc2.snappedParallel.isParallel() && iDesc2.snappedParallel.getSubIntervalCount() == 0) {
            iDesc2.snappedParallel = null;
        }
    }