332 lines
12 KiB
Java
332 lines
12 KiB
Java
/* ====================================================================
|
|
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.xssf.usermodel;
|
|
|
|
import org.apache.poi.hssf.record.formula.Ptg;
|
|
import org.apache.poi.ss.formula.FormulaParser;
|
|
import org.apache.poi.ss.formula.FormulaType;
|
|
import org.apache.poi.ss.usermodel.Name;
|
|
import org.apache.poi.ss.util.AreaReference;
|
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
|
|
|
|
/**
|
|
* Represents a defined named range in a SpreadsheetML workbook.
|
|
* <p>
|
|
* Defined names are descriptive text that is used to represents a cell, range of cells, formula, or constant value.
|
|
* Use easy-to-understand names, such as Products, to refer to hard to understand ranges, such as <code>Sales!C20:C30</code>.
|
|
* </p>
|
|
* Example:
|
|
* <pre><blockquote>
|
|
* XSSFWorkbook wb = new XSSFWorkbook();
|
|
* XSSFSheet sh = wb.createSheet("Sheet1");
|
|
*
|
|
* //applies to the entire workbook
|
|
* XSSFName name1 = wb.createName();
|
|
* name1.setNameName("FMLA");
|
|
* name1.setRefersToFormula("Sheet1!$B$3");
|
|
*
|
|
* //applies to Sheet1
|
|
* XSSFName name2 = wb.createName();
|
|
* name2.setNameName("SheetLevelName");
|
|
* name2.setComment("This name is scoped to Sheet1");
|
|
* name2.setLocalSheetId(0);
|
|
* name2.setRefersToFormula("Sheet1!$B$3");
|
|
*
|
|
* </blockquote></pre>
|
|
*
|
|
* @author Nick Burch
|
|
* @author Yegor Kozlov
|
|
*/
|
|
public final class XSSFName implements Name {
|
|
|
|
/**
|
|
* A built-in defined name that specifies the workbook's print area
|
|
*/
|
|
public final static String BUILTIN_PRINT_AREA = "_xlnm.Print_Area";
|
|
|
|
/**
|
|
* A built-in defined name that specifies the row(s) or column(s) to repeat
|
|
* at the top of each printed page.
|
|
*/
|
|
public final static String BUILTIN_PRINT_TITLE = "_xlnm.Print_Titles";
|
|
|
|
/**
|
|
* A built-in defined name that refers to a range containing the criteria values
|
|
* to be used in applying an advanced filter to a range of data
|
|
*/
|
|
public final static String BUILTIN_CRITERIA = "_xlnm.Criteria:";
|
|
|
|
|
|
/**
|
|
* this defined name refers to the range containing the filtered
|
|
* output values resulting from applying an advanced filter criteria to a source
|
|
* range
|
|
*/
|
|
public final static String BUILTIN_EXTRACT = "_xlnm.Extract:";
|
|
|
|
/**
|
|
* ?an be one of the following
|
|
* <li> this defined name refers to a range to which an advanced filter has been
|
|
* applied. This represents the source data range, unfiltered.
|
|
* <li> This defined name refers to a range to which an AutoFilter has been
|
|
* applied
|
|
*/
|
|
public final static String BUILTIN_FILTER_DB = "_xlnm._FilterDatabase:";
|
|
|
|
/**
|
|
* A built-in defined name that refers to a consolidation area
|
|
*/
|
|
public final static String BUILTIN_CONSOLIDATE_AREA = "_xlnm.Consolidate_Area";
|
|
|
|
/**
|
|
* A built-in defined name that specified that the range specified is from a database data source
|
|
*/
|
|
public final static String BUILTIN_DATABASE = "_xlnm.Database";
|
|
|
|
/**
|
|
* A built-in defined name that refers to a sheet title.
|
|
*/
|
|
public final static String BUILTIN_SHEET_TITLE = "_xlnm.Sheet_Title";
|
|
|
|
private XSSFWorkbook workbook;
|
|
private CTDefinedName ctName;
|
|
|
|
/**
|
|
* Creates an XSSFName object - called internally by XSSFWorkbook.
|
|
*
|
|
* @param name - the xml bean that holds data represenring this defined name.
|
|
* @param workbook - the workbook object associated with the name
|
|
* @see org.apache.poi.xssf.usermodel.XSSFWorkbook#createName()
|
|
*/
|
|
protected XSSFName(CTDefinedName name, XSSFWorkbook workbook) {
|
|
this.workbook = workbook;
|
|
this.ctName = name;
|
|
}
|
|
|
|
/**
|
|
* Returns the underlying named range object
|
|
*/
|
|
protected CTDefinedName getCTName() {
|
|
return ctName;
|
|
}
|
|
|
|
/**
|
|
* Returns the name that will appear in the user interface for the defined name.
|
|
*
|
|
* @return text name of this defined name
|
|
*/
|
|
public String getNameName() {
|
|
return ctName.getName();
|
|
}
|
|
|
|
/**
|
|
* Sets the name that will appear in the user interface for the defined name.
|
|
* Names must begin with a letter or underscore, not contain spaces and be unique across the workbook.
|
|
*
|
|
* @param name name of this defined name
|
|
* @throws IllegalArgumentException if the name is invalid or the workbook already contains this name (case-insensitive)
|
|
*/
|
|
public void setNameName(String name) {
|
|
validateName(name);
|
|
|
|
//Check to ensure no other names have the same case-insensitive name
|
|
for (int i = 0; i < workbook.getNumberOfNames(); i++) {
|
|
XSSFName nm = workbook.getNameAt(i);
|
|
if (nm != this && nm.getNameName().equalsIgnoreCase(name)) {
|
|
throw new IllegalArgumentException("The workbook already contains this name: " + name);
|
|
}
|
|
}
|
|
ctName.setName(name);
|
|
}
|
|
|
|
/**
|
|
* Returns the reference of this named range, such as Sales!C20:C30.
|
|
*
|
|
* @return the reference of this named range
|
|
*/
|
|
public String getRefersToFormula() {
|
|
return ctName.getStringValue();
|
|
}
|
|
|
|
/**
|
|
* Sets the reference of this named range, such as Sales!C20:C30.
|
|
*
|
|
* @param formulaText the reference to set
|
|
* @throws IllegalArgumentException if the specified reference is unparsable
|
|
*/
|
|
public void setRefersToFormula(String formulaText) {
|
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(workbook);
|
|
Ptg[] ptgs;
|
|
try {
|
|
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 + "'", e);
|
|
}
|
|
throw e;
|
|
}
|
|
ctName.setStringValue(formulaText);
|
|
}
|
|
|
|
/**
|
|
* Tests if this name points to a cell that no longer exists
|
|
*
|
|
* @return true if the name refers to a deleted cell, false otherwise
|
|
*/
|
|
public boolean isDeleted(){
|
|
String ref = getRefersToFormula();
|
|
return ref != null && ref.indexOf("#REF!") != -1;
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
public void setLocalSheetId(int sheetId) {
|
|
if(sheetId == -1) ctName.unsetLocalSheetId();
|
|
else ctName.setLocalSheetId(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 getLocalSheetId() {
|
|
return ctName.isSetLocalSheetId() ? (int) ctName.getLocalSheetId() : -1;
|
|
}
|
|
|
|
/**
|
|
* Indicates that the defined name refers to a user-defined function.
|
|
* This attribute is used when there is an add-in or other code project associated with the file.
|
|
*
|
|
* @param value <code>true</code> indicates the name refers to a function.
|
|
*/
|
|
public void setFunction(boolean value) {
|
|
ctName.setFunction(value);
|
|
}
|
|
|
|
/**
|
|
* Indicates that the defined name refers to a user-defined function.
|
|
* This attribute is used when there is an add-in or other code project associated with the file.
|
|
*
|
|
* @return <code>true</code> indicates the name refers to a function.
|
|
*/
|
|
public boolean getFunction() {
|
|
return ctName.getFunction();
|
|
}
|
|
|
|
/**
|
|
* Specifies the function group index if the defined name refers to a function. The function
|
|
* group defines the general category for the function. This attribute is used when there is
|
|
* an add-in or other code project associated with the file.
|
|
*
|
|
* @param functionGroupId the function group index that defines the general category for the function
|
|
*/
|
|
public void setFunctionGroupId(int functionGroupId) {
|
|
ctName.setFunctionGroupId(functionGroupId);
|
|
}
|
|
|
|
/**
|
|
* Returns the function group index if the defined name refers to a function. The function
|
|
* group defines the general category for the function. This attribute is used when there is
|
|
* an add-in or other code project associated with the file.
|
|
*
|
|
* @return the function group index that defines the general category for the function
|
|
*/
|
|
public int getFunctionGroupId() {
|
|
return (int) ctName.getFunctionGroupId();
|
|
}
|
|
|
|
/**
|
|
* Get the sheets name which this named range is referenced to
|
|
*
|
|
* @return sheet name, which this named range referred to.
|
|
* Empty string if the referenced sheet name weas not found.
|
|
*/
|
|
public String getSheetName() {
|
|
if (ctName.isSetLocalSheetId()) {
|
|
// Given as explicit sheet id
|
|
int sheetId = (int)ctName.getLocalSheetId();
|
|
return workbook.getSheetName(sheetId);
|
|
} else {
|
|
String ref = getRefersToFormula();
|
|
AreaReference areaRef = new AreaReference(ref);
|
|
return areaRef.getFirstCell().getSheetName();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Is the name refers to a user-defined function ?
|
|
*
|
|
* @return <code>true</code> if this name refers to a user-defined function
|
|
*/
|
|
public boolean isFunctionName() {
|
|
return getFunction();
|
|
}
|
|
|
|
/**
|
|
* Returns the comment the user provided when the name was created.
|
|
*
|
|
* @return the user comment for this named range
|
|
*/
|
|
public String getComment() {
|
|
return ctName.getComment();
|
|
}
|
|
|
|
/**
|
|
* Specifies the comment the user provided when the name was created.
|
|
*
|
|
* @param comment the user comment for this named range
|
|
*/
|
|
public void setComment(String comment) {
|
|
ctName.setComment(comment);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return ctName.toString().hashCode();
|
|
}
|
|
|
|
/**
|
|
* Compares this name to the specified object.
|
|
* The result is <code>true</code> if the argument is XSSFName and the
|
|
* underlying CTDefinedName bean equals to the CTDefinedName representing this name
|
|
*
|
|
* @param o the object to compare this <code>XSSFName</code> against.
|
|
* @return <code>true</code> if the <code>XSSFName </code>are equal;
|
|
* <code>false</code> otherwise.
|
|
*/
|
|
@Override
|
|
public boolean equals(Object o) {
|
|
if(o == this) return true;
|
|
|
|
if (!(o instanceof XSSFName)) return false;
|
|
|
|
XSSFName cf = (XSSFName) o;
|
|
return ctName.toString().equals(cf.getCTName().toString());
|
|
}
|
|
|
|
private static void validateName(String name){
|
|
char c = name.charAt(0);
|
|
if(!(c == '_' || Character.isLetter(c)) || name.indexOf(' ') != -1) {
|
|
throw new IllegalArgumentException("Invalid name: '"+name+"'; Names must begin with a letter or underscore and not contain spaces");
|
|
}
|
|
}
|
|
}
|