1. Support sheet-level names2. Fixed XSSFCell to properly handle cell references with column numbers up to XFD3. when pasring formula, HSSFName.setRefersToFormula must set type of operands to Ptg.CLASS_REF, otherwise created named don't appear in the dropdown to the left of formula bar in Excel
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@723392 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1341f419ae
commit
2ae887e98c
@ -37,6 +37,8 @@
|
||||
|
||||
<!-- Don't forget to update status.xml too! -->
|
||||
<release version="3.5-beta5" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">Support sheet-level names</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Fixed XSSFCell to properly handle cell references with column numbers up to XFD</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44914 - Fixed warning message "WARN. Unread n bytes of record 0xNN"</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">46156 - Improved number to text conversion to be closer to that of Excel</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">46312 - Fixed ValueRecordsAggregate to handle removal of new empty row</action>
|
||||
|
@ -34,6 +34,8 @@
|
||||
<!-- Don't forget to update changes.xml too! -->
|
||||
<changes>
|
||||
<release version="3.5-beta5" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">Support sheet-level names</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Fixed XSSFCell to properly handle cell references with column numbers up to XFD</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44914 - Fixed warning message "WARN. Unread n bytes of record 0xNN"</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">46156 - Improved number to text conversion to be closer to that of Excel</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">46312 - Fixed ValueRecordsAggregate to handle removal of new empty row</action>
|
||||
|
@ -557,6 +557,17 @@ public class HSSFCell implements Cell {
|
||||
stringValue.setUnicodeString(book.getWorkbook().getSSTString(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets formula for this cell.
|
||||
* <p>
|
||||
* Note, this method only sets the formula string and does not calculate the formula value.
|
||||
* To set the precalculated value use {@link #setCellValue(double)} or {@link #setCellValue(String)}
|
||||
* </p>
|
||||
*
|
||||
* @param formula the formula to set, e.g. <code>SUM(C4:E4)</code>.
|
||||
* If the argument is <code>null</code> then the current formula is removed.
|
||||
* @throws IllegalArgumentException if the formula is unparsable
|
||||
*/
|
||||
public void setCellFormula(String formula) {
|
||||
int row=record.getRow();
|
||||
short col=record.getColumn();
|
||||
|
@ -22,6 +22,7 @@ import org.apache.poi.hssf.model.Workbook;
|
||||
import org.apache.poi.hssf.record.NameRecord;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.ss.usermodel.Name;
|
||||
import org.apache.poi.ss.formula.FormulaType;
|
||||
|
||||
/**
|
||||
* High Level Representation of a 'defined name' which could be a 'built-in' name,
|
||||
@ -133,7 +134,7 @@ public final class HSSFName implements Name {
|
||||
* @throws IllegalArgumentException if the specified reference is unparsable
|
||||
*/
|
||||
public void setRefersToFormula(String formulaText) {
|
||||
Ptg[] ptgs = HSSFFormulaParser.parse(formulaText, _book);
|
||||
Ptg[] ptgs = HSSFFormulaParser.parse(formulaText, _book, FormulaType.NAMEDRANGE);
|
||||
_definedNameRec.setNameDefinition(ptgs);
|
||||
}
|
||||
|
||||
@ -176,4 +177,49 @@ public final class HSSFName implements Name {
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if the defined name is a local name, and if so, which sheet it is on.
|
||||
*
|
||||
* @param index if greater than 0, the defined name is a local name and the value MUST be a 0-based index
|
||||
* to the collection of sheets as they appear in the workbook.
|
||||
* @throws IllegalArgumentException if the sheet index is invalid.
|
||||
*/
|
||||
public void setSheetIndex(int index){
|
||||
int lastSheetIx = _book.getNumberOfSheets() - 1;
|
||||
if (index < -1 || index > lastSheetIx) {
|
||||
throw new IllegalArgumentException("Sheet index (" + index +") is out of range" +
|
||||
(lastSheetIx == -1 ? "" : (" (0.." + lastSheetIx + ")")));
|
||||
}
|
||||
|
||||
_definedNameRec.setSheetNumber(index + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sheet index this name applies to.
|
||||
*
|
||||
* @return the sheet index this name applies to, -1 if this name applies to the entire workbook
|
||||
*/
|
||||
public int getSheetIndex(){
|
||||
return _definedNameRec.getSheetNumber() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the comment the user provided when the name was created.
|
||||
*
|
||||
* @return the user comment for this named range
|
||||
*/
|
||||
public String getComment(){
|
||||
return _definedNameRec.getDescriptionText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the comment the user provided when the name was created.
|
||||
*
|
||||
* @param comment the user comment for this named range
|
||||
*/
|
||||
public void setComment(String comment){
|
||||
_definedNameRec.setDescriptionText(comment);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ final class OperandClassTransformer {
|
||||
case FormulaType.CELL:
|
||||
rootNodeOperandClass = Ptg.CLASS_VALUE;
|
||||
break;
|
||||
case FormulaType.NAMEDRANGE:
|
||||
case FormulaType.DATAVALIDATION_LIST:
|
||||
rootNodeOperandClass = Ptg.CLASS_REF;
|
||||
break;
|
||||
|
@ -189,6 +189,7 @@ public interface Cell {
|
||||
*
|
||||
* @param formula the formula to set, e.g. <code>SUM(C4:E4)</code>.
|
||||
* If the argument is <code>null</code> then the current formula is removed.
|
||||
* @throws IllegalArgumentException if the formula is unparsable
|
||||
*/
|
||||
void setCellFormula(String formula);
|
||||
|
||||
|
@ -93,7 +93,7 @@ public interface Name {
|
||||
void setNameName(String name);
|
||||
|
||||
/**
|
||||
* Returns the formula that the name is defined to refer to. The following are representative examples:
|
||||
* Returns the formula that the name is defined to refer to.
|
||||
*
|
||||
* @return the reference for this name
|
||||
* @see #setRefersToFormula(String)
|
||||
@ -129,4 +129,33 @@ public interface Name {
|
||||
* @return true if the name refers to a deleted cell, false otherwise
|
||||
*/
|
||||
boolean isDeleted();
|
||||
|
||||
/**
|
||||
* Tell Excel that this name applies to the worksheet with the specified index instead of the entire workbook.
|
||||
*
|
||||
* @param sheetId the sheet index this name applies to, -1 unsets this property making the name workbook-global
|
||||
* @throws IllegalArgumentException if the sheet index is invalid.
|
||||
*/
|
||||
public void setSheetIndex(int sheetId);
|
||||
|
||||
/**
|
||||
* Returns the sheet index this name applies to.
|
||||
*
|
||||
* @return the sheet index this name applies to, -1 if this name applies to the entire workbook
|
||||
*/
|
||||
public int getSheetIndex();
|
||||
|
||||
/**
|
||||
* Returns the comment the user provided when the name was created.
|
||||
*
|
||||
* @return the user comment for this named range
|
||||
*/
|
||||
public String getComment();
|
||||
|
||||
/**
|
||||
* Sets the comment the user provided when the name was created.
|
||||
*
|
||||
* @param comment the user comment for this named range
|
||||
*/
|
||||
public void setComment(String comment);
|
||||
}
|
||||
|
@ -23,8 +23,11 @@ import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
import org.apache.poi.ss.formula.FormulaParser;
|
||||
import org.apache.poi.ss.formula.FormulaType;
|
||||
import org.apache.poi.xssf.model.StylesTable;
|
||||
import org.apache.poi.xssf.model.SharedStringsTable;
|
||||
import org.apache.poi.POIXMLException;
|
||||
@ -51,7 +54,7 @@ public final class XSSFCell implements Cell {
|
||||
/**
|
||||
* The maximum number of columns in SpreadsheetML
|
||||
*/
|
||||
private static final int MAX_COLUMN_NUMBER = 16384;
|
||||
public static final int MAX_COLUMN_NUMBER = 16384; //2^14
|
||||
|
||||
private static final String FALSE_AS_STRING = "0";
|
||||
private static final String TRUE_AS_STRING = "1";
|
||||
@ -330,6 +333,7 @@ public final class XSSFCell implements Cell {
|
||||
*
|
||||
* @param formula the formula to set, e.g. <code>SUM(C4:E4)</code>.
|
||||
* If the argument is <code>null</code> then the current formula is removed.
|
||||
* @throws IllegalArgumentException if the formula is invalid
|
||||
*/
|
||||
public void setCellFormula(String formula) {
|
||||
if (formula == null && cell.isSetF()) {
|
||||
@ -337,6 +341,16 @@ public final class XSSFCell implements Cell {
|
||||
return;
|
||||
}
|
||||
|
||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(row.getSheet().getWorkbook());
|
||||
try {
|
||||
Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL);
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getClass().getName().startsWith(FormulaParser.class.getName())) {
|
||||
throw new IllegalArgumentException("Unparsable formula '" + formula + "'", e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
CTCellFormula f = CTCellFormula.Factory.newInstance();
|
||||
f.setStringValue(formula);
|
||||
cell.setF(f);
|
||||
@ -580,7 +594,8 @@ public final class XSSFCell implements Cell {
|
||||
protected void setCellNum(int num) {
|
||||
checkBounds(num);
|
||||
cellNum = num;
|
||||
cell.setR(formatPosition());
|
||||
String ref = new CellReference(getRowIndex(), getColumnIndex()).formatAsString();
|
||||
cell.setR(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -598,22 +613,6 @@ public final class XSSFCell implements Cell {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an A1 style reference from internal represenetation
|
||||
*
|
||||
* @return an A1 style reference to the location of this cell
|
||||
*/
|
||||
protected String formatPosition() {
|
||||
int col = this.getColumnIndex();
|
||||
String result = Character.valueOf((char) (col % 26 + 'A')).toString();
|
||||
if (col >= 26){
|
||||
col = col / 26;
|
||||
result = Character.valueOf((char) (col + '@')) + result;
|
||||
}
|
||||
result = result + String.valueOf(row.getRowNum() + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cells type (numeric, formula or string)
|
||||
*
|
||||
@ -733,10 +732,10 @@ public final class XSSFCell implements Cell {
|
||||
*/
|
||||
private static void checkBounds(int cellNum) {
|
||||
if (cellNum > MAX_COLUMN_NUMBER) {
|
||||
throw new POIXMLException("You cannot have more than "+MAX_COLUMN_NUMBER+" columns " +
|
||||
throw new IllegalArgumentException("You cannot have more than "+MAX_COLUMN_NUMBER+" columns " +
|
||||
"in a given row because Excel can't handle it");
|
||||
} else if (cellNum < 0) {
|
||||
throw new POIXMLException("You cannot reference columns with an index of less then 0.");
|
||||
throw new IllegalArgumentException("You cannot reference columns with an index of less then 0.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,9 +170,8 @@ public final class XSSFName implements Name {
|
||||
*/
|
||||
public void setRefersToFormula(String formulaText) {
|
||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(workbook);
|
||||
Ptg[] ptgs;
|
||||
try {
|
||||
ptgs = FormulaParser.parse(formulaText, fpb, FormulaType.CELL); // TODO - use type NAMEDRANGE
|
||||
Ptg[] ptgs = FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE);
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getClass().getName().startsWith(FormulaParser.class.getName())) {
|
||||
throw new IllegalArgumentException("Unparsable formula '" + formulaText + "'", e);
|
||||
@ -195,11 +194,20 @@ public final class XSSFName implements Name {
|
||||
/**
|
||||
* Tell Excel that this name applies to the worksheet with the specified index instead of the entire workbook.
|
||||
*
|
||||
* @param sheetId the sheet index this name applies to, -1 unsets this property making the name workbook-global
|
||||
* @param index the sheet index this name applies to, -1 unsets this property making the name workbook-global
|
||||
*/
|
||||
public void setLocalSheetId(int sheetId) {
|
||||
if(sheetId == -1) ctName.unsetLocalSheetId();
|
||||
else ctName.setLocalSheetId(sheetId);
|
||||
public void setSheetIndex(int index) {
|
||||
int lastSheetIx = workbook.getNumberOfSheets() - 1;
|
||||
if (index < -1 || index > lastSheetIx) {
|
||||
throw new IllegalArgumentException("Sheet index (" + index +") is out of range" +
|
||||
(lastSheetIx == -1 ? "" : (" (0.." + lastSheetIx + ")")));
|
||||
}
|
||||
|
||||
if(index == -1) {
|
||||
if(ctName.isSetLocalSheetId()) ctName.unsetLocalSheetId();
|
||||
} else {
|
||||
ctName.setLocalSheetId(index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,7 +215,7 @@ public final class XSSFName implements Name {
|
||||
*
|
||||
* @return the sheet index this name applies to, -1 if this name applies to the entire workbook
|
||||
*/
|
||||
public int getLocalSheetId() {
|
||||
public int getSheetIndex() {
|
||||
return ctName.isSetLocalSheetId() ? (int) ctName.getLocalSheetId() : -1;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import java.util.*;
|
||||
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.POIXMLException;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
|
||||
|
||||
@ -29,6 +30,11 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
|
||||
*/
|
||||
public class XSSFRow implements Row, Comparable<XSSFRow> {
|
||||
|
||||
/**
|
||||
* The maximum number of rows in SpreadsheetML
|
||||
*/
|
||||
public static final int MAX_ROW_NUMBER = 1048576; //2 ^ 20
|
||||
|
||||
/**
|
||||
* the xml bean containing all cell definitions for this row
|
||||
*/
|
||||
@ -309,10 +315,12 @@ public class XSSFRow implements Row, Comparable<XSSFRow> {
|
||||
* Set the row number of this row.
|
||||
*
|
||||
* @param rowNum the row number (0-based)
|
||||
* @throws IllegalArgumentException if rowNum < 0
|
||||
* @throws IllegalArgumentException if rowNum < 0 or greater than {@link #MAX_ROW_NUMBER}
|
||||
*/
|
||||
public void setRowNum(int rowNum) {
|
||||
if(rowNum < 0) throw new IllegalArgumentException("Row number must be >= 0");
|
||||
if (rowNum > MAX_ROW_NUMBER)
|
||||
throw new IllegalArgumentException("You cannot have more than "+MAX_ROW_NUMBER+" rows ");
|
||||
|
||||
this.row.setR(rowNum + 1);
|
||||
}
|
||||
|
@ -745,7 +745,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
|
||||
public void removePrintArea(int sheetIndex) {
|
||||
int cont = 0;
|
||||
for (XSSFName name : namedRanges) {
|
||||
if (name.getNameName().equals(XSSFName.BUILTIN_PRINT_AREA) && name.getLocalSheetId() == sheetIndex) {
|
||||
if (name.getNameName().equals(XSSFName.BUILTIN_PRINT_AREA) && name.getSheetIndex() == sheetIndex) {
|
||||
namedRanges.remove(cont);
|
||||
break;
|
||||
}
|
||||
@ -967,7 +967,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
|
||||
|
||||
private XSSFName getBuiltInName(String builtInCode, int sheetNumber) {
|
||||
for (XSSFName name : namedRanges) {
|
||||
if (name.getNameName().equalsIgnoreCase(builtInCode) && name.getLocalSheetId() == sheetNumber) {
|
||||
if (name.getNameName().equalsIgnoreCase(builtInCode) && name.getSheetIndex() == sheetNumber) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
@ -305,20 +305,39 @@ public final class TestXSSFCell extends TestCase {
|
||||
assertEquals(255, XSSFCell.parseCellNum("IV32768"));
|
||||
}
|
||||
|
||||
public void testFormatPosition() {
|
||||
XSSFRow row = createParentObjects();
|
||||
row.setRowNum(0);
|
||||
public void testSetCellReference() {
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
XSSFSheet sheet = wb.createSheet();
|
||||
XSSFRow row = sheet.createRow(0);
|
||||
XSSFCell cell = row.createCell(0);
|
||||
cell.setCellNum((short) 0);
|
||||
assertEquals("A1", cell.formatPosition());
|
||||
cell.setCellNum((short) 25);
|
||||
assertEquals("Z1", cell.formatPosition());
|
||||
cell.setCellNum((short) 26);
|
||||
assertEquals("AA1", cell.formatPosition());
|
||||
cell.setCellNum((short) 255);
|
||||
assertEquals("IV1", cell.formatPosition());
|
||||
row.setRowNum(32767);
|
||||
assertEquals("IV32768", cell.formatPosition());
|
||||
assertEquals("A1", cell.getCTCell().getR());
|
||||
|
||||
row = sheet.createRow(100);
|
||||
cell = row.createCell(100);
|
||||
assertEquals("CW101", cell.getCTCell().getR());
|
||||
|
||||
row = sheet.createRow(XSSFRow.MAX_ROW_NUMBER);
|
||||
cell = row.createCell(100);
|
||||
assertEquals("CW1048577", cell.getCTCell().getR());
|
||||
|
||||
row = sheet.createRow(XSSFRow.MAX_ROW_NUMBER);
|
||||
cell = row.createCell(XSSFCell.MAX_COLUMN_NUMBER);
|
||||
assertEquals("XFE1048577", cell.getCTCell().getR());
|
||||
|
||||
try {
|
||||
sheet.createRow(XSSFRow.MAX_ROW_NUMBER + 1);
|
||||
fail("expecting exception when rownum > XSSFRow.MAX_ROW_NUMBER");
|
||||
} catch(IllegalArgumentException e){
|
||||
;
|
||||
}
|
||||
|
||||
try {
|
||||
row = sheet.createRow(100);
|
||||
row.createCell(XSSFCell.MAX_COLUMN_NUMBER + 1);
|
||||
fail("expecting exception when columnIndex > XSSFCell.MAX_COLUMN_NUMBER");
|
||||
} catch(IllegalArgumentException e){
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetCellComment() {
|
||||
|
@ -52,9 +52,25 @@ public class TestXSSFName extends TestCase {
|
||||
assertEquals("'Testing Named Ranges'!$A$1:$B$1", name1.getRefersToFormula());
|
||||
assertEquals("Testing Named Ranges", name1.getSheetName());
|
||||
|
||||
assertEquals(-1, name1.getLocalSheetId());
|
||||
name1.setLocalSheetId(1);
|
||||
assertEquals(1, name1.getLocalSheetId());
|
||||
assertEquals(-1, name1.getSheetIndex());
|
||||
name1.setSheetIndex(-1);
|
||||
assertEquals(-1, name1.getSheetIndex());
|
||||
try {
|
||||
name1.setSheetIndex(1);
|
||||
fail("should throw IllegalArgumentException");
|
||||
} catch(IllegalArgumentException e){
|
||||
assertEquals("Sheet index (1) is out of range", e.getMessage());
|
||||
}
|
||||
wb.createSheet();
|
||||
try {
|
||||
name1.setSheetIndex(1);
|
||||
fail("should throw IllegalArgumentException");
|
||||
} catch(IllegalArgumentException e){
|
||||
assertEquals("Sheet index (1) is out of range (0..0)", e.getMessage());
|
||||
}
|
||||
wb.createSheet();
|
||||
name1.setSheetIndex(1);
|
||||
assertEquals(1, name1.getSheetIndex());
|
||||
}
|
||||
|
||||
public void testUnicodeNamedRange() {
|
||||
|
@ -24,8 +24,11 @@ import java.io.IOException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.model.HSSFFormulaParser;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.ss.util.AreaReference;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
import org.apache.poi.ss.formula.FormulaType;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -530,4 +533,20 @@ public final class TestNamedRange extends TestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When setting A1 type of referencese HSSFName.setRefersToFormula
|
||||
* must set the type of operands to Ptg.CLASS_REF,
|
||||
* otherwise created named don't appear in the dropdown to the left opf formula bar in Excel
|
||||
*/
|
||||
public void testTypeOfRootPtg(){
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
wb.createSheet("CSCO");
|
||||
|
||||
Ptg[] ptgs = HSSFFormulaParser.parse("CSCO!$E$71", wb, FormulaType.NAMEDRANGE);
|
||||
for (int i = 0; i < ptgs.length; i++) {
|
||||
assertEquals('R', ptgs[i].getRVAType());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user