Partial HSSF support for adding new external workbook formula references for #57184
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1636742 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4b479d98c4
commit
0fdd7a1dbc
@ -94,6 +94,7 @@ import org.apache.poi.ss.formula.ptg.Ptg;
|
|||||||
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
|
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
|
||||||
import org.apache.poi.ss.formula.udf.UDFFinder;
|
import org.apache.poi.ss.formula.udf.UDFFinder;
|
||||||
import org.apache.poi.ss.usermodel.BuiltinFormats;
|
import org.apache.poi.ss.usermodel.BuiltinFormats;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
@ -1804,6 +1805,10 @@ public final class InternalWorkbook {
|
|||||||
return linkTable;
|
return linkTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int linkExternalWorkbook(String name, Workbook externalWorkbook) {
|
||||||
|
return getOrCreateLinkTable().linkExternalWorkbook(name, externalWorkbook);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the first sheet name by his extern sheet index
|
* Finds the first sheet name by his extern sheet index
|
||||||
* @param externSheetIndex extern sheet index
|
* @param externSheetIndex extern sheet index
|
||||||
|
@ -37,6 +37,7 @@ import org.apache.poi.ss.formula.ptg.ErrPtg;
|
|||||||
import org.apache.poi.ss.formula.ptg.NameXPtg;
|
import org.apache.poi.ss.formula.ptg.NameXPtg;
|
||||||
import org.apache.poi.ss.formula.ptg.Ptg;
|
import org.apache.poi.ss.formula.ptg.Ptg;
|
||||||
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
|
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link Table (OOO pdf reference: 4.10.3 ) <p/>
|
* Link Table (OOO pdf reference: 4.10.3 ) <p/>
|
||||||
@ -111,6 +112,14 @@ final class LinkTable {
|
|||||||
temp.toArray(_crnBlocks);
|
temp.toArray(_crnBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new block for external references.
|
||||||
|
*/
|
||||||
|
public ExternalBookBlock(String url, String[] sheetNames) {
|
||||||
|
_externalBookRecord = SupBookRecord.createExternalReferences(url, sheetNames);
|
||||||
|
_crnBlocks = new CRNBlock[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new block for internal references. It is called when constructing a new LinkTable.
|
* Create a new block for internal references. It is called when constructing a new LinkTable.
|
||||||
*
|
*
|
||||||
@ -383,30 +392,67 @@ final class LinkTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getExternalSheetIndex(String workbookName, String firstSheetName, String lastSheetName) {
|
private int getExternalWorkbookIndex(String workbookName) {
|
||||||
SupBookRecord ebrTarget = null;
|
|
||||||
int externalBookIndex = -1;
|
|
||||||
for (int i=0; i<_externalBookBlocks.length; i++) {
|
for (int i=0; i<_externalBookBlocks.length; i++) {
|
||||||
SupBookRecord ebr = _externalBookBlocks[i].getExternalBookRecord();
|
SupBookRecord ebr = _externalBookBlocks[i].getExternalBookRecord();
|
||||||
if (!ebr.isExternalReferences()) {
|
if (!ebr.isExternalReferences()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (workbookName.equals(ebr.getURL())) { // not sure if 'equals()' works when url has a directory
|
if (workbookName.equals(ebr.getURL())) { // not sure if 'equals()' works when url has a directory
|
||||||
ebrTarget = ebr;
|
return i;
|
||||||
externalBookIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ebrTarget == null) {
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int linkExternalWorkbook(String name, Workbook externalWorkbook) {
|
||||||
|
int extBookIndex = getExternalWorkbookIndex(name);
|
||||||
|
if (extBookIndex != -1) {
|
||||||
|
// Already linked!
|
||||||
|
return extBookIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new SupBookRecord
|
||||||
|
String[] sheetNames = new String[externalWorkbook.getNumberOfSheets()];
|
||||||
|
for (int sn=0; sn<sheetNames.length; sn++) {
|
||||||
|
sheetNames[sn] = externalWorkbook.getSheetName(sn);
|
||||||
|
}
|
||||||
|
String url = "\000" + name;
|
||||||
|
ExternalBookBlock block = new ExternalBookBlock(url, sheetNames);
|
||||||
|
|
||||||
|
// Add it into the list + records
|
||||||
|
extBookIndex = extendExternalBookBlocks(block);
|
||||||
|
|
||||||
|
// add the created SupBookRecord before ExternSheetRecord
|
||||||
|
int idx = findFirstRecordLocBySid(ExternSheetRecord.sid);
|
||||||
|
if (idx == -1) {
|
||||||
|
idx = _workbookRecordList.size();
|
||||||
|
}
|
||||||
|
_workbookRecordList.add(idx, block.getExternalBookRecord());
|
||||||
|
|
||||||
|
// Setup links for the sheets
|
||||||
|
for (int sn=0; sn<sheetNames.length; sn++) {
|
||||||
|
_externSheetRecord.addRef(extBookIndex, sn, sn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report where it went
|
||||||
|
return extBookIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getExternalSheetIndex(String workbookName, String firstSheetName, String lastSheetName) {
|
||||||
|
int externalBookIndex = getExternalWorkbookIndex(workbookName);
|
||||||
|
if (externalBookIndex == -1) {
|
||||||
throw new RuntimeException("No external workbook with name '" + workbookName + "'");
|
throw new RuntimeException("No external workbook with name '" + workbookName + "'");
|
||||||
}
|
}
|
||||||
|
SupBookRecord ebrTarget = _externalBookBlocks[externalBookIndex].getExternalBookRecord();
|
||||||
|
|
||||||
int firstSheetIndex = getSheetIndex(ebrTarget.getSheetNames(), firstSheetName);
|
int firstSheetIndex = getSheetIndex(ebrTarget.getSheetNames(), firstSheetName);
|
||||||
int lastSheetIndex = getSheetIndex(ebrTarget.getSheetNames(), lastSheetName);
|
int lastSheetIndex = getSheetIndex(ebrTarget.getSheetNames(), lastSheetName);
|
||||||
|
|
||||||
|
// Find or add the external sheet record definition for this
|
||||||
int result = _externSheetRecord.getRefIxForSheet(externalBookIndex, firstSheetIndex, lastSheetIndex);
|
int result = _externSheetRecord.getRefIxForSheet(externalBookIndex, firstSheetIndex, lastSheetIndex);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
throw new RuntimeException("ExternSheetRecord does not contain combination ("
|
result = _externSheetRecord.addRef(externalBookIndex, firstSheetIndex, lastSheetIndex);
|
||||||
+ externalBookIndex + ", " + firstSheetIndex + ", " + lastSheetIndex + ")");
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -580,13 +626,7 @@ final class LinkTable {
|
|||||||
// An ExternalBlock for Add-In functions was not found. Create a new one.
|
// An ExternalBlock for Add-In functions was not found. Create a new one.
|
||||||
if (extBlock == null) {
|
if (extBlock == null) {
|
||||||
extBlock = new ExternalBookBlock();
|
extBlock = new ExternalBookBlock();
|
||||||
|
extBlockIndex = extendExternalBookBlocks(extBlock);
|
||||||
ExternalBookBlock[] tmp = new ExternalBookBlock[_externalBookBlocks.length + 1];
|
|
||||||
System.arraycopy(_externalBookBlocks, 0, tmp, 0, _externalBookBlocks.length);
|
|
||||||
tmp[tmp.length - 1] = extBlock;
|
|
||||||
_externalBookBlocks = tmp;
|
|
||||||
|
|
||||||
extBlockIndex = _externalBookBlocks.length - 1;
|
|
||||||
|
|
||||||
// add the created SupBookRecord before ExternSheetRecord
|
// add the created SupBookRecord before ExternSheetRecord
|
||||||
int idx = findFirstRecordLocBySid(ExternSheetRecord.sid);
|
int idx = findFirstRecordLocBySid(ExternSheetRecord.sid);
|
||||||
@ -620,6 +660,14 @@ final class LinkTable {
|
|||||||
int ix = _externSheetRecord.getRefIxForSheet(extBlockIndex, fakeSheetIdx, fakeSheetIdx);
|
int ix = _externSheetRecord.getRefIxForSheet(extBlockIndex, fakeSheetIdx, fakeSheetIdx);
|
||||||
return new NameXPtg(ix, nameIndex);
|
return new NameXPtg(ix, nameIndex);
|
||||||
}
|
}
|
||||||
|
private int extendExternalBookBlocks(ExternalBookBlock newBlock) {
|
||||||
|
ExternalBookBlock[] tmp = new ExternalBookBlock[_externalBookBlocks.length + 1];
|
||||||
|
System.arraycopy(_externalBookBlocks, 0, tmp, 0, _externalBookBlocks.length);
|
||||||
|
tmp[tmp.length - 1] = newBlock;
|
||||||
|
_externalBookBlocks = tmp;
|
||||||
|
|
||||||
|
return (_externalBookBlocks.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
private int findRefIndexFromExtBookIndex(int extBookIndex) {
|
private int findRefIndexFromExtBookIndex(int extBookIndex) {
|
||||||
return _externSheetRecord.findRefIndexFromExtBookIndex(extBookIndex);
|
return _externSheetRecord.findRefIndexFromExtBookIndex(extBookIndex);
|
||||||
|
@ -79,6 +79,7 @@ import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
|
|||||||
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
|
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
|
||||||
import org.apache.poi.ss.formula.udf.UDFFinder;
|
import org.apache.poi.ss.formula.udf.UDFFinder;
|
||||||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
import org.apache.poi.ss.util.CellRangeAddress;
|
import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
import org.apache.poi.ss.util.WorkbookUtil;
|
import org.apache.poi.ss.util.WorkbookUtil;
|
||||||
import org.apache.poi.util.Configurator;
|
import org.apache.poi.util.Configurator;
|
||||||
@ -1850,6 +1851,19 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
|||||||
return storageId;
|
return storageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the LinkTable records required to allow formulas referencing
|
||||||
|
* the specified external workbook to be added to this one. Allows
|
||||||
|
* formulas such as "[MyOtherWorkbook]Sheet3!$A$5" to be added to the
|
||||||
|
* file, for workbooks not already referenced.
|
||||||
|
*
|
||||||
|
* @param name The name the workbook will be referenced as in formulas
|
||||||
|
* @param workbook The open workbook to fetch the link required information from
|
||||||
|
*/
|
||||||
|
public int linkExternalWorkbook(String name, Workbook workbook) {
|
||||||
|
return this.workbook.linkExternalWorkbook(name, workbook);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the workbook protected with a password (not encrypted)?
|
* Is the workbook protected with a password (not encrypted)?
|
||||||
*/
|
*/
|
||||||
|
@ -407,6 +407,22 @@ public interface Workbook extends Closeable {
|
|||||||
*/
|
*/
|
||||||
void removeName(String name);
|
void removeName(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the linking required to allow formulas referencing
|
||||||
|
* the specified external workbook to be added to this one.
|
||||||
|
* <p>In order for formulas such as "[MyOtherWorkbook]Sheet3!$A$5"
|
||||||
|
* to be added to the file, some linking information must first
|
||||||
|
* be recorded. Once a given external workbook has been linked,
|
||||||
|
* then formulas using it can added. Each workbook needs linking
|
||||||
|
* only once.
|
||||||
|
* <p>This linking only applies for writing formulas. To link things
|
||||||
|
* for evaluation, see {@link FormulaEvaluator#setupReferencedWorkbooks(java.util.Map)}
|
||||||
|
*
|
||||||
|
* @param name The name the workbook will be referenced as in formulas
|
||||||
|
* @param workbook The open workbook to fetch the link required information from
|
||||||
|
*/
|
||||||
|
int linkExternalWorkbook(String name, Workbook workbook);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the printarea for the sheet provided
|
* Sets the printarea for the sheet provided
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -1174,6 +1174,20 @@ public class SXSSFWorkbook implements Workbook
|
|||||||
{
|
{
|
||||||
_wb.setSheetHidden(sheetIx,hidden);
|
_wb.setSheetHidden(sheetIx,hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the LinkTable records required to allow formulas referencing
|
||||||
|
* the specified external workbook to be added to this one. Allows
|
||||||
|
* formulas such as "[MyOtherWorkbook]Sheet3!$A$5" to be added to the
|
||||||
|
* file, for workbooks not already referenced.
|
||||||
|
*
|
||||||
|
* @param name The name the workbook will be referenced as in formulas
|
||||||
|
* @param workbook The open workbook to fetch the link required information from
|
||||||
|
*/
|
||||||
|
public int linkExternalWorkbook(String name, Workbook workbook) {
|
||||||
|
throw new RuntimeException("NotImplemented");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a new toolpack in this workbook.
|
* Register a new toolpack in this workbook.
|
||||||
*
|
*
|
||||||
|
@ -1704,6 +1704,18 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
|
|||||||
return mapInfo;
|
return mapInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the LinkTable records required to allow formulas referencing
|
||||||
|
* the specified external workbook to be added to this one. Allows
|
||||||
|
* formulas such as "[MyOtherWorkbook.xlsx]Sheet3!$A$5" to be added to the
|
||||||
|
* file, for workbooks not already referenced.
|
||||||
|
*
|
||||||
|
* @param name The name the workbook will be referenced as in formulas
|
||||||
|
* @param workbook The open workbook to fetch the link required information from
|
||||||
|
*/
|
||||||
|
public int linkExternalWorkbook(String name, Workbook workbook) {
|
||||||
|
throw new RuntimeException("NotImplemented");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a boolean value that indicates whether structure of workbook is locked. <br/>
|
* Specifies a boolean value that indicates whether structure of workbook is locked. <br/>
|
||||||
|
@ -231,13 +231,34 @@ public final class TestHSSFFormulaEvaluator extends BaseTestFormulaEvaluator {
|
|||||||
assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
|
assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
|
||||||
assertEquals(36.90, cell.getNumericCellValue(), 0.0001);
|
assertEquals(36.90, cell.getNumericCellValue(), 0.0001);
|
||||||
|
|
||||||
/*
|
|
||||||
// Now add a formula that refers to yet another (different) workbook
|
|
||||||
cell = wb.getSheetAt(0).getRow(1).createCell(42);
|
|
||||||
cell.setCellFormula("[alt.xls]Sheet1!$A$1");
|
|
||||||
|
|
||||||
// Check it - TODO Is this correct? Or should it become [2]Sheet1!$A$1 ?
|
// Add a formula that refers to one of the existing external workbooks
|
||||||
assertEquals("[alt.xls]Sheet1!$A$1", cell.getCellFormula());
|
cell = wb.getSheetAt(0).getRow(1).createCell(40);
|
||||||
|
cell.setCellFormula("Cost*[XRefCalcData.xls]MarkupSheet!$B$1");
|
||||||
|
|
||||||
|
// Check is was stored correctly
|
||||||
|
assertEquals("Cost*[XRefCalcData.xls]MarkupSheet!$B$1", cell.getCellFormula());
|
||||||
|
|
||||||
|
// Check it evaluates correctly
|
||||||
|
eval.evaluateFormulaCell(cell);
|
||||||
|
assertEquals(24.60*1.8, cell.getNumericCellValue());
|
||||||
|
|
||||||
|
|
||||||
|
// Try to add a formula for a new external workbook, won't be allowed to start
|
||||||
|
try {
|
||||||
|
cell = wb.getSheetAt(0).getRow(1).createCell(42);
|
||||||
|
cell.setCellFormula("[alt.xls]Sheet0!$A$1");
|
||||||
|
fail("New workbook not linked, shouldn't be able to add");
|
||||||
|
} catch(Exception e) {}
|
||||||
|
|
||||||
|
// Link our new workbook
|
||||||
|
HSSFWorkbook alt = new HSSFWorkbook();
|
||||||
|
alt.createSheet().createRow(0).createCell(0).setCellValue("In another workbook");
|
||||||
|
wb.linkExternalWorkbook("alt.xls", alt);
|
||||||
|
|
||||||
|
// Now add a formula that refers to our new workbook
|
||||||
|
cell.setCellFormula("[alt.xls]Sheet0!$A$1");
|
||||||
|
assertEquals("[alt.xls]Sheet0!$A$1", cell.getCellFormula());
|
||||||
|
|
||||||
// Evaluate it, without a link to that workbook
|
// Evaluate it, without a link to that workbook
|
||||||
try {
|
try {
|
||||||
@ -246,8 +267,21 @@ public final class TestHSSFFormulaEvaluator extends BaseTestFormulaEvaluator {
|
|||||||
} catch(Exception e) {}
|
} catch(Exception e) {}
|
||||||
|
|
||||||
// Add a link, check it does
|
// Add a link, check it does
|
||||||
HSSFWorkbook alt = new HSSFWorkbook();
|
HSSFFormulaEvaluator.setupEnvironment(
|
||||||
alt.createSheet().createRow(0).createCell(0).setCellValue("In another workbook");
|
new String[] { "XRefCalc.xls", "XRefCalcData.xls", "alt.xls" },
|
||||||
|
new HSSFFormulaEvaluator[] {
|
||||||
|
eval,
|
||||||
|
new HSSFFormulaEvaluator(wbData),
|
||||||
|
new HSSFFormulaEvaluator(alt)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
eval.evaluateFormulaCell(cell);
|
||||||
|
assertEquals("In another workbook", cell.getStringCellValue());
|
||||||
|
|
||||||
|
|
||||||
|
// Save and re-load
|
||||||
|
wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||||
|
eval = new HSSFFormulaEvaluator(wb);
|
||||||
HSSFFormulaEvaluator.setupEnvironment(
|
HSSFFormulaEvaluator.setupEnvironment(
|
||||||
new String[] { "XRefCalc.xls", "XRefCalcData.xls", "alt.xls" },
|
new String[] { "XRefCalc.xls", "XRefCalcData.xls", "alt.xls" },
|
||||||
new HSSFFormulaEvaluator[] {
|
new HSSFFormulaEvaluator[] {
|
||||||
@ -257,9 +291,17 @@ public final class TestHSSFFormulaEvaluator extends BaseTestFormulaEvaluator {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
eval.evaluate(cell);
|
// Check the one referring to the previously existing workbook behaves
|
||||||
|
cell = wb.getSheetAt(0).getRow(1).getCell(40);
|
||||||
|
assertEquals("Cost*[XRefCalcData.xls]MarkupSheet!$B$1", cell.getCellFormula());
|
||||||
|
eval.evaluateFormulaCell(cell);
|
||||||
|
assertEquals(24.60*1.8, cell.getNumericCellValue());
|
||||||
|
|
||||||
|
// Now check the newly added reference
|
||||||
|
cell = wb.getSheetAt(0).getRow(1).getCell(42);
|
||||||
|
assertEquals("[alt.xls]Sheet0!$A$1", cell.getCellFormula());
|
||||||
|
eval.evaluateFormulaCell(cell);
|
||||||
assertEquals("In another workbook", cell.getStringCellValue());
|
assertEquals("In another workbook", cell.getStringCellValue());
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSharedFormulas(){
|
public void testSharedFormulas(){
|
||||||
|
Loading…
Reference in New Issue
Block a user