CellReference firstCell = ar.getFirstCell();
CellReference lastCell = ar.getLastCell();
setFirstRow(firstCell.getRow());
- setFirstColumn(firstCell.getCol());
+ setFirstColumn(firstCell.getCol() == -1 ? 0 : firstCell.getCol());
setLastRow(lastCell.getRow());
- setLastColumn(lastCell.getCol());
+ setLastColumn(lastCell.getCol() == -1 ? 0xFF : lastCell.getCol());
setFirstColRelative(!firstCell.isColAbsolute());
setLastColRelative(!lastCell.isColAbsolute());
setFirstRowRelative(!firstCell.isRowAbsolute());
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
+import java.util.regex.Pattern;
import org.apache.poi.POIDocument;
import org.apache.poi.ddf.EscherBSERecord;
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Glen Stampoultzis (glens at apache.org)
* @author Shawn Laubach (slaubach at apache dot org)
- * @version 2.0-pre
+ *
*/
-public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook
-{
+public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook {
+ private static final Pattern COMMA_PATTERN = Pattern.compile(",");
private static final int MAX_ROW = 0xFFFF;
private static final short MAX_COLUMN = (short)0x00FF;
}
public int getSheetIndexFromExternSheetIndex(int externSheetNumber) {
- return workbook.getSheetIndexFromExternSheetIndex(externSheetNumber);
- }
+ return workbook.getSheetIndexFromExternSheetIndex(externSheetNumber);
+ }
private HSSFSheet[] getSheets() {
HSSFSheet[] result = new HSSFSheet[_sheets.size()];
return result;
}
- /**
+ /**
* Get the HSSFSheet object at the given index.
* @param index of the sheet number (0-based physical & logical)
* @return HSSFSheet at the provided index
return result;
}
- public NameRecord getNameRecord(int nameIndex) {
- return getWorkbook().getNameRecord(nameIndex);
- }
+ public NameRecord getNameRecord(int nameIndex) {
+ return getWorkbook().getNameRecord(nameIndex);
+ }
/** gets the named range name
* @param index the named range index (0 based)
if (name == null) {
- name = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
- // adding one here because 0 indicates a global named region; doesn't make sense for print areas
- }
+ name = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
+ // adding one here because 0 indicates a global named region; doesn't make sense for print areas
+ }
+ String[] parts = COMMA_PATTERN.split(reference);
StringBuffer sb = new StringBuffer(32);
- SheetNameFormatter.appendFormat(sb, getSheetName(sheetIndex));
- sb.append("!");
- sb.append(reference);
+ for (int i = 0; i < parts.length; i++) {
+ if(i>0) {
+ sb.append(",");
+ }
+ SheetNameFormatter.appendFormat(sb, getSheetName(sheetIndex));
+ sb.append("!");
+ sb.append(parts[i]);
+ }
name.setNameDefinition(HSSFFormulaParser.parse(sb.toString(), this));
}
NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
//adding one here because 0 indicates a global named region; doesn't make sense for print areas
if (name == null) {
- return null;
- }
+ return null;
+ }
return HSSFFormulaParser.toFormulaString(this, name.getNameDefinition());
}
}
public CreationHelper getCreationHelper() {
- return new HSSFCreationHelper(this);
+ return new HSSFCreationHelper(this);
}
private static byte[] newUID() {
import org.apache.poi.hssf.record.formula.IntPtg;
import org.apache.poi.hssf.record.formula.LessEqualPtg;
import org.apache.poi.hssf.record.formula.LessThanPtg;
+import org.apache.poi.hssf.record.formula.MemFuncPtg;
import org.apache.poi.hssf.record.formula.MissingArgPtg;
import org.apache.poi.hssf.record.formula.MultiplyPtg;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.SubtractPtg;
import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
+import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
// TODO - handle <book name> ! <named range name>
int externIdx = getExternalSheetIndex(iden.getName());
String secondIden = parseUnquotedIdentifier();
+ if (isRowOrCol(secondIden) && look == ':') {
+ GetChar();
+ String thirdIden = parseUnquotedIdentifier();
+ return new Area3DPtg(secondIden + ":" + thirdIden, externIdx);
+ }
AreaReference areaRef = parseArea(secondIden);
if (areaRef == null) {
return new Ref3DPtg(secondIden, externIdx);
+ name + "' is not a range as expected");
}
+ private static boolean isRowOrCol(String str) {
+ int i=0;
+ if (str.charAt(i) == '$') {
+ i++;
+ }
+ if (IsDigit(str.charAt(i))) {
+ while (i<str.length()) {
+ if (!IsDigit(str.charAt(i))) {
+ return false;
+ }
+ i++;
+ }
+ return true;
+ }
+ if (IsAlpha(str.charAt(i))) {
+ while (i<str.length()) {
+ if (!IsAlpha(str.charAt(i))) {
+ return false;
+ }
+ i++;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
private int getExternalSheetIndex(String name) {
if (name.charAt(0) == '[') {
// we have a sheet name qualified with workbook name e.g. '[MyData.xls]Sheet1'
/** get arguments to a function */
private ParseNode[] Arguments() {
//average 2 args per function
- List temp = new ArrayList(2);
+ List<ParseNode> temp = new ArrayList<ParseNode>(2);
SkipWhite();
if(look == ')') {
return ParseNode.EMPTY_ARRAY;
private ParseNode parseArray() {
- List rowsData = new ArrayList();
+ List<Object[]> rowsData = new ArrayList<Object[]>();
while(true) {
Object[] singleRowData = parseArrayRow();
rowsData.add(singleRowData);
}
private Object[] parseArrayRow() {
- List temp = new ArrayList();
+ List<Object> temp = new ArrayList<Object>();
while (true) {
temp.add(parseArrayItem());
SkipWhite();
result = new ParseNode(operator, result, other);
}
}
+ private ParseNode unionExpression() {
+ ParseNode result = comparisonExpression();
+ boolean hasUnions = false;
+ while (true) {
+ SkipWhite();
+ switch(look) {
+ case ',':
+ GetChar();
+ hasUnions = true;
+ ParseNode other = comparisonExpression();
+ result = new ParseNode(UnionPtg.instance, result, other);
+ continue;
+ }
+ if (hasUnions) {
+ MemFuncPtg memFuncPtg = new MemFuncPtg(result.getEncodedSize());
+ result = new ParseNode(memFuncPtg, result);
+ }
+ return result;
+ }
+ }
private ParseNode comparisonExpression() {
ParseNode result = concatExpression();
private void parse() {
pointer=0;
GetChar();
- _rootNode = comparisonExpression();
+ _rootNode = unionExpression();
if(pointer <= formulaLength) {
String msg = "Unused input [" + formulaString.substring(pointer-1)
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.ControlPtg;
+import org.apache.poi.hssf.record.formula.MemFuncPtg;
+import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.RangePtg;
+import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.record.formula.ValueOperatorPtg;
-import org.apache.poi.hssf.record.formula.Ptg;
/**
* This class performs 'operand class' transformation. Non-base tokens are classified into three
return;
}
- if (token instanceof ValueOperatorPtg || token instanceof ControlPtg) {
+ if (token instanceof ValueOperatorPtg || token instanceof ControlPtg
+ || token instanceof MemFuncPtg
+ || token instanceof UnionPtg) {
// Value Operator Ptgs and Control are base tokens, so token will be unchanged
// but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag
package org.apache.poi.ss.formula;
+import org.apache.poi.hssf.record.formula.ArrayPtg;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
+import org.apache.poi.hssf.record.formula.MemFuncPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
/**
private int getTokenCount() {
return _tokenCount;
}
+ public int getEncodedSize() {
+ int result = _token instanceof ArrayPtg ? ArrayPtg.PLAIN_TOKEN_SIZE : _token.getSize();
+ for (int i = 0; i < _children.length; i++) {
+ result += _children[i].getEncodedSize();
+ }
+ return result;
+ }
/**
* Collects the array of <tt>Ptg</tt> tokens for the specified tree.
return temp.getResult();
}
private void collectPtgs(TokenCollector temp) {
- if (isIf(getToken())) {
+ if (isIf(_token)) {
collectIfPtgs(temp);
return;
}
+ boolean isPreFixOperator = _token instanceof MemFuncPtg;
+ if (isPreFixOperator) {
+ temp.add(_token);
+ }
for (int i=0; i< getChildren().length; i++) {
getChildren()[i].collectPtgs(temp);
}
- temp.add(getToken());
+ if (!isPreFixOperator) {
+ temp.add(_token);
+ }
}
/**
* The IF() function gets marked up with two or three tAttr tokens.
temp.setPlaceholder(skipAfterTrueParamIndex, attrSkipAfterTrue);
}
- temp.add(getToken());
+ temp.add(_token);
}
private static boolean isIf(Ptg token) {
ptgs = FormulaParser.parse(formulaText, fpb, FormulaType.CELL); // TODO - use type NAMEDRANGE
} catch (RuntimeException e) {
if (e.getClass().getName().startsWith(FormulaParser.class.getName())) {
- throw new IllegalArgumentException("Unparsable formula '" + formulaText + "'");
+ throw new IllegalArgumentException("Unparsable formula '" + formulaText + "'", e);
}
throw e;
}
package org.apache.poi.xssf.usermodel;
-import java.io.*;
-import java.util.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
import javax.xml.namespace.QName;
+
import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLDocumentPart;
+import org.apache.poi.POIXMLException;
+import org.apache.poi.hssf.record.formula.SheetNameFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.PackageHelper;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.model.*;
-import org.apache.poi.POIXMLException;
+import org.apache.poi.xssf.model.SharedStringsTable;
+import org.apache.poi.xssf.model.StylesTable;
+import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
-import org.apache.xmlbeans.XmlException;
import org.openxml4j.exceptions.OpenXML4JException;
-import org.openxml4j.opc.*;
import org.openxml4j.opc.Package;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
+import org.openxml4j.opc.PackagePart;
+import org.openxml4j.opc.PackagePartName;
+import org.openxml4j.opc.PackageRelationship;
+import org.openxml4j.opc.PackageRelationshipTypes;
+import org.openxml4j.opc.PackagingURIHelper;
+import org.openxml4j.opc.TargetMode;
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBookView;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBookViews;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedNames;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDialogsheet;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.STSheetState;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument;
/**
* High level representation of a SpreadsheetML workbook. This is the first object most users
* top level object for creating new sheets/etc.
*/
public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<XSSFSheet> {
+ private static final Pattern COMMA_PATTERN = Pattern.compile(",");
/**
* Width of one character of the default font in pixels. Same for Calibry and Arial.
}
//short externSheetIndex = getWorkbook().checkExternSheet(sheetIndex);
//name.setExternSheetNumber(externSheetIndex);
- name.setReference(reference);
+ String[] parts = COMMA_PATTERN.split(reference);
+ StringBuffer sb = new StringBuffer(32);
+ for (int i = 0; i < parts.length; i++) {
+ if(i>0) {
+ sb.append(",");
+ }
+ SheetNameFormatter.appendFormat(sb, getSheetName(sheetIndex));
+ sb.append("!");
+ sb.append(parts[i]);
+ }
+ name.setFormula(sb.toString());
}
/**
CellReference colRef = new CellReference(sheetName, startR, startC, true, true);
CellReference colRef2 = new CellReference(sheetName, endR, endC, true, true);
- return "'" + sheetName + "'!$" + colRef.getCellRefParts()[2] + "$" + colRef.getCellRefParts()[1] + ":$" + colRef2.getCellRefParts()[2] + "$" + colRef2.getCellRefParts()[1];
+ return "$" + colRef.getCellRefParts()[2] + "$" + colRef.getCellRefParts()[1] + ":$" + colRef2.getCellRefParts()[2] + "$" + colRef2.getCellRefParts()[1];
}
private XSSFName getBuiltInName(String builtInCode, int sheetNumber) {
import org.apache.poi.hssf.record.constant.ErrorConstant;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.AddPtg;
+import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.AreaI;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.ArrayPtg;
import org.apache.poi.hssf.record.formula.FuncPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.IntPtg;
+import org.apache.poi.hssf.record.formula.MemFuncPtg;
import org.apache.poi.hssf.record.formula.MissingArgPtg;
import org.apache.poi.hssf.record.formula.MultiplyPtg;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.SubtractPtg;
import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
+import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.usermodel.FormulaExtractor;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaParserTestHelper;
/**
/* package */ static Ptg[] confirmTokenClasses(String formula, Class[] expectedClasses) {
Ptg[] ptgs = parseFormula(formula);
+ confirmTokenClasses(ptgs, expectedClasses);
+ return ptgs;
+ }
+ private static void confirmTokenClasses(Ptg[] ptgs, Class[] expectedClasses) {
assertEquals(expectedClasses.length, ptgs.length);
for (int i = 0; i < expectedClasses.length; i++) {
if(expectedClasses[i] != ptgs[i].getClass()) {
+ ptgs[i].getClass().getName() + ")");
}
}
- return ptgs;
}
public void testPower() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("Sheet1");
HSSFName name = wb.createName();
- name.setReference("Sheet1!B1");
+ name.setFormula("Sheet1!B1");
name.setNameName("pfy1");
Ptg[] ptgs;
assertEquals(expectedExternSheetIndex, ((Ref3DPtg)ptg0).getExternSheetIndex());
}
+ public void testUnion() {
+ String formula = "Sheet1!$B$2:$C$3,OFFSET(Sheet1!$E$2:$E$4,1,Sheet1!$A$1),Sheet1!$D$6";
+ HSSFWorkbook wb = new HSSFWorkbook();
+ wb.createSheet("Sheet1");
+ Ptg[] ptgs = FormulaParser.parse(formula, HSSFEvaluationWorkbook.create(wb));
+
+ Class[] expectedClasses = {
+ // TODO - AttrPtg.class, // Excel prepends this
+ MemFuncPtg.class,
+ Area3DPtg.class,
+ Area3DPtg.class,
+ IntPtg.class,
+ Ref3DPtg.class,
+ FuncVarPtg.class,
+ UnionPtg.class,
+ Ref3DPtg.class,
+ UnionPtg.class,
+ };
+ confirmTokenClasses(ptgs, expectedClasses);
+ MemFuncPtg mf = (MemFuncPtg)ptgs[0];
+ assertEquals(45, mf.getLenRefSubexpression());
+ }
}
assertEquals("isFullRowRange", isFullRow, cr.isFullRowRange());
assertEquals("isFullColumnRange", isFullColumn, cr.isFullColumnRange());
}
+
+ public void testNumberOfCells() {
+ assertEquals(1, oneCell.getNumberOfCells());
+ assertEquals(100, box9x9.getNumberOfCells());
+ assertEquals(121, box10to20c.getNumberOfCells());
+ }
}
public void testPrintAreaUnion(){
HSSFWorkbook workbook = new HSSFWorkbook();
workbook.createSheet("Test Print Area");
- String sheetName = workbook.getSheetName(0);
-
-
- if (false) { // TODO - fix formula parser to support unions
- String reference = "'" + sheetName + "'!$A$1:$B$1,'" + sheetName + "'!$D$1:$F$2";
- workbook.setPrintArea(0, reference);
- String retrievedPrintArea = workbook.getPrintArea(0);
- assertNotNull("Print Area not defined for first sheet", retrievedPrintArea);
- assertEquals(reference, retrievedPrintArea);
- }
+
+ String reference = "$A$1:$B$1,$D$1:$F$2";
+ workbook.setPrintArea(0, reference);
+ String retrievedPrintArea = workbook.getPrintArea(0);
+ assertNotNull("Print Area not defined for first sheet", retrievedPrintArea);
+ assertEquals("'Test Print Area'!$A$1:$B$1,'Test Print Area'!$D$1:$F$2", retrievedPrintArea);
}
/**