From: Javen O'Neal Date: Mon, 20 Jun 2016 00:25:29 +0000 (+0000) Subject: mv o.a.p.hssf.record.cf.CellRangeUtil o.a.p.ss.util.CellRangeUtil X-Git-Tag: REL_3_15_BETA2~42 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=7e7b5b09c2e8231c52814633eda7bd5a181e82c6;p=poi.git mv o.a.p.hssf.record.cf.CellRangeUtil o.a.p.ss.util.CellRangeUtil git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1749240 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/hssf/record/CFHeaderBase.java b/src/java/org/apache/poi/hssf/record/CFHeaderBase.java index dc7052de45..3784638657 100644 --- a/src/java/org/apache/poi/hssf/record/CFHeaderBase.java +++ b/src/java/org/apache/poi/hssf/record/CFHeaderBase.java @@ -17,9 +17,9 @@ package org.apache.poi.hssf.record; -import org.apache.poi.hssf.record.cf.CellRangeUtil; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.ss.util.CellRangeUtil; import org.apache.poi.util.LittleEndianOutput; /** diff --git a/src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java b/src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java deleted file mode 100644 index cde666a8ed..0000000000 --- a/src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java +++ /dev/null @@ -1,269 +0,0 @@ -/* ==================================================================== - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -==================================================================== */ - -package org.apache.poi.hssf.record.cf; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.poi.ss.util.CellRangeAddress; - -/** - * TODO Should this move to org.apache.poi.ss.util ? - */ -public final class CellRangeUtil { - private CellRangeUtil() { - // no instance of this class - } - - public static final int NO_INTERSECTION = 1; - public static final int OVERLAP = 2; - /** first range is within the second range */ - public static final int INSIDE = 3; - /** first range encloses or is equal to the second */ - public static final int ENCLOSES = 4; - - /** - * Intersect this range with the specified range. - * - * @param crB - the specified range - * @return code which reflects how the specified range is related to this range.
- * Possible return codes are: - * NO_INTERSECTION - the specified range is outside of this range;
- * OVERLAP - both ranges partially overlap;
- * INSIDE - the specified range is inside of this one
- * ENCLOSES - the specified range encloses (possibly exactly the same as) this range
- */ - public static int intersect(CellRangeAddress crA, CellRangeAddress crB ) - { - - int firstRow = crB.getFirstRow(); - int lastRow = crB.getLastRow(); - int firstCol = crB.getFirstColumn(); - int lastCol = crB.getLastColumn(); - - if - ( - gt(crA.getFirstRow(),lastRow) || - lt(crA.getLastRow(),firstRow) || - gt(crA.getFirstColumn(),lastCol) || - lt(crA.getLastColumn(),firstCol) - ) - { - return NO_INTERSECTION; - } - else if( contains(crA, crB) ) - { - return INSIDE; - } - else if( contains(crB, crA)) - { - return ENCLOSES; - } - else - { - return OVERLAP; - } - } - - /** - * Do all possible cell merges between cells of the list so that:
- *
  • if a cell range is completely inside of another cell range, it gets removed from the list - *
  • if two cells have a shared border, merge them into one bigger cell range - * @param cellRanges - * @return updated List of cell ranges - */ - public static CellRangeAddress[] mergeCellRanges(CellRangeAddress[] cellRanges) { - if(cellRanges.length < 1) { - return cellRanges; - } - - List lst = new ArrayList(); - for(CellRangeAddress cr : cellRanges) { - lst.add(cr); - } - List temp = mergeCellRanges(lst); - return toArray(temp); - } - - private static List mergeCellRanges(List cellRangeList) - { - // loop until either only one item is left or we did not merge anything any more - while (cellRangeList.size() > 1) { - boolean somethingGotMerged = false; - - // look at all cell-ranges - for (int i = 0; i < cellRangeList.size(); i++) { - CellRangeAddress range1 = cellRangeList.get(i); - - // compare each cell range to all other cell-ranges - for (int j = i + 1; j < cellRangeList.size(); j++) { - CellRangeAddress range2 = cellRangeList.get(j); - - CellRangeAddress[] mergeResult = mergeRanges(range1, range2); - if (mergeResult == null) { - continue; - } - somethingGotMerged = true; - // overwrite range1 with first result - cellRangeList.set(i, mergeResult[0]); - // remove range2 - cellRangeList.remove(j--); - // add any extra results beyond the first - for (int k = 1; k < mergeResult.length; k++) { - j++; - cellRangeList.add(j, mergeResult[k]); - } - } - } - if (!somethingGotMerged) { - break; - } - } - - return cellRangeList; - } - - /** - * @return the new range(s) to replace the supplied ones. null if no merge is possible - */ - private static CellRangeAddress[] mergeRanges(CellRangeAddress range1, CellRangeAddress range2) { - int x = intersect(range1, range2); - switch(x) - { - case CellRangeUtil.NO_INTERSECTION: - // nothing in common: at most they could be adjacent to each other and thus form a single bigger area - if(hasExactSharedBorder(range1, range2)) { - return new CellRangeAddress[] { createEnclosingCellRange(range1, range2), }; - } - // else - No intersection and no shared border: do nothing - return null; - case CellRangeUtil.OVERLAP: - // commented out the cells overlap implementation, it caused endless loops, see Bug 55380 - // disabled for now, the algorithm will not detect some border cases this way currently! - //return resolveRangeOverlap(range1, range2); - return null; - case CellRangeUtil.INSIDE: - // Remove range2, since it is completely inside of range1 - return new CellRangeAddress[] { range1 }; - case CellRangeUtil.ENCLOSES: - // range2 encloses range1, so replace it with the enclosing one - return new CellRangeAddress[] { range2 }; - } - throw new RuntimeException("unexpected intersection result (" + x + ")"); - } - - private static CellRangeAddress[] toArray(List temp) { - CellRangeAddress[] result = new CellRangeAddress[temp.size()]; - temp.toArray(result); - return result; - } - - /** - * Check if the specified range is located inside of this cell range. - * - * @param crB - * @return true if this cell range contains the argument range inside if it's area - */ - public static boolean contains(CellRangeAddress crA, CellRangeAddress crB) - { - int firstRow = crB.getFirstRow(); - int lastRow = crB.getLastRow(); - int firstCol = crB.getFirstColumn(); - int lastCol = crB.getLastColumn(); - return le(crA.getFirstRow(), firstRow) && ge(crA.getLastRow(), lastRow) - && le(crA.getFirstColumn(), firstCol) && ge(crA.getLastColumn(), lastCol); - } - - /** - * Check if the two cell ranges have a shared border. - * - * @return true if the ranges have a complete shared border (i.e. - * the two ranges together make a simple rectangular region. - */ - public static boolean hasExactSharedBorder(CellRangeAddress crA, CellRangeAddress crB) { - int oFirstRow = crB.getFirstRow(); - int oLastRow = crB.getLastRow(); - int oFirstCol = crB.getFirstColumn(); - int oLastCol = crB.getLastColumn(); - - if (crA.getFirstRow() > 0 && crA.getFirstRow()-1 == oLastRow || - oFirstRow > 0 && oFirstRow-1 == crA.getLastRow()) { - // ranges have a horizontal border in common - // make sure columns are identical: - return crA.getFirstColumn() == oFirstCol && crA.getLastColumn() == oLastCol; - } - - if (crA.getFirstColumn()>0 && crA.getFirstColumn() - 1 == oLastCol || - oFirstCol>0 && crA.getLastColumn() == oFirstCol -1) { - // ranges have a vertical border in common - // make sure rows are identical: - return crA.getFirstRow() == oFirstRow && crA.getLastRow() == oLastRow; - } - return false; - } - - /** - * Create an enclosing CellRange for the two cell ranges. - * - * @return enclosing CellRange - */ - public static CellRangeAddress createEnclosingCellRange(CellRangeAddress crA, CellRangeAddress crB) { - if( crB == null) { - return crA.copy(); - } - - return new CellRangeAddress( - lt(crB.getFirstRow(), crA.getFirstRow()) ?crB.getFirstRow() :crA.getFirstRow(), - gt(crB.getLastRow(), crA.getLastRow()) ?crB.getLastRow() :crA.getLastRow(), - lt(crB.getFirstColumn(),crA.getFirstColumn())?crB.getFirstColumn():crA.getFirstColumn(), - gt(crB.getLastColumn(), crA.getLastColumn()) ?crB.getLastColumn() :crA.getLastColumn() - ); - } - - /** - * @return true if a < b - */ - private static boolean lt(int a, int b) - { - return a == -1 ? false : (b == -1 ? true : a < b); - } - - /** - * @return true if a <= b - */ - private static boolean le(int a, int b) - { - return a == b || lt(a,b); - } - - /** - * @return true if a > b - */ - private static boolean gt(int a, int b) - { - return lt(b,a); - } - - /** - * @return true if a >= b - */ - private static boolean ge(int a, int b) - { - return !lt(a,b); - } -} diff --git a/src/java/org/apache/poi/ss/util/CellRangeUtil.java b/src/java/org/apache/poi/ss/util/CellRangeUtil.java new file mode 100644 index 0000000000..3ecba186a0 --- /dev/null +++ b/src/java/org/apache/poi/ss/util/CellRangeUtil.java @@ -0,0 +1,264 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.ss.util; + +import java.util.ArrayList; +import java.util.List; + +public final class CellRangeUtil { + private CellRangeUtil() { + // no instance of this class + } + + public static final int NO_INTERSECTION = 1; + public static final int OVERLAP = 2; + /** first range is within the second range */ + public static final int INSIDE = 3; + /** first range encloses or is equal to the second */ + public static final int ENCLOSES = 4; + + /** + * Intersect this range with the specified range. + * + * @param crB - the specified range + * @return code which reflects how the specified range is related to this range.
    + * Possible return codes are: + * NO_INTERSECTION - the specified range is outside of this range;
    + * OVERLAP - both ranges partially overlap;
    + * INSIDE - the specified range is inside of this one
    + * ENCLOSES - the specified range encloses (possibly exactly the same as) this range
    + */ + public static int intersect(CellRangeAddress crA, CellRangeAddress crB ) + { + + int firstRow = crB.getFirstRow(); + int lastRow = crB.getLastRow(); + int firstCol = crB.getFirstColumn(); + int lastCol = crB.getLastColumn(); + + if + ( + gt(crA.getFirstRow(),lastRow) || + lt(crA.getLastRow(),firstRow) || + gt(crA.getFirstColumn(),lastCol) || + lt(crA.getLastColumn(),firstCol) + ) + { + return NO_INTERSECTION; + } + else if( contains(crA, crB) ) + { + return INSIDE; + } + else if( contains(crB, crA)) + { + return ENCLOSES; + } + else + { + return OVERLAP; + } + } + + /** + * Do all possible cell merges between cells of the list so that:
    + *
  • if a cell range is completely inside of another cell range, it gets removed from the list + *
  • if two cells have a shared border, merge them into one bigger cell range + * @param cellRanges + * @return updated List of cell ranges + */ + public static CellRangeAddress[] mergeCellRanges(CellRangeAddress[] cellRanges) { + if(cellRanges.length < 1) { + return cellRanges; + } + + List lst = new ArrayList(); + for(CellRangeAddress cr : cellRanges) { + lst.add(cr); + } + List temp = mergeCellRanges(lst); + return toArray(temp); + } + + private static List mergeCellRanges(List cellRangeList) + { + // loop until either only one item is left or we did not merge anything any more + while (cellRangeList.size() > 1) { + boolean somethingGotMerged = false; + + // look at all cell-ranges + for (int i = 0; i < cellRangeList.size(); i++) { + CellRangeAddress range1 = cellRangeList.get(i); + + // compare each cell range to all other cell-ranges + for (int j = i + 1; j < cellRangeList.size(); j++) { + CellRangeAddress range2 = cellRangeList.get(j); + + CellRangeAddress[] mergeResult = mergeRanges(range1, range2); + if (mergeResult == null) { + continue; + } + somethingGotMerged = true; + // overwrite range1 with first result + cellRangeList.set(i, mergeResult[0]); + // remove range2 + cellRangeList.remove(j--); + // add any extra results beyond the first + for (int k = 1; k < mergeResult.length; k++) { + j++; + cellRangeList.add(j, mergeResult[k]); + } + } + } + if (!somethingGotMerged) { + break; + } + } + + return cellRangeList; + } + + /** + * @return the new range(s) to replace the supplied ones. null if no merge is possible + */ + private static CellRangeAddress[] mergeRanges(CellRangeAddress range1, CellRangeAddress range2) { + int x = intersect(range1, range2); + switch(x) + { + case CellRangeUtil.NO_INTERSECTION: + // nothing in common: at most they could be adjacent to each other and thus form a single bigger area + if(hasExactSharedBorder(range1, range2)) { + return new CellRangeAddress[] { createEnclosingCellRange(range1, range2), }; + } + // else - No intersection and no shared border: do nothing + return null; + case CellRangeUtil.OVERLAP: + // commented out the cells overlap implementation, it caused endless loops, see Bug 55380 + // disabled for now, the algorithm will not detect some border cases this way currently! + //return resolveRangeOverlap(range1, range2); + return null; + case CellRangeUtil.INSIDE: + // Remove range2, since it is completely inside of range1 + return new CellRangeAddress[] { range1 }; + case CellRangeUtil.ENCLOSES: + // range2 encloses range1, so replace it with the enclosing one + return new CellRangeAddress[] { range2 }; + } + throw new RuntimeException("unexpected intersection result (" + x + ")"); + } + + private static CellRangeAddress[] toArray(List temp) { + CellRangeAddress[] result = new CellRangeAddress[temp.size()]; + temp.toArray(result); + return result; + } + + /** + * Check if the specified range is located inside of this cell range. + * + * @param crB + * @return true if this cell range contains the argument range inside if it's area + */ + public static boolean contains(CellRangeAddress crA, CellRangeAddress crB) + { + int firstRow = crB.getFirstRow(); + int lastRow = crB.getLastRow(); + int firstCol = crB.getFirstColumn(); + int lastCol = crB.getLastColumn(); + return le(crA.getFirstRow(), firstRow) && ge(crA.getLastRow(), lastRow) + && le(crA.getFirstColumn(), firstCol) && ge(crA.getLastColumn(), lastCol); + } + + /** + * Check if the two cell ranges have a shared border. + * + * @return true if the ranges have a complete shared border (i.e. + * the two ranges together make a simple rectangular region. + */ + public static boolean hasExactSharedBorder(CellRangeAddress crA, CellRangeAddress crB) { + int oFirstRow = crB.getFirstRow(); + int oLastRow = crB.getLastRow(); + int oFirstCol = crB.getFirstColumn(); + int oLastCol = crB.getLastColumn(); + + if (crA.getFirstRow() > 0 && crA.getFirstRow()-1 == oLastRow || + oFirstRow > 0 && oFirstRow-1 == crA.getLastRow()) { + // ranges have a horizontal border in common + // make sure columns are identical: + return crA.getFirstColumn() == oFirstCol && crA.getLastColumn() == oLastCol; + } + + if (crA.getFirstColumn()>0 && crA.getFirstColumn() - 1 == oLastCol || + oFirstCol>0 && crA.getLastColumn() == oFirstCol -1) { + // ranges have a vertical border in common + // make sure rows are identical: + return crA.getFirstRow() == oFirstRow && crA.getLastRow() == oLastRow; + } + return false; + } + + /** + * Create an enclosing CellRange for the two cell ranges. + * + * @return enclosing CellRange + */ + public static CellRangeAddress createEnclosingCellRange(CellRangeAddress crA, CellRangeAddress crB) { + if( crB == null) { + return crA.copy(); + } + + return new CellRangeAddress( + lt(crB.getFirstRow(), crA.getFirstRow()) ?crB.getFirstRow() :crA.getFirstRow(), + gt(crB.getLastRow(), crA.getLastRow()) ?crB.getLastRow() :crA.getLastRow(), + lt(crB.getFirstColumn(),crA.getFirstColumn())?crB.getFirstColumn():crA.getFirstColumn(), + gt(crB.getLastColumn(), crA.getLastColumn()) ?crB.getLastColumn() :crA.getLastColumn() + ); + } + + /** + * @return true if a < b + */ + private static boolean lt(int a, int b) + { + return a == -1 ? false : (b == -1 ? true : a < b); + } + + /** + * @return true if a <= b + */ + private static boolean le(int a, int b) + { + return a == b || lt(a,b); + } + + /** + * @return true if a > b + */ + private static boolean gt(int a, int b) + { + return lt(b,a); + } + + /** + * @return true if a >= b + */ + private static boolean ge(int a, int b) + { + return !lt(a,b); + } +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java index 82eddd46d8..a3781d22dd 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java @@ -22,7 +22,6 @@ package org.apache.poi.xssf.usermodel; import java.util.ArrayList; import java.util.List; -import org.apache.poi.hssf.record.cf.CellRangeUtil; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.usermodel.ComparisonOperator; import org.apache.poi.ss.usermodel.ConditionalFormatting; @@ -31,6 +30,7 @@ import org.apache.poi.ss.usermodel.ExtendedColor; import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet; import org.apache.poi.ss.usermodel.SheetConditionalFormatting; import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeUtil; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCfRule; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTConditionalFormatting; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; diff --git a/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java b/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java index f01a2a3912..54f1702e23 100644 --- a/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java +++ b/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java @@ -23,6 +23,7 @@ import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeUtil; /** * Tests CellRange operations.