This closes #866, support use the defined name to reference the data range in pivot table options
- Fix incorrect scope when getting defined name - Update docs: use column number instead of index on get column width
This commit is contained in:
parent
24967a5c25
commit
f27624acdd
13
calc.go
13
calc.go
|
@ -955,16 +955,23 @@ func isOperatorPrefixToken(token efp.Token) bool {
|
||||||
|
|
||||||
// getDefinedNameRefTo convert defined name to reference range.
|
// getDefinedNameRefTo convert defined name to reference range.
|
||||||
func (f *File) getDefinedNameRefTo(definedNameName string, currentSheet string) (refTo string) {
|
func (f *File) getDefinedNameRefTo(definedNameName string, currentSheet string) (refTo string) {
|
||||||
|
var workbookRefTo, worksheetRefTo string
|
||||||
for _, definedName := range f.GetDefinedName() {
|
for _, definedName := range f.GetDefinedName() {
|
||||||
if definedName.Name == definedNameName {
|
if definedName.Name == definedNameName {
|
||||||
refTo = definedName.RefersTo
|
|
||||||
// worksheet scope takes precedence over scope workbook when both definedNames exist
|
// worksheet scope takes precedence over scope workbook when both definedNames exist
|
||||||
|
if definedName.Scope == "Workbook" {
|
||||||
|
workbookRefTo = definedName.RefersTo
|
||||||
|
}
|
||||||
if definedName.Scope == currentSheet {
|
if definedName.Scope == currentSheet {
|
||||||
break
|
worksheetRefTo = definedName.RefersTo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return refTo
|
refTo = workbookRefTo
|
||||||
|
if worksheetRefTo != "" {
|
||||||
|
refTo = worksheetRefTo
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseToken parse basic arithmetic operator priority and evaluate based on
|
// parseToken parse basic arithmetic operator priority and evaluate based on
|
||||||
|
|
4
col.go
4
col.go
|
@ -604,7 +604,7 @@ func (f *File) positionObjectPixels(sheet string, col, row, x1, y1, width, heigh
|
||||||
}
|
}
|
||||||
|
|
||||||
// getColWidth provides a function to get column width in pixels by given
|
// getColWidth provides a function to get column width in pixels by given
|
||||||
// sheet name and column index.
|
// sheet name and column number.
|
||||||
func (f *File) getColWidth(sheet string, col int) int {
|
func (f *File) getColWidth(sheet string, col int) int {
|
||||||
xlsx, _ := f.workSheetReader(sheet)
|
xlsx, _ := f.workSheetReader(sheet)
|
||||||
if xlsx.Cols != nil {
|
if xlsx.Cols != nil {
|
||||||
|
@ -623,7 +623,7 @@ func (f *File) getColWidth(sheet string, col int) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetColWidth provides a function to get column width by given worksheet name
|
// GetColWidth provides a function to get column width by given worksheet name
|
||||||
// and column index.
|
// and column name.
|
||||||
func (f *File) GetColWidth(sheet, col string) (float64, error) {
|
func (f *File) GetColWidth(sheet, col string) (float64, error) {
|
||||||
colNum, err := ColumnNameToNumber(col)
|
colNum, err := ColumnNameToNumber(col)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
|
|
||||||
// PivotTableOption directly maps the format settings of the pivot table.
|
// PivotTableOption directly maps the format settings of the pivot table.
|
||||||
type PivotTableOption struct {
|
type PivotTableOption struct {
|
||||||
|
pivotTableSheetName string
|
||||||
DataRange string
|
DataRange string
|
||||||
PivotTableRange string
|
PivotTableRange string
|
||||||
Rows []PivotTableField
|
Rows []PivotTableField
|
||||||
|
@ -164,14 +165,19 @@ func (f *File) parseFormatPivotTableSet(opt *PivotTableOption) (*xlsxWorksheet,
|
||||||
if opt == nil {
|
if opt == nil {
|
||||||
return nil, "", errors.New("parameter is required")
|
return nil, "", errors.New("parameter is required")
|
||||||
}
|
}
|
||||||
dataSheetName, _, err := f.adjustRange(opt.DataRange)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
|
|
||||||
}
|
|
||||||
pivotTableSheetName, _, err := f.adjustRange(opt.PivotTableRange)
|
pivotTableSheetName, _, err := f.adjustRange(opt.PivotTableRange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", fmt.Errorf("parameter 'PivotTableRange' parsing error: %s", err.Error())
|
return nil, "", fmt.Errorf("parameter 'PivotTableRange' parsing error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
opt.pivotTableSheetName = pivotTableSheetName
|
||||||
|
dataRange := f.getDefinedNameRefTo(opt.DataRange, pivotTableSheetName)
|
||||||
|
if dataRange == "" {
|
||||||
|
dataRange = opt.DataRange
|
||||||
|
}
|
||||||
|
dataSheetName, _, err := f.adjustRange(dataRange)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
|
||||||
|
}
|
||||||
dataSheet, err := f.workSheetReader(dataSheetName)
|
dataSheet, err := f.workSheetReader(dataSheetName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dataSheet, "", err
|
return dataSheet, "", err
|
||||||
|
@ -215,8 +221,12 @@ func (f *File) adjustRange(rangeStr string) (string, []int, error) {
|
||||||
|
|
||||||
// getPivotFieldsOrder provides a function to get order list of pivot table
|
// getPivotFieldsOrder provides a function to get order list of pivot table
|
||||||
// fields.
|
// fields.
|
||||||
func (f *File) getPivotFieldsOrder(dataRange string) ([]string, error) {
|
func (f *File) getPivotFieldsOrder(opt *PivotTableOption) ([]string, error) {
|
||||||
order := []string{}
|
order := []string{}
|
||||||
|
dataRange := f.getDefinedNameRefTo(opt.DataRange, opt.pivotTableSheetName)
|
||||||
|
if dataRange == "" {
|
||||||
|
dataRange = opt.DataRange
|
||||||
|
}
|
||||||
dataSheet, coordinates, err := f.adjustRange(dataRange)
|
dataSheet, coordinates, err := f.adjustRange(dataRange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return order, fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
|
return order, fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
|
||||||
|
@ -235,12 +245,18 @@ func (f *File) getPivotFieldsOrder(dataRange string) ([]string, error) {
|
||||||
// addPivotCache provides a function to create a pivot cache by given properties.
|
// addPivotCache provides a function to create a pivot cache by given properties.
|
||||||
func (f *File) addPivotCache(pivotCacheID int, pivotCacheXML string, opt *PivotTableOption, ws *xlsxWorksheet) error {
|
func (f *File) addPivotCache(pivotCacheID int, pivotCacheXML string, opt *PivotTableOption, ws *xlsxWorksheet) error {
|
||||||
// validate data range
|
// validate data range
|
||||||
dataSheet, coordinates, err := f.adjustRange(opt.DataRange)
|
definedNameRef := true
|
||||||
|
dataRange := f.getDefinedNameRefTo(opt.DataRange, opt.pivotTableSheetName)
|
||||||
|
if dataRange == "" {
|
||||||
|
definedNameRef = false
|
||||||
|
dataRange = opt.DataRange
|
||||||
|
}
|
||||||
|
dataSheet, coordinates, err := f.adjustRange(dataRange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
|
return fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
|
||||||
}
|
}
|
||||||
// data range has been checked
|
// data range has been checked
|
||||||
order, _ := f.getPivotFieldsOrder(opt.DataRange)
|
order, _ := f.getPivotFieldsOrder(opt)
|
||||||
hcell, _ := CoordinatesToCellName(coordinates[0], coordinates[1])
|
hcell, _ := CoordinatesToCellName(coordinates[0], coordinates[1])
|
||||||
vcell, _ := CoordinatesToCellName(coordinates[2], coordinates[3])
|
vcell, _ := CoordinatesToCellName(coordinates[2], coordinates[3])
|
||||||
pc := xlsxPivotCacheDefinition{
|
pc := xlsxPivotCacheDefinition{
|
||||||
|
@ -258,7 +274,9 @@ func (f *File) addPivotCache(pivotCacheID int, pivotCacheXML string, opt *PivotT
|
||||||
},
|
},
|
||||||
CacheFields: &xlsxCacheFields{},
|
CacheFields: &xlsxCacheFields{},
|
||||||
}
|
}
|
||||||
|
if definedNameRef {
|
||||||
|
pc.CacheSource.WorksheetSource = &xlsxWorksheetSource{Name: opt.DataRange}
|
||||||
|
}
|
||||||
for _, name := range order {
|
for _, name := range order {
|
||||||
defaultRowsSubtotal, rowOk := f.getPivotTableFieldNameDefaultSubtotal(name, opt.Rows)
|
defaultRowsSubtotal, rowOk := f.getPivotTableFieldNameDefaultSubtotal(name, opt.Rows)
|
||||||
defaultColumnsSubtotal, colOk := f.getPivotTableFieldNameDefaultSubtotal(name, opt.Columns)
|
defaultColumnsSubtotal, colOk := f.getPivotTableFieldNameDefaultSubtotal(name, opt.Columns)
|
||||||
|
@ -509,7 +527,7 @@ func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opt *PivotTableOp
|
||||||
// addPivotFields create pivot fields based on the column order of the first
|
// addPivotFields create pivot fields based on the column order of the first
|
||||||
// row in the data region by given pivot table definition and option.
|
// row in the data region by given pivot table definition and option.
|
||||||
func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opt *PivotTableOption) error {
|
func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opt *PivotTableOption) error {
|
||||||
order, err := f.getPivotFieldsOrder(opt.DataRange)
|
order, err := f.getPivotFieldsOrder(opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -606,7 +624,7 @@ func (f *File) countPivotCache() int {
|
||||||
// to a sequential index by given fields and pivot option.
|
// to a sequential index by given fields and pivot option.
|
||||||
func (f *File) getPivotFieldsIndex(fields []PivotTableField, opt *PivotTableOption) ([]int, error) {
|
func (f *File) getPivotFieldsIndex(fields []PivotTableField, opt *PivotTableOption) ([]int, error) {
|
||||||
pivotFieldsIndex := []int{}
|
pivotFieldsIndex := []int{}
|
||||||
orders, err := f.getPivotFieldsOrder(opt.DataRange)
|
orders, err := f.getPivotFieldsOrder(opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pivotFieldsIndex, err
|
return pivotFieldsIndex, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,10 +136,16 @@ func TestAddPivotTable(t *testing.T) {
|
||||||
ShowColHeaders: true,
|
ShowColHeaders: true,
|
||||||
ShowLastColumn: true,
|
ShowLastColumn: true,
|
||||||
}))
|
}))
|
||||||
//Test Pivot table with many data, many rows, many cols
|
// Create pivot table with many data, many rows, many cols and defined name
|
||||||
|
f.SetDefinedName(&DefinedName{
|
||||||
|
Name: "dataRange",
|
||||||
|
RefersTo: "Sheet1!$A$1:$E$31",
|
||||||
|
Comment: "Pivot Table Data Range",
|
||||||
|
Scope: "Sheet2",
|
||||||
|
})
|
||||||
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
|
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
|
||||||
DataRange: "Sheet1!$A$1:$E$31",
|
DataRange: "dataRange",
|
||||||
PivotTableRange: "Sheet2!$A$56:$AG$90",
|
PivotTableRange: "Sheet2!$A$57:$AJ$91",
|
||||||
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
|
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
|
||||||
Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Type"}},
|
Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Type"}},
|
||||||
Data: []PivotTableField{{Data: "Sales", Subtotal: "Sum", Name: "Sum of Sales"}, {Data: "Sales", Subtotal: "Average", Name: "Average of Sales"}},
|
Data: []PivotTableField{{Data: "Sales", Subtotal: "Sum", Name: "Sum of Sales"}, {Data: "Sales", Subtotal: "Average", Name: "Average of Sales"}},
|
||||||
|
@ -223,7 +229,7 @@ func TestAddPivotTable(t *testing.T) {
|
||||||
_, _, err := f.adjustRange("")
|
_, _, err := f.adjustRange("")
|
||||||
assert.EqualError(t, err, "parameter is required")
|
assert.EqualError(t, err, "parameter is required")
|
||||||
// Test get pivot fields order with empty data range
|
// Test get pivot fields order with empty data range
|
||||||
_, err = f.getPivotFieldsOrder("")
|
_, err = f.getPivotFieldsOrder(&PivotTableOption{})
|
||||||
assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
|
assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
|
||||||
// Test add pivot cache with empty data range
|
// Test add pivot cache with empty data range
|
||||||
assert.EqualError(t, f.addPivotCache(0, "", &PivotTableOption{}, nil), "parameter 'DataRange' parsing error: parameter is required")
|
assert.EqualError(t, f.addPivotCache(0, "", &PivotTableOption{}, nil), "parameter 'DataRange' parsing error: parameter is required")
|
||||||
|
@ -288,7 +294,7 @@ func TestAddPivotColFields(t *testing.T) {
|
||||||
func TestGetPivotFieldsOrder(t *testing.T) {
|
func TestGetPivotFieldsOrder(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
// Test get pivot fields order with not exist worksheet
|
// Test get pivot fields order with not exist worksheet
|
||||||
_, err := f.getPivotFieldsOrder("SheetN!$A$1:$E$31")
|
_, err := f.getPivotFieldsOrder(&PivotTableOption{DataRange: "SheetN!$A$1:$E$31"})
|
||||||
assert.EqualError(t, err, "sheet SheetN is not exist")
|
assert.EqualError(t, err, "sheet SheetN is not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue