List<Range> calculateModifiedRanges(final JsArrayInteger modifiedRows, final int pageStart, final int pageEnd) {
        sortJsArrayInteger(modifiedRows);

        int rangeStart0 = -1;
        int rangeEnd0 = -1;
        int rangeStart1 = -1;
        int rangeEnd1 = -1;
        int maxDiff = 0;
        for (int i = 0; i < modifiedRows.length(); i++) {
            final int index = modifiedRows.get(i);
            if (index < pageStart || index >= pageEnd) {
                // The index is out of range of the current page.
                continue;
            } else if (rangeStart0 == -1) {
                // Range0 defaults to the first index.
                rangeStart0 = index;
                rangeEnd0 = index;
            } else if (rangeStart1 == -1) {
                // Range1 defaults to the second index.
                maxDiff = index - rangeEnd0;
                rangeStart1 = index;
                rangeEnd1 = index;
            } else {
                final int diff = index - rangeEnd1;
                if (diff > maxDiff) {
                    // Move the old range1 onto range0 and start range1 from
                    // this index.
                    rangeEnd0 = rangeEnd1;
                    rangeStart1 = index;
                    rangeEnd1 = index;
                    maxDiff = diff;
                } else {
                    // Add this index to range1.
                    rangeEnd1 = index;
                }
            }
        }

        // Convert the range ends to exclusive indexes for calculations.
        rangeEnd0 += 1;
        rangeEnd1 += 1;

        // Combine the ranges if they are continuous.
        if (rangeStart1 == rangeEnd0) {
            rangeEnd0 = rangeEnd1;
            rangeStart1 = -1;
            rangeEnd1 = -1;
        }

        // Return the ranges.
        final List<Range> toRet = new ArrayList<>();
        if (rangeStart0 != -1) {
            final int rangeLength0 = rangeEnd0 - rangeStart0;
            toRet.add(new Range(rangeStart0, rangeLength0));
        }
        if (rangeStart1 != -1) {
            final int rangeLength1 = rangeEnd1 - rangeStart1;
            toRet.add(new Range(rangeStart1, rangeLength1));
        }
        return toRet;
    }
Combine the modified row indexes into as many as two {@link Range}s,
optimizing to have the fewest unmodified rows within the ranges. Using
two ranges covers the most common use cases of selecting one row,
selecting a range, moving selection from one row to another, or moving
keyboard selection.
<p>
<p>
Visible for testing.
</p>
<p>
<p>
This method has the side effect of sorting the modified rows.
</p>

@param modifiedRows the unordered indexes of modified rows
@return up to two ranges that encompass the modified rows
stroom-core-client-widget/src/main/java/com/google/gwt/user/cellview/client/HasDataPresenter.java