bug 58637: contribution from Hannes Erven: add CellAddress class, distinct from CellReference

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1715743 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Javen O'Neal 2015-11-23 09:30:53 +00:00
parent c5eef0ba45
commit dbba80c3fc
3 changed files with 279 additions and 2 deletions

View File

@ -0,0 +1,160 @@
/* ====================================================================
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.Locale;
/**
* <p>This class is a container for POI usermodel row=0 column=0 cell references.
* It is barely a container for these two coordinates. The implementation
* of the Comparable interface sorts by "natural" order top left to bottom right.</p>
*
* <p>Use <tt>CellAddress</tt> when you want to refer to the location of a cell in a sheet
* when the concept of relative/absolute does not apply (such as the anchor location
* of a cell comment). Use {@link CellReference} when the concept of
* relative/absolute does apply (such as a cell reference in a formula).
* <tt>CellAddress</tt>es do not have a concept of "sheet", while <tt>CellReference</tt>s do.</p>
*/
public class CellAddress implements Comparable<CellAddress> {
/** A constant for references to the first cell in a sheet. */
public static final CellAddress A1 = new CellAddress(0, 0);
private final int _row;
private final int _col;
/**
* Create a new CellAddress object.
*
* @param row Row index (first row is 0)
* @param column Column index (first column is 0)
*/
public CellAddress(int row, int column) {
super();
this._row = row;
this._col = column;
}
/**
* Create a new CellAddress object.
*
* @param address a cell address in A1 format. Address may not contain sheet name or dollar signs.
* (that is, address is not a cell reference. Use {@link #CellAddress(CellReference)} instead if
* starting with a cell reference.)
*/
public CellAddress(String address) {
int length = address.length();
int loc = 0;
// step over column name chars until first digit for row number.
for (; loc < length; loc++) {
char ch = address.charAt(loc);
if (Character.isDigit(ch)) {
break;
}
}
String sCol = address.substring(0,loc).toUpperCase(Locale.ROOT);
String sRow = address.substring(loc);
// FIXME: breaks if address contains a sheet name or dollar signs from an absolute CellReference
this._row = Integer.parseInt(sRow)-1;
this._col = CellReference.convertColStringToIndex(sCol);
}
/**
* Create a new CellAddress object.
*
* @param reference a reference to a cell
*/
public CellAddress(CellReference reference) {
this(reference.getRow(), reference.getCol());
}
/**
* Get the cell address row
*
* @return row
*/
public int getRow() {
return _row;
}
/**
* Get the cell address column
*
* @return column
*/
public int getColumn() {
return _col;
}
/**
* Compare this CellAddress using the "natural" row-major, column-minor ordering.
* That is, top-left to bottom-right ordering.
*
* @param other
* @return <ul>
* <li>-1 if this CellAddress is before (above/left) of other</li>
* <li>0 if addresses are the same</li>
* <li>1 if this CellAddress is after (below/right) of other</li>
* </ul>
*/
@Override
public int compareTo(CellAddress other) {
int r = this._row-other._row;
if (r!=0) return r;
r = this._col-other._col;
if (r!=0) return r;
return 0;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if(!(o instanceof CellAddress)) {
return false;
}
CellAddress cr = (CellAddress) o;
return _row == cr._row
&& _col == cr._col
;
}
@Override
public int hashCode() {
return this._row + this._col<<16;
}
@Override
public String toString() {
return formatAsString();
}
/**
* Same as {@link #toString()}
* @return A1-style cell address string representation
*/
public String formatAsString() {
return CellReference.convertNumToColString(this._col)+(this._row+1);
}
}

View File

@ -26,10 +26,17 @@ import org.apache.poi.ss.formula.SheetNameFormatter;
import org.apache.poi.ss.usermodel.Cell;
/**
* Common conversion functions between Excel style A1, C27 style
* <p>Common conversion functions between Excel style A1, C27 style
* cell references, and POI usermodel style row=0, column=0
* style references. Handles sheet-based and sheet-free references
* as well, eg "Sheet1!A1" and "$B$72"
* as well, eg "Sheet1!A1" and "$B$72"</p>
*
* <p>Use <tt>CellReference</tt> when the concept of
* relative/absolute does apply (such as a cell reference in a formula).
* Use {@link CellAddress} when you want to refer to the location of a cell in a sheet
* when the concept of relative/absolute does not apply (such as the anchor location
* of a cell comment).
* <tt>CellReference</tt>s have a concept of "sheet", while <tt>CellAddress</tt>es do not.</p>
*/
public class CellReference {
/**

View File

@ -0,0 +1,110 @@
/* ====================================================================
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 org.apache.poi.ss.util.CellAddress;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assume.assumeTrue;
import java.util.Arrays;
/**
* Tests that the common CellAddress works as we need it to.
* Note - some additional testing is also done in the HSSF class,
* {@link org.apache.poi.hssf.util.TestCellAddress}
*/
public final class TestCellAddress {
@Test
public void testConstructors() {
CellAddress cellAddress;
final CellReference cellRef = new CellReference("Sheet1", 0, 0, true, true);
final String address = "A1";
final int row = 0;
final int col = 0;
cellAddress = new CellAddress(row, col);
assertEquals(CellAddress.A1, cellAddress);
cellAddress = new CellAddress(address);
assertEquals(CellAddress.A1, cellAddress);
cellAddress = new CellAddress(cellRef);
assertEquals(CellAddress.A1, cellAddress);
}
@Test
public void testFormatAsString() {
assertEquals("A1", CellAddress.A1.formatAsString());
}
@Test
public void testEquals() {
assertEquals(new CellReference(6, 4), new CellReference(6, 4));
assertNotEquals(new CellReference(4, 6), new CellReference(6, 4));
}
@Test
public void testCompareTo() {
final CellAddress A1 = new CellAddress(0, 0);
final CellAddress A2 = new CellAddress(1, 0);
final CellAddress B1 = new CellAddress(0, 1);
final CellAddress B2 = new CellAddress(1, 1);
assertEquals(0, A1.compareTo(A1));
assertEquals(-1, A1.compareTo(B1));
assertEquals(-1, A1.compareTo(A2));
assertEquals(-1, A1.compareTo(B2));
assertEquals(1, B1.compareTo(A1));
assertEquals(0, B1.compareTo(B1));
assertEquals(-1, B1.compareTo(A2));
assertEquals(-1, B1.compareTo(B2));
assertEquals(1, A2.compareTo(A1));
assertEquals(1, A2.compareTo(B1));
assertEquals(0, A2.compareTo(A2));
assertEquals(-1, A2.compareTo(B2));
assertEquals(1, B2.compareTo(A1));
assertEquals(1, B2.compareTo(B1));
assertEquals(1, B2.compareTo(A2));
assertEquals(0, B2.compareTo(B2));
CellAddress[] sorted = {A1, B1, A2, B2};
CellAddress[] unsorted = {B1, B2, A1, A2};
assumeTrue(!sorted.equals(unsorted));
Arrays.sort(unsorted);
assertArrayEquals(sorted, unsorted);
}
@Test
public void testGetRow() {
final CellAddress addr = new CellAddress(6, 4);
assertEquals(6, addr.getRow());
}
@Test
public void testGetColumn() {
final CellAddress addr = new CellAddress(6, 4);
assertEquals(4, addr.getColumn());
}
}