git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@713909 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_5_BETA4
@@ -37,6 +37,7 @@ | |||
<!-- Don't forget to update status.xml too! --> | |||
<release version="3.5-beta4" date="2008-??-??"> | |||
<action dev="POI-DEVELOPERS" type="fix">46174 - Fixed HSSFName to handle general formulas (not just area references)</header> | |||
<action dev="POI-DEVELOPERS" type="add">46189 - added chart records: CHARTFRTINFO, STARTBLOCK, ENDBLOCK, STARTOBJECT, ENDOBJECT, and CATLAB</action> | |||
<action dev="POI-DEVELOPERS" type="fix">46199 - More tweaks to EmbeddedObjectRefSubRecord</header> | |||
<action dev="POI-DEVELOPERS" type="add">Changes to formula evaluation allowing for reduced memory usage</action> |
@@ -34,6 +34,7 @@ | |||
<!-- Don't forget to update changes.xml too! --> | |||
<changes> | |||
<release version="3.5-beta4" date="2008-??-??"> | |||
<action dev="POI-DEVELOPERS" type="fix">46174 - Fixed HSSFName to handle general formulas (not just area references)</header> | |||
<action dev="POI-DEVELOPERS" type="add">46189 - added chart records: CHARTFRTINFO, STARTBLOCK, ENDBLOCK, STARTOBJECT, ENDOBJECT, and CATLAB</action> | |||
<action dev="POI-DEVELOPERS" type="fix">46199 - More tweaks to EmbeddedObjectRefSubRecord</header> | |||
<action dev="POI-DEVELOPERS" type="add">Changes to formula evaluation allowing for reduced memory usage</action> |
@@ -17,18 +17,10 @@ | |||
package org.apache.poi.hssf.record; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.poi.hssf.model.HSSFFormulaParser; | |||
import org.apache.poi.hssf.record.formula.Area3DPtg; | |||
import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.hssf.record.formula.Ref3DPtg; | |||
import org.apache.poi.hssf.record.formula.UnionPtg; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import org.apache.poi.hssf.util.RangeAddress; | |||
import org.apache.poi.ss.formula.Formula; | |||
import org.apache.poi.ss.util.AreaReference; | |||
import org.apache.poi.util.HexDump; | |||
import org.apache.poi.util.LittleEndianInput; | |||
import org.apache.poi.util.LittleEndianOutput; | |||
@@ -414,87 +406,6 @@ public final class NameRecord extends StandardRecord { | |||
return 0; | |||
} | |||
/** sets the extern sheet number | |||
* @param externSheetNumber extern sheet number | |||
*/ | |||
public void setExternSheetNumber(short externSheetNumber){ | |||
Ptg[] ptgs = field_13_name_definition.getTokens(); | |||
Ptg ptg; | |||
if (ptgs.length < 1){ | |||
ptg = createNewPtg(); | |||
ptgs = new Ptg[] { ptg, }; | |||
} else { | |||
ptg = ptgs[0]; | |||
} | |||
if (ptg.getClass() == Area3DPtg.class){ | |||
((Area3DPtg) ptg).setExternSheetIndex(externSheetNumber); | |||
} else if (ptg.getClass() == Ref3DPtg.class){ | |||
((Ref3DPtg) ptg).setExternSheetIndex(externSheetNumber); | |||
} | |||
field_13_name_definition = Formula.create(ptgs); | |||
} | |||
private static Ptg createNewPtg(){ | |||
return new Area3DPtg("A1:A1", 0); // TODO - change to not be partially initialised | |||
} | |||
/** gets the reference , the area only (range) | |||
* @return area reference | |||
*/ | |||
public String getAreaReference(HSSFWorkbook book){ | |||
return HSSFFormulaParser.toFormulaString(book, field_13_name_definition.getTokens()); | |||
} | |||
/** sets the reference , the area only (range) | |||
* @param ref area reference | |||
*/ | |||
public void setAreaReference(String ref){ | |||
//Trying to find if what ptg do we need | |||
RangeAddress ra = new RangeAddress(ref); | |||
Ptg oldPtg; | |||
if (field_13_name_definition.getEncodedTokenSize() < 1){ | |||
oldPtg = createNewPtg(); | |||
} else { | |||
//Trying to find extern sheet index | |||
oldPtg = field_13_name_definition.getTokens()[0]; | |||
} | |||
List temp = new ArrayList(); | |||
int externSheetIndex = 0; | |||
if (oldPtg.getClass() == Area3DPtg.class){ | |||
externSheetIndex = ((Area3DPtg) oldPtg).getExternSheetIndex(); | |||
} else if (oldPtg.getClass() == Ref3DPtg.class){ | |||
externSheetIndex = ((Ref3DPtg) oldPtg).getExternSheetIndex(); | |||
} | |||
if (ra.hasRange()) { | |||
// Is it contiguous or not? | |||
AreaReference[] refs = AreaReference.generateContiguous(ref); | |||
// Add the area reference(s) | |||
for(int i=0; i<refs.length; i++) { | |||
Ptg ptg = new Area3DPtg(refs[i].formatAsString(), externSheetIndex); | |||
temp.add(ptg); | |||
} | |||
// And then a union if we had more than one area | |||
if(refs.length > 1) { | |||
Ptg ptg = UnionPtg.instance; | |||
temp.add(ptg); | |||
} | |||
} else { | |||
Ref3DPtg ptg = new Ref3DPtg(ra.getFromCell(), externSheetIndex); | |||
temp.add(ptg); | |||
} | |||
Ptg[] ptgs = new Ptg[temp.size()]; | |||
temp.toArray(ptgs); | |||
field_13_name_definition = Formula.create(ptgs); | |||
} | |||
/** | |||
* called by the constructor, should set class level fields. Should throw | |||
* runtime exception for bad/icomplete data. |
@@ -17,9 +17,10 @@ | |||
package org.apache.poi.hssf.usermodel; | |||
import org.apache.poi.hssf.model.HSSFFormulaParser; | |||
import org.apache.poi.hssf.model.Workbook; | |||
import org.apache.poi.hssf.record.NameRecord; | |||
import org.apache.poi.hssf.util.RangeAddress; | |||
import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.ss.usermodel.Name; | |||
/** | |||
@@ -80,43 +81,33 @@ public final class HSSFName implements Name { | |||
} | |||
/** | |||
* Note - this method only applies to named ranges | |||
* @return the formula text defining the named range | |||
* @deprecated (Nov 2008) Misleading name. Use {@link #getFormula()} instead. | |||
*/ | |||
public String getReference() { | |||
if (_definedNameRec.isFunctionName()) { | |||
throw new IllegalStateException("Only applicable to named ranges"); | |||
} | |||
return _definedNameRec.getAreaReference(_book); | |||
return getFormula(); | |||
} | |||
/** | |||
* sets the sheet name which this named range referenced to | |||
* @param sheetName the sheet name of the reference | |||
* @deprecated (Nov 2008) Misleading name. Use {@link #setFormula(String)} instead. | |||
*/ | |||
private void setSheetName(String sheetName){ | |||
int sheetNumber = _book.getSheetIndex(sheetName); | |||
short externSheetNumber = _book.getWorkbook().checkExternSheet(sheetNumber); | |||
_definedNameRec.setExternSheetNumber(externSheetNumber); | |||
public void setReference(String ref){ | |||
setFormula(ref); | |||
} | |||
public void setFormula(String formulaText) { | |||
Ptg[] ptgs = HSSFFormulaParser.parse(formulaText, _book); | |||
_definedNameRec.setNameDefinition(ptgs); | |||
} | |||
/** | |||
* sets the reference of this named range | |||
* @param ref the reference to set | |||
* Note - this method only applies to named ranges | |||
* @return the formula text defining this name | |||
*/ | |||
public void setReference(String ref){ | |||
RangeAddress ra = new RangeAddress(ref); | |||
String sheetName = ra.getSheetName(); | |||
if (ra.hasSheetName()) { | |||
setSheetName(sheetName); | |||
public String getFormula() { | |||
if (_definedNameRec.isFunctionName()) { | |||
throw new IllegalStateException("Only applicable to named ranges"); | |||
} | |||
//allow the poi utilities to parse it out | |||
_definedNameRec.setAreaReference(ref); | |||
return HSSFFormulaParser.toFormulaString(_book, _definedNameRec.getNameDefinition()); | |||
} | |||
/** |
@@ -33,6 +33,7 @@ import org.apache.poi.ddf.EscherBSERecord; | |||
import org.apache.poi.ddf.EscherBitmapBlip; | |||
import org.apache.poi.ddf.EscherBlipRecord; | |||
import org.apache.poi.ddf.EscherRecord; | |||
import org.apache.poi.hssf.model.HSSFFormulaParser; | |||
import org.apache.poi.hssf.model.RecordStream; | |||
import org.apache.poi.hssf.model.Sheet; | |||
import org.apache.poi.hssf.model.Workbook; | |||
@@ -57,6 +58,7 @@ import org.apache.poi.hssf.record.formula.MemFuncPtg; | |||
import org.apache.poi.hssf.record.formula.NameXPtg; | |||
import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.hssf.record.formula.Ref3DPtg; | |||
import org.apache.poi.hssf.record.formula.SheetNameFormatter; | |||
import org.apache.poi.hssf.record.formula.UnionPtg; | |||
import org.apache.poi.hssf.util.CellReference; | |||
import org.apache.poi.poifs.filesystem.DirectoryNode; | |||
@@ -1364,15 +1366,15 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1); | |||
if (name == null) | |||
name = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1); | |||
//adding one here because 0 indicates a global named region; doesnt make sense for print areas | |||
short externSheetIndex = getWorkbook().checkExternSheet(sheetIndex); | |||
name.setExternSheetNumber(externSheetIndex); | |||
name.setAreaReference(reference); | |||
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 | |||
} | |||
StringBuffer sb = new StringBuffer(32); | |||
SheetNameFormatter.appendFormat(sb, getSheetName(sheetIndex)); | |||
sb.append("!"); | |||
sb.append(reference); | |||
name.setNameDefinition(HSSFFormulaParser.parse(sb.toString(), this)); | |||
} | |||
/** | |||
@@ -1403,13 +1405,14 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
* @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java) | |||
* @return String Null if no print area has been defined | |||
*/ | |||
public String getPrintArea(int sheetIndex) | |||
{ | |||
public String getPrintArea(int sheetIndex) { | |||
NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1); | |||
if (name == null) return null; | |||
//adding one here because 0 indicates a global named region; doesnt make sense for print areas | |||
return name.getAreaReference(this); | |||
//adding one here because 0 indicates a global named region; doesn't make sense for print areas | |||
if (name == null) { | |||
return null; | |||
} | |||
return HSSFFormulaParser.toFormulaString(this, name.getNameDefinition()); | |||
} | |||
/** |
@@ -1,367 +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.util; | |||
/** | |||
* Title: Range Address <P> | |||
* Description: provides connectivity utilities for ranges<P> | |||
* | |||
* | |||
* REFERENCE: <P> | |||
* @author IgOr KaTz && EuGeNe BuMaGiN (Tal Moshaiov) (VistaPortal LDT.) | |||
@version 1.0 | |||
*/ | |||
public class RangeAddress { | |||
final static int WRONG_POS = -1; | |||
final static int MAX_HEIGHT = 66666; | |||
final static char SO_FORMNAME_ENCLOSURE = '\''; | |||
String m_sheetName; | |||
String m_cellFrom; | |||
String m_cellTo; | |||
/** | |||
* Accepts an external reference from excel. | |||
* <p> | |||
* i.e. Sheet1!$A$4:$B$9 | |||
* @param _url | |||
*/ | |||
public RangeAddress (String _url) { | |||
init (_url); | |||
} | |||
public RangeAddress (int _startCol, int _startRow, int _endCol, int _endRow) { | |||
init (numTo26Sys (_startCol) + _startRow + ":" | |||
+ numTo26Sys (_endCol) + _endRow); | |||
} | |||
/** | |||
* | |||
* @return String <b>note: </b> All absolute references are removed | |||
*/ | |||
public String getAddress (){ | |||
String result = ""; | |||
if(m_sheetName != null) | |||
result += m_sheetName+"!"; | |||
if(m_cellFrom != null){ | |||
result += m_cellFrom; | |||
if(m_cellTo != null) | |||
result += ":" + m_cellTo; | |||
} | |||
return result; | |||
} | |||
public String getSheetName (){ | |||
return m_sheetName; | |||
} | |||
public String getRange (){ | |||
String result = ""; | |||
if(m_cellFrom != null){ | |||
result += m_cellFrom; | |||
if(m_cellTo != null) | |||
result += ":" + m_cellTo; | |||
} | |||
return result; | |||
} | |||
public boolean isCellOk (String _cell){ | |||
if (_cell != null){ | |||
if ( (getYPosition (_cell) != WRONG_POS) && | |||
(getXPosition (_cell) != WRONG_POS) ) | |||
return true; | |||
else | |||
return false; | |||
} else | |||
return false; | |||
} | |||
public boolean isSheetNameOk (){ | |||
return isSheetNameOk (m_sheetName); | |||
} | |||
private static boolean intern_isSheetNameOk (String _sheetName, boolean _canBeWaitSpace){ | |||
for (int i = 0 ; i < _sheetName.length (); i++){ | |||
char ch = _sheetName.charAt (i); | |||
if (! (Character.isLetterOrDigit (ch) || (ch == '_')|| | |||
_canBeWaitSpace&&(ch == ' '))){ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
public static boolean isSheetNameOk (String _sheetName){ | |||
boolean res = false; | |||
if ( ( _sheetName != null) && !_sheetName.equals ("")){ | |||
res = intern_isSheetNameOk (_sheetName,true); | |||
}else | |||
res = true; | |||
return res; | |||
} | |||
public String getFromCell (){ | |||
return m_cellFrom; | |||
} | |||
public String getToCell (){ | |||
return m_cellTo; | |||
} | |||
public int getWidth (){ | |||
if(m_cellFrom != null && m_cellTo != null){ | |||
int toX = getXPosition (m_cellTo); | |||
int fromX = getXPosition (m_cellFrom); | |||
if ((toX == WRONG_POS) || (fromX == WRONG_POS)){ | |||
return 0; | |||
}else | |||
return toX - fromX + 1; | |||
} | |||
return 0; | |||
} | |||
public int getHeight (){ | |||
if(m_cellFrom != null && m_cellTo != null){ | |||
int toY = getYPosition (m_cellTo); | |||
int fromY = getYPosition (m_cellFrom); | |||
if ((toY == WRONG_POS) || (fromY == WRONG_POS)){ | |||
return 0; | |||
}else | |||
return toY - fromY + 1; | |||
} | |||
return 0; | |||
} | |||
public void setSize (int _width, int _height){ | |||
if(m_cellFrom == null) | |||
m_cellFrom = "a1"; | |||
int tlX, tlY, rbX, rbY; | |||
tlX = getXPosition (m_cellFrom); | |||
tlY = getYPosition (m_cellFrom); | |||
m_cellTo = numTo26Sys (tlX + _width - 1); | |||
m_cellTo += String.valueOf (tlY + _height - 1); | |||
} | |||
public boolean hasSheetName (){ | |||
if(m_sheetName == null) | |||
return false; | |||
return true; | |||
} | |||
public boolean hasRange (){ | |||
return (m_cellFrom != null && m_cellTo != null && !m_cellFrom.equals(m_cellTo)); | |||
} | |||
public boolean hasCell (){ | |||
if(m_cellFrom == null) | |||
return false; | |||
return true; | |||
} | |||
private void init (String _url){ | |||
_url = removeString(_url, "$"); | |||
_url = removeString(_url, "'"); | |||
String[] urls = parseURL (_url); | |||
m_sheetName = urls[0]; | |||
m_cellFrom = urls[1]; | |||
m_cellTo = urls[2]; | |||
//What if range is one celled ? | |||
if (m_cellTo == null){ | |||
m_cellTo = m_cellFrom; | |||
} | |||
//Removing noneeds characters | |||
m_cellTo = removeString(m_cellTo,"."); | |||
} | |||
private String[] parseURL (String _url){ | |||
String[] result = new String[3]; | |||
int index = _url.indexOf(':'); | |||
if (index >= 0) { | |||
String fromStr = _url.substring(0, index); | |||
String toStr = _url.substring(index+1); | |||
index = fromStr.indexOf('!'); | |||
if (index >= 0) { | |||
result[0] = fromStr.substring(0, index); | |||
result[1] = fromStr.substring(index+1); | |||
} else { | |||
result[1] = fromStr; | |||
} | |||
index = toStr.indexOf('!'); | |||
if (index >= 0) { | |||
result[2] = toStr.substring(index+1); | |||
} else { | |||
result[2] = toStr; | |||
} | |||
} else { | |||
index = _url.indexOf('!'); | |||
if (index >= 0) { | |||
result[0] = _url.substring(0, index); | |||
result[1] = _url.substring(index+1); | |||
} else { | |||
result[1] = _url; | |||
} | |||
} | |||
return result; | |||
} | |||
public int getYPosition (String _subrange){ | |||
int result = WRONG_POS; | |||
_subrange = _subrange.trim (); | |||
if (_subrange.length () != 0){ | |||
String digitstr = getDigitPart (_subrange); | |||
try { | |||
result = Integer.parseInt (digitstr); | |||
if (result > MAX_HEIGHT){ | |||
result = WRONG_POS; | |||
} | |||
} | |||
catch (Exception ex) { | |||
result = WRONG_POS; | |||
} | |||
} | |||
return result; | |||
} | |||
private static boolean isLetter (String _str){ | |||
boolean res = true; | |||
if ( !_str.equals ("") ){ | |||
for (int i = 0 ; i < _str.length (); i++){ | |||
char ch = _str.charAt (i); | |||
if (! Character.isLetter (ch)){ | |||
res = false; | |||
break; | |||
} | |||
} | |||
}else | |||
res = false; | |||
return res; | |||
} | |||
public int getXPosition (String _subrange){ | |||
int result = WRONG_POS; | |||
String tmp = filter$ (_subrange); | |||
tmp = this.getCharPart (_subrange); | |||
// we will process only 2 letters ranges | |||
if (isLetter (tmp) && ((tmp.length () == 2)|| (tmp.length () == 1) )){ | |||
result = get26Sys (tmp); | |||
} | |||
return result; | |||
} | |||
public String getDigitPart (String _value){ | |||
String result = ""; | |||
int digitpos = getFirstDigitPosition (_value); | |||
if(digitpos >= 0){ | |||
result = _value.substring (digitpos); | |||
} | |||
return result; | |||
} | |||
public String getCharPart (String _value){ | |||
String result = ""; | |||
int digitpos = getFirstDigitPosition (_value); | |||
if(digitpos >= 0){ | |||
result = _value.substring (0, digitpos); | |||
} | |||
return result; | |||
} | |||
private String filter$ (String _range){ | |||
String res = ""; | |||
for (int i = 0 ; i < _range.length () ; i++){ | |||
char ch = _range.charAt (i); | |||
if ( ch != '$' ){ | |||
res = res + ch; | |||
} | |||
} | |||
return res; | |||
} | |||
private int getFirstDigitPosition (String _value){ | |||
int result = WRONG_POS; | |||
if(_value != null && _value.trim ().length () == 0){ | |||
return result; | |||
} | |||
_value = _value.trim (); | |||
int length = _value.length (); | |||
for(int i = 0; i < length; i++){ | |||
if(Character.isDigit (_value.charAt (i))){ | |||
result = i; | |||
break; | |||
} | |||
} | |||
return result; | |||
} | |||
public int get26Sys (String _s){ | |||
int sum = 0; | |||
int multiplier = 1; | |||
if (_s != "") { | |||
for (int i = _s.length ()-1 ; i >= 0 ; i--){ | |||
char ch = _s.charAt (i); | |||
int val = Character.getNumericValue (ch) - Character.getNumericValue ('A')+1; | |||
sum = sum + val * multiplier; | |||
multiplier = multiplier * 26; | |||
} | |||
return sum; | |||
} | |||
return WRONG_POS; | |||
} | |||
public String numTo26Sys (int _num){ | |||
int sum = 0; | |||
int reminder; | |||
String s =""; | |||
do{ | |||
_num --; | |||
reminder = _num % 26; | |||
int val = 65 + reminder; | |||
_num = _num / 26; | |||
s = (char)val + s; // reverce | |||
}while(_num > 0); | |||
return s; | |||
} | |||
public String replaceString(String _source , String _oldPattern, | |||
String _newPattern){ | |||
StringBuffer res = new StringBuffer(_source); | |||
int pos = -1; | |||
while ((pos = res.toString().indexOf(_oldPattern, pos)) > -1){ | |||
res.replace(pos, pos + _oldPattern.length(), _newPattern); | |||
} | |||
return res.toString(); | |||
} | |||
public String removeString(String _source, String _match){ | |||
return replaceString(_source, _match, ""); | |||
} | |||
} |
@@ -41,7 +41,6 @@ public final class TestFormulaParserEval extends TestCase { | |||
public void testWithNamedRange() { | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
Ptg[] ptgs; | |||
HSSFSheet s = workbook.createSheet("Foo"); | |||
s.createRow(0).createCell(0).setCellValue(1.1); | |||
@@ -52,21 +51,25 @@ public final class TestFormulaParserEval extends TestCase { | |||
name.setNameName("testName"); | |||
name.setReference("A1:A2"); | |||
ptgs = HSSFFormulaParser.parse("SUM(testName)", workbook); | |||
assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2); | |||
assertEquals(NamePtg.class, ptgs[0].getClass()); | |||
assertEquals(FuncVarPtg.class, ptgs[1].getClass()); | |||
confirmParseFormula(workbook); | |||
// Now make it a single cell | |||
name.setReference("C3"); | |||
ptgs = HSSFFormulaParser.parse("SUM(testName)", workbook); | |||
assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2); | |||
assertEquals(NamePtg.class, ptgs[0].getClass()); | |||
assertEquals(FuncVarPtg.class, ptgs[1].getClass()); | |||
confirmParseFormula(workbook); | |||
// And make it non-contiguous | |||
name.setReference("A1:A2,C3"); | |||
ptgs = HSSFFormulaParser.parse("SUM(testName)", workbook); | |||
if (false) { // TODO (Nov 2008) - make the formula parser support area unions | |||
name.setReference("A1:A2,C3"); | |||
} | |||
confirmParseFormula(workbook); | |||
} | |||
/** | |||
* Makes sure that a formula referring to the named range parses properly | |||
*/ | |||
private static void confirmParseFormula(HSSFWorkbook workbook) { | |||
Ptg[] ptgs = HSSFFormulaParser.parse("SUM(testName)", workbook); | |||
assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2); | |||
assertEquals(NamePtg.class, ptgs[0].getClass()); | |||
assertEquals(FuncVarPtg.class, ptgs[1].getClass()); |
@@ -17,8 +17,11 @@ | |||
package org.apache.poi.hssf.record; | |||
import org.apache.poi.hssf.usermodel.HSSFName; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import org.apache.poi.util.HexRead; | |||
import junit.framework.AssertionFailedError; | |||
import junit.framework.TestCase; | |||
/** | |||
@@ -55,4 +58,27 @@ public final class TestNameRecord extends TestCase { | |||
byte[] data2 = nr.serialize(); | |||
TestcaseRecordInputStream.confirmRecordEncoding(NameRecord.sid, data, data2); | |||
} | |||
public void testFormulaRelAbs_bug46174() { | |||
// perhaps this testcase belongs on TestHSSFName | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFName name = wb.createName(); | |||
wb.createSheet("Sheet1"); | |||
name.setNameName("test"); | |||
name.setReference("Sheet1!$B$3"); | |||
if (name.getReference().equals("Sheet1!B3")) { | |||
throw new AssertionFailedError("Identified bug 46174"); | |||
} | |||
assertEquals("Sheet1!$B$3", name.getReference()); | |||
} | |||
public void testFormulaGeneral() { | |||
// perhaps this testcase belongs on TestHSSFName | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFName name = wb.createName(); | |||
wb.createSheet("Sheet1"); | |||
name.setNameName("test"); | |||
name.setFormula("Sheet1!A1+Sheet1!A2"); | |||
assertEquals("Sheet1!A1+Sheet1!A2", name.getFormula()); | |||
name.setFormula("5*6"); | |||
assertEquals("5*6", name.getFormula()); | |||
} | |||
} |
@@ -26,6 +26,7 @@ import junit.framework.AssertionFailedError; | |||
import junit.framework.TestCase; | |||
import org.apache.poi.hssf.HSSFTestDataSamples; | |||
import org.apache.poi.hssf.model.HSSFFormulaParser; | |||
import org.apache.poi.hssf.model.Sheet; | |||
import org.apache.poi.hssf.record.NameRecord; | |||
import org.apache.poi.hssf.record.Record; | |||
@@ -533,7 +534,7 @@ public final class TestHSSFWorkbook extends TestCase { | |||
assertEquals(3, wb.getWorkbook().getNumNames()); | |||
nr = wb.getWorkbook().getNameRecord(2); | |||
// TODO - render full row and full column refs properly | |||
assertEquals("Sheet2!$A$1:$IV$1", nr.getAreaReference(wb)); // 1:1 | |||
assertEquals("Sheet2!$A$1:$IV$1", HSSFFormulaParser.toFormulaString(wb, nr.getNameDefinition())); // 1:1 | |||
try { | |||
wb.setRepeatingRowsAndColumns(3, 4, 5, 8, 11); | |||
@@ -547,6 +548,6 @@ public final class TestHSSFWorkbook extends TestCase { | |||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
assertEquals(3, wb.getWorkbook().getNumNames()); | |||
nr = wb.getWorkbook().getNameRecord(2); | |||
assertEquals("Sheet2!E:F,Sheet2!$A$9:$IV$12", nr.getAreaReference(wb)); // E:F,9:12 | |||
assertEquals("Sheet2!E:F,Sheet2!$A$9:$IV$12", HSSFFormulaParser.toFormulaString(wb, nr.getNameDefinition())); // E:F,9:12 | |||
} | |||
} |
@@ -28,11 +28,11 @@ import org.apache.poi.ss.util.AreaReference; | |||
import org.apache.poi.ss.util.CellReference; | |||
/** | |||
* | |||
* | |||
* @author ROMANL | |||
* @author Andrew C. Oliver (acoliver at apache dot org) | |||
* @author Danny Mui (danny at muibros.com) | |||
* @author Amol S. Deshmukh < amol at ap ache dot org > | |||
* @author Amol S. Deshmukh < amol at ap ache dot org > | |||
*/ | |||
public final class TestNamedRange extends TestCase { | |||
@@ -59,8 +59,6 @@ public final class TestNamedRange extends TestCase { | |||
HSSFName namedRange1 = wb.getNameAt(0); | |||
//Getting it sheet name | |||
sheetName = namedRange1.getSheetName(); | |||
//Getting its reference | |||
String referece = namedRange1.getReference(); | |||
// sanity check | |||
SanityChecker c = new SanityChecker(); | |||
@@ -71,12 +69,12 @@ public final class TestNamedRange extends TestCase { | |||
assertTrue("Name is "+nm.getNameName(),"RangeTest".equals(nm.getNameName())); | |||
assertEquals(wb.getSheetName(0)+"!$D$4:$E$8", nm.getReference()); | |||
} | |||
/** | |||
* Reads an excel file already containing a named range. | |||
* <p> | |||
* Addresses Bug <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=9632" target="_bug">#9632</a> | |||
*/ | |||
*/ | |||
public void testNamedRead() { | |||
HSSFWorkbook wb = openSample("namedinput.xls"); | |||
@@ -89,7 +87,7 @@ public final class TestNamedRange extends TestCase { | |||
//Getting its reference | |||
String reference = namedRange1.getReference(); | |||
assertEquals(sheetName+"!$A$1:$D$10", reference); | |||
HSSFName namedRange2 = wb.getNameAt(1); | |||
@@ -112,10 +110,10 @@ public final class TestNamedRange extends TestCase { | |||
assertEquals(sheetName+"!$A$1:$D$10", name.getReference()); | |||
name = wb.getNameAt(1); | |||
String newReference = sheetName +"!$A$1:$C$36"; | |||
String newReference = sheetName +"!$A$1:$C$36"; | |||
name.setReference(newReference); | |||
assertEquals(newReference, name.getReference()); | |||
assertEquals(newReference, name.getReference()); | |||
} | |||
/** | |||
@@ -123,13 +121,13 @@ public final class TestNamedRange extends TestCase { | |||
*/ | |||
public void testMultipleNamedWrite() { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
wb.createSheet("testSheet1"); | |||
String sheetName = wb.getSheetName(0); | |||
assertEquals("testSheet1", sheetName); | |||
//Creating new Named Range | |||
HSSFName newNamedRange = wb.createName(); | |||
@@ -142,15 +140,13 @@ public final class TestNamedRange extends TestCase { | |||
newNamedRange2.setNameName("AnotherTest"); | |||
newNamedRange2.setReference(sheetName + "!$F$1:$G$6"); | |||
HSSFName namedRange1 = wb.getNameAt(0); | |||
String referece = namedRange1.getReference(); | |||
wb.getNameAt(0); | |||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
HSSFName nm =wb.getNameAt(wb.getNameIndex("RangeTest")); | |||
assertTrue("Name is "+nm.getNameName(),"RangeTest".equals(nm.getNameName())); | |||
assertTrue("Reference is "+nm.getReference(),(wb.getSheetName(0)+"!$D$4:$E$8").equals(nm.getReference())); | |||
nm = wb.getNameAt(wb.getNameIndex("AnotherTest")); | |||
assertTrue("Name is "+nm.getNameName(),"AnotherTest".equals(nm.getNameName())); | |||
assertTrue("Reference is "+nm.getReference(),newNamedRange2.getReference().equals(nm.getReference())); | |||
@@ -192,7 +188,7 @@ public final class TestNamedRange extends TestCase { | |||
// Set the reference for the named range for worksheet 'sheet2' | |||
namedRange2.setReference("sheet2" + "!$A$1:$O$21"); | |||
// Write the workbook to a file | |||
// Read the Excel file and verify its content | |||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
@@ -203,7 +199,7 @@ public final class TestNamedRange extends TestCase { | |||
HSSFName nm2 =wb.getNameAt(wb.getNameIndex("RangeTest2")); | |||
assertTrue("Name is "+nm2.getNameName(),"RangeTest2".equals(nm2.getNameName())); | |||
assertTrue("Reference is "+nm2.getReference(),(wb.getSheetName(1)+"!$A$1:$O$21").equals(nm2.getReference())); | |||
} | |||
} | |||
public void testUnicodeNamedRange() { | |||
HSSFWorkbook workBook = new HSSFWorkbook(); | |||
@@ -223,15 +219,14 @@ public final class TestNamedRange extends TestCase { | |||
/** | |||
* Test to see if the print areas can be retrieved/created in memory | |||
*/ | |||
public void testSinglePrintArea() | |||
{ | |||
public void testSinglePrintArea() { | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
HSSFSheet sheet = workbook.createSheet("Test Print Area"); | |||
workbook.createSheet("Test Print Area"); | |||
String sheetName = workbook.getSheetName(0); | |||
String reference = sheetName+"!$A$1:$B$1"; | |||
String reference = "$A$1:$B$1"; | |||
workbook.setPrintArea(0, reference); | |||
String retrievedPrintArea = workbook.getPrintArea(0); | |||
assertNotNull("Print Area not defined for first sheet", retrievedPrintArea); | |||
@@ -239,17 +234,17 @@ public final class TestNamedRange extends TestCase { | |||
} | |||
/** | |||
* For Convenience, dont force sheet names to be used | |||
* For Convenience, don't force sheet names to be used | |||
*/ | |||
public void testSinglePrintAreaWOSheet() | |||
{ | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
HSSFSheet sheet = workbook.createSheet("Test Print Area"); | |||
workbook.createSheet("Test Print Area"); | |||
String sheetName = workbook.getSheetName(0); | |||
String reference = "$A$1:$B$1"; | |||
workbook.setPrintArea(0, reference); | |||
String retrievedPrintArea = workbook.getPrintArea(0); | |||
assertNotNull("Print Area not defined for first sheet", retrievedPrintArea); | |||
@@ -275,14 +270,14 @@ public final class TestNamedRange extends TestCase { | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
workbook.createSheet("Test Print Area"); | |||
String sheetName = workbook.getSheetName(0); | |||
String reference = sheetName+"!$A$1:$B$1"; | |||
String reference = "$A$1:$B$1"; | |||
workbook.setPrintArea(0, reference); | |||
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); | |||
String retrievedPrintArea = workbook.getPrintArea(0); | |||
String retrievedPrintArea = workbook.getPrintArea(0); | |||
assertNotNull("Print Area not defined for first sheet", retrievedPrintArea); | |||
assertEquals("References Match", "'" + sheetName + "'!$A$1:$B$1", retrievedPrintArea); | |||
} | |||
@@ -296,43 +291,43 @@ public final class TestNamedRange extends TestCase { | |||
workbook.createSheet("Sheet1"); | |||
workbook.createSheet("Sheet2"); | |||
workbook.createSheet("Sheet3"); | |||
String reference1 = "Sheet1!$A$1:$B$1"; | |||
String reference2 = "Sheet2!$B$2:$D$5"; | |||
String reference3 = "Sheet3!$D$2:$F$5"; | |||
workbook.setPrintArea(0, reference1); | |||
String reference1 = "$A$1:$B$1"; | |||
String reference2 = "$B$2:$D$5"; | |||
String reference3 = "$D$2:$F$5"; | |||
workbook.setPrintArea(0, reference1); | |||
workbook.setPrintArea(1, reference2); | |||
workbook.setPrintArea(2, reference3); | |||
//Check created print areas | |||
String retrievedPrintArea; | |||
retrievedPrintArea = workbook.getPrintArea(0); | |||
assertNotNull("Print Area Not Found (Sheet 1)", retrievedPrintArea); | |||
assertEquals(reference1, retrievedPrintArea); | |||
assertEquals("Sheet1!" + reference1, retrievedPrintArea); | |||
retrievedPrintArea = workbook.getPrintArea(1); | |||
assertNotNull("Print Area Not Found (Sheet 2)", retrievedPrintArea); | |||
assertEquals(reference2, retrievedPrintArea); | |||
assertEquals("Sheet2!" + reference2, retrievedPrintArea); | |||
retrievedPrintArea = workbook.getPrintArea(2); | |||
assertNotNull("Print Area Not Found (Sheet 3)", retrievedPrintArea); | |||
assertEquals(reference3, retrievedPrintArea); | |||
assertEquals("Sheet3!" + reference3, retrievedPrintArea); | |||
// Check print areas after re-reading workbook | |||
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); | |||
retrievedPrintArea = workbook.getPrintArea(0); | |||
assertNotNull("Print Area Not Found (Sheet 1)", retrievedPrintArea); | |||
assertEquals(reference1, retrievedPrintArea); | |||
assertEquals("Sheet1!" + reference1, retrievedPrintArea); | |||
retrievedPrintArea = workbook.getPrintArea(1); | |||
assertNotNull("Print Area Not Found (Sheet 2)", retrievedPrintArea); | |||
assertEquals(reference2, retrievedPrintArea); | |||
assertEquals("Sheet2!" + reference2, retrievedPrintArea); | |||
retrievedPrintArea = workbook.getPrintArea(2); | |||
assertNotNull("Print Area Not Found (Sheet 3)", retrievedPrintArea); | |||
assertEquals(reference3, retrievedPrintArea); | |||
assertEquals("Sheet3!" + reference3, retrievedPrintArea); | |||
} | |||
/** | |||
@@ -341,12 +336,11 @@ public final class TestNamedRange extends TestCase { | |||
*/ | |||
public void testPrintAreaCoords(){ | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
HSSFSheet sheet = workbook.createSheet("Test Print Area"); | |||
workbook.createSheet("Test Print Area"); | |||
String sheetName = workbook.getSheetName(0); | |||
String reference = sheetName+"!$A$1:$B$1"; | |||
workbook.setPrintArea(0, 0, 1, 0, 0); | |||
String retrievedPrintArea = workbook.getPrintArea(0); | |||
assertNotNull("Print Area not defined for first sheet", retrievedPrintArea); | |||
@@ -360,18 +354,17 @@ public final class TestNamedRange extends TestCase { | |||
*/ | |||
public void testPrintAreaUnion(){ | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
HSSFSheet sheet = workbook.createSheet("Test Print Area"); | |||
workbook.createSheet("Test Print Area"); | |||
String sheetName = workbook.getSheetName(0); | |||
String reference = sheetName + "!$A$1:$B$1, " + sheetName + "!$D$1:$F$2"; | |||
String expResult = "'" + 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(expResult, retrievedPrintArea); | |||
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); | |||
} | |||
} | |||
/** | |||
@@ -380,18 +373,17 @@ public final class TestNamedRange extends TestCase { | |||
*/ | |||
public void testPrintAreaRemove() { | |||
HSSFWorkbook workbook = new HSSFWorkbook(); | |||
HSSFSheet sheet = workbook.createSheet("Test Print Area"); | |||
String sheetName = workbook.getSheetName(0); | |||
String reference = sheetName+"!$A$1:$B$1"; | |||
workbook.createSheet("Test Print Area"); | |||
workbook.getSheetName(0); | |||
workbook.setPrintArea(0, 0, 1, 0, 0); | |||
String retrievedPrintArea = workbook.getPrintArea(0); | |||
assertNotNull("Print Area not defined for first sheet", retrievedPrintArea); | |||
workbook.removePrintArea(0); | |||
assertNull("PrintArea was not removed", workbook.getPrintArea(0)); | |||
assertNull("PrintArea was not removed", workbook.getPrintArea(0)); | |||
} | |||
/** | |||
@@ -406,11 +398,11 @@ public final class TestNamedRange extends TestCase { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet sheet = wb.createSheet(sheetName); | |||
sheet.createRow(0).createCell(0).setCellValue(new HSSFRichTextString(cellValue)); | |||
// create named range for a single cell using areareference | |||
HSSFName namedCell = wb.createName(); | |||
namedCell.setNameName(cellName); | |||
String reference = sheetName+"!A1:A1"; | |||
String reference = "'" + sheetName + "'" + "!A1:A1"; | |||
namedCell.setReference(reference); | |||
// retrieve the newly created named range | |||
@@ -442,7 +434,7 @@ public final class TestNamedRange extends TestCase { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet sheet = wb.createSheet(sname); | |||
sheet.createRow(0).createCell(0).setCellValue(new HSSFRichTextString(cvalue)); | |||
// create named range for a single cell using cellreference | |||
HSSFName namedCell = wb.createName(); | |||
namedCell.setNameName(cname); | |||
@@ -471,7 +463,7 @@ public final class TestNamedRange extends TestCase { | |||
HSSFName name1 = wb.getNameAt(0); | |||
assertEquals("a", name1.getNameName()); | |||
assertEquals("Sheet1!$A$1", name1.getReference()); | |||
AreaReference ref1 = new AreaReference(name1.getReference()); | |||
new AreaReference(name1.getReference()); | |||
assertTrue("Successfully constructed first reference", true); | |||
HSSFName name2 = wb.getNameAt(1); | |||
@@ -479,19 +471,19 @@ public final class TestNamedRange extends TestCase { | |||
assertEquals("Sheet1!#REF!", name2.getReference()); | |||
assertTrue(name2.isDeleted()); | |||
try { | |||
AreaReference ref2 = new AreaReference(name2.getReference()); | |||
new AreaReference(name2.getReference()); | |||
fail("attempt to supply an invalid reference to AreaReference constructor results in exception"); | |||
} catch (StringIndexOutOfBoundsException e) { // TODO - use a different exception for this condition | |||
// expected during successful test | |||
} | |||
} | |||
} | |||
public void testRepeatingRowsAndColumsNames() { | |||
// First test that setting RR&C for same sheet more than once only creates a | |||
// First test that setting RR&C for same sheet more than once only creates a | |||
// single Print_Titles built-in record | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet sheet = wb.createSheet("FirstSheet"); | |||
// set repeating rows and columns twice for the first sheet | |||
for (int i = 0; i < 2; i++) { | |||
wb.setRepeatingRowsAndColumns(0, 0, 0, 0, 3-1); | |||
@@ -499,7 +491,7 @@ public final class TestNamedRange extends TestCase { | |||
} | |||
assertEquals(1, wb.getNumberOfNames()); | |||
HSSFName nr1 = wb.getNameAt(0); | |||
assertEquals("Print_Titles", nr1.getNameName()); | |||
if (false) { | |||
// TODO - full column references not rendering properly, absolute markers not present either | |||
@@ -507,16 +499,16 @@ public final class TestNamedRange extends TestCase { | |||
} else { | |||
assertEquals("FirstSheet!A:A,FirstSheet!$A$1:$IV$3", nr1.getReference()); | |||
} | |||
// Save and re-open | |||
HSSFWorkbook nwb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
assertEquals(1, nwb.getNumberOfNames()); | |||
nr1 = nwb.getNameAt(0); | |||
assertEquals("Print_Titles", nr1.getNameName()); | |||
assertEquals("FirstSheet!A:A,FirstSheet!$A$1:$IV$3", nr1.getReference()); | |||
// check that setting RR&C on a second sheet causes a new Print_Titles built-in | |||
// name to be created | |||
sheet = nwb.createSheet("SecondSheet"); | |||
@@ -524,10 +516,10 @@ public final class TestNamedRange extends TestCase { | |||
assertEquals(2, nwb.getNumberOfNames()); | |||
HSSFName nr2 = nwb.getNameAt(1); | |||
assertEquals("Print_Titles", nr2.getNameName()); | |||
assertEquals("SecondSheet!B:C,SecondSheet!$A$1:$IV$1", nr2.getReference()); | |||
if (false) { | |||
// In case you fancy checking in excel, to ensure it | |||
// won't complain about the file now |
@@ -32,7 +32,6 @@ public class AllHSSFUtilTests { | |||
result.addTestSuite(TestAreaReference.class); | |||
result.addTestSuite(TestCellReference.class); | |||
result.addTestSuite(TestHSSFColor.class); | |||
result.addTestSuite(TestRangeAddress.class); | |||
result.addTestSuite(TestRKUtil.class); | |||
return result; | |||
} |
@@ -23,6 +23,7 @@ import java.io.InputStream; | |||
import junit.framework.TestCase; | |||
import org.apache.poi.hssf.HSSFTestDataSamples; | |||
import org.apache.poi.hssf.model.HSSFFormulaParser; | |||
import org.apache.poi.hssf.model.Workbook; | |||
import org.apache.poi.hssf.record.NameRecord; | |||
import org.apache.poi.hssf.record.formula.Area3DPtg; | |||
@@ -107,6 +108,7 @@ public final class TestAreaReference extends TestCase { | |||
TestCellReference.confirmCell(allCells[2], "Tabelle1", 6, 1, true, true, "Tabelle1!$B$7"); | |||
} | |||
// TODO - remove this sub-class | |||
private static final class HSSFWB extends HSSFWorkbook { | |||
public HSSFWB(InputStream in) throws IOException { | |||
super(in); | |||
@@ -220,7 +222,7 @@ public final class TestAreaReference extends TestCase { | |||
assertEquals(refB, ptgC.toFormulaString(eb)); | |||
assertEquals(",", ptgD.toFormulaString()); | |||
assertEquals(ref, nr.getAreaReference(wb)); | |||
assertEquals(ref, HSSFFormulaParser.toFormulaString(wb, nr.getNameDefinition())); | |||
// Check the high level definition | |||
int idx = wb.getNameIndex("test"); |
@@ -1,46 +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.util; | |||
import junit.framework.TestCase; | |||
/** | |||
* Tests the Range Address Utility Functionality | |||
* @author Danny Mui (danny at muibros.com) | |||
*/ | |||
public class TestRangeAddress extends TestCase { | |||
public TestRangeAddress(String s) { | |||
super(s); | |||
} | |||
public static void main(java.lang.String[] args) { | |||
junit.textui.TestRunner.run(TestRangeAddress.class); | |||
} | |||
public void testReferenceParse() { | |||
String reference = "Sheet2!$A$1:$C$3"; | |||
RangeAddress ra = new RangeAddress(reference); | |||
assertEquals("Sheet2!A1:C3", ra.getAddress()); | |||
} | |||
} |