This closes #1993, support to set and get pivot table classic layout

- Add new field `ClassicLayout` in the `PivotTableOptions`
- Add a new exported error variable `ErrPivotTableClassicLayout`
- Update unit tests
- Add documentation for the SetDefinedName function, ref #1015
This commit is contained in:
xuri 2024-09-21 15:39:36 +08:00
parent 02189fb016
commit 41c7dd30ce
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
5 changed files with 73 additions and 16 deletions

View File

@ -97,6 +97,8 @@ var (
// ErrPasswordLengthInvalid defined the error message on invalid password // ErrPasswordLengthInvalid defined the error message on invalid password
// length. // length.
ErrPasswordLengthInvalid = errors.New("password length invalid") ErrPasswordLengthInvalid = errors.New("password length invalid")
// ErrPivotTableClassicLayout
ErrPivotTableClassicLayout = errors.New("cannot enable ClassicLayout and CompactData in the same time")
// ErrSave defined the error message for saving file. // ErrSave defined the error message for saving file.
ErrSave = errors.New("no path defined for file, consider File.WriteTo or File.Write") ErrSave = errors.New("no path defined for file, consider File.WriteTo or File.Write")
// ErrSheetIdx defined the error message on receive the invalid worksheet // ErrSheetIdx defined the error message on receive the invalid worksheet

View File

@ -51,6 +51,7 @@ type PivotTableOptions struct {
UseAutoFormatting bool UseAutoFormatting bool
PageOverThenDown bool PageOverThenDown bool
MergeItem bool MergeItem bool
ClassicLayout bool
CompactData bool CompactData bool
ShowError bool ShowError bool
ShowRowHeaders bool ShowRowHeaders bool
@ -220,6 +221,9 @@ func (f *File) parseFormatPivotTableSet(opts *PivotTableOptions) (*xlsxWorksheet
if !ok { if !ok {
return dataSheet, pivotTableSheetPath, ErrSheetNotExist{pivotTableSheetName} return dataSheet, pivotTableSheetPath, ErrSheetNotExist{pivotTableSheetName}
} }
if opts.CompactData && opts.ClassicLayout {
return nil, "", ErrPivotTableClassicLayout
}
return dataSheet, pivotTableSheetPath, err return dataSheet, pivotTableSheetPath, err
} }
@ -352,6 +356,7 @@ func (f *File) addPivotTable(cacheID, pivotTableID int, opts *PivotTableOptions)
MergeItem: &opts.MergeItem, MergeItem: &opts.MergeItem,
CreatedVersion: pivotTableVersion, CreatedVersion: pivotTableVersion,
CompactData: &opts.CompactData, CompactData: &opts.CompactData,
GridDropZones: opts.ClassicLayout,
ShowError: &opts.ShowError, ShowError: &opts.ShowError,
FieldPrintTitles: opts.FieldPrintTitles, FieldPrintTitles: opts.FieldPrintTitles,
ItemPrintTitles: opts.ItemPrintTitles, ItemPrintTitles: opts.ItemPrintTitles,
@ -387,6 +392,12 @@ func (f *File) addPivotTable(cacheID, pivotTableID int, opts *PivotTableOptions)
if pt.Name == "" { if pt.Name == "" {
pt.Name = fmt.Sprintf("PivotTable%d", pivotTableID) pt.Name = fmt.Sprintf("PivotTable%d", pivotTableID)
} }
// set classic layout
if opts.ClassicLayout {
pt.Compact, pt.CompactData = boolPtr(false), boolPtr(false)
}
// pivot fields // pivot fields
_ = f.addPivotFields(&pt, opts) _ = f.addPivotFields(&pt, opts)
@ -537,6 +548,14 @@ func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opts *PivotTableO
return err return err
} }
// setClassicLayout provides a method to set classic layout for pivot table by
// setting Compact and Outline to false.
func (fld *xlsxPivotField) setClassicLayout(classicLayout bool) {
if classicLayout {
fld.Compact, fld.Outline = boolPtr(false), boolPtr(false)
}
}
// 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, opts *PivotTableOptions) error { func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOptions) error {
@ -554,8 +573,7 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOpti
} else { } else {
items = append(items, &xlsxItem{T: "default"}) items = append(items, &xlsxItem{T: "default"})
} }
fld := &xlsxPivotField{
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{
Name: f.getPivotTableFieldName(name, opts.Rows), Name: f.getPivotTableFieldName(name, opts.Rows),
Axis: "axisRow", Axis: "axisRow",
DataField: inPivotTableField(opts.Data, name) != -1, DataField: inPivotTableField(opts.Data, name) != -1,
@ -568,11 +586,13 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOpti
Count: len(items), Count: len(items),
Item: items, Item: items,
}, },
}) }
fld.setClassicLayout(opts.ClassicLayout)
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, fld)
continue continue
} }
if inPivotTableField(opts.Filter, name) != -1 { if inPivotTableField(opts.Filter, name) != -1 {
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{ fld := &xlsxPivotField{
Axis: "axisPage", Axis: "axisPage",
DataField: inPivotTableField(opts.Data, name) != -1, DataField: inPivotTableField(opts.Data, name) != -1,
Name: f.getPivotTableFieldName(name, opts.Columns), Name: f.getPivotTableFieldName(name, opts.Columns),
@ -582,7 +602,9 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOpti
{T: "default"}, {T: "default"},
}, },
}, },
}) }
fld.setClassicLayout(opts.ClassicLayout)
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, fld)
continue continue
} }
if inPivotTableField(opts.Columns, name) != -1 { if inPivotTableField(opts.Columns, name) != -1 {
@ -593,7 +615,7 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOpti
} else { } else {
items = append(items, &xlsxItem{T: "default"}) items = append(items, &xlsxItem{T: "default"})
} }
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{ fld := &xlsxPivotField{
Name: f.getPivotTableFieldName(name, opts.Columns), Name: f.getPivotTableFieldName(name, opts.Columns),
Axis: "axisCol", Axis: "axisCol",
DataField: inPivotTableField(opts.Data, name) != -1, DataField: inPivotTableField(opts.Data, name) != -1,
@ -606,16 +628,22 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOpti
Count: len(items), Count: len(items),
Item: items, Item: items,
}, },
}) }
fld.setClassicLayout(opts.ClassicLayout)
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, fld)
continue continue
} }
if inPivotTableField(opts.Data, name) != -1 { if inPivotTableField(opts.Data, name) != -1 {
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{ fld := &xlsxPivotField{
DataField: true, DataField: true,
}) }
fld.setClassicLayout(opts.ClassicLayout)
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, fld)
continue continue
} }
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{}) fld := &xlsxPivotField{}
fld.setClassicLayout(opts.ClassicLayout)
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, fld)
} }
return err return err
} }
@ -847,6 +875,7 @@ func (f *File) getPivotTable(sheet, pivotTableXML, pivotCacheRels string) (Pivot
DataRange: fmt.Sprintf("%s!%s", pc.CacheSource.WorksheetSource.Sheet, pc.CacheSource.WorksheetSource.Ref), DataRange: fmt.Sprintf("%s!%s", pc.CacheSource.WorksheetSource.Sheet, pc.CacheSource.WorksheetSource.Ref),
PivotTableRange: fmt.Sprintf("%s!%s", sheet, pt.Location.Ref), PivotTableRange: fmt.Sprintf("%s!%s", sheet, pt.Location.Ref),
Name: pt.Name, Name: pt.Name,
ClassicLayout: pt.GridDropZones,
FieldPrintTitles: pt.FieldPrintTitles, FieldPrintTitles: pt.FieldPrintTitles,
ItemPrintTitles: pt.ItemPrintTitles, ItemPrintTitles: pt.ItemPrintTitles,
} }

View File

@ -38,12 +38,13 @@ func TestPivotTable(t *testing.T) {
RowGrandTotals: true, RowGrandTotals: true,
ColGrandTotals: true, ColGrandTotals: true,
ShowDrill: true, ShowDrill: true,
ClassicLayout: true,
ShowError: true,
ShowRowHeaders: true, ShowRowHeaders: true,
ShowColHeaders: true, ShowColHeaders: true,
ShowLastColumn: true, ShowLastColumn: true,
ShowError: true,
ItemPrintTitles: true,
FieldPrintTitles: true, FieldPrintTitles: true,
ItemPrintTitles: true,
PivotTableStyleName: "PivotStyleLight16", PivotTableStyleName: "PivotStyleLight16",
} }
assert.NoError(t, f.AddPivotTable(expected)) assert.NoError(t, f.AddPivotTable(expected))
@ -265,18 +266,25 @@ func TestPivotTable(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
// Test add pivot table with invalid sheet name // Test add pivot table with invalid sheet name
assert.EqualError(t, f.AddPivotTable(&PivotTableOptions{ assert.Error(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet:1!A1:E31", DataRange: "Sheet:1!A1:E31",
PivotTableRange: "Sheet:1!G2:M34", PivotTableRange: "Sheet:1!G2:M34",
Rows: []PivotTableField{{Data: "Year"}}, Rows: []PivotTableField{{Data: "Year"}},
}), ErrSheetNameInvalid.Error()) }), ErrSheetNameInvalid)
// Test add pivot table with enable ClassicLayout and CompactData in the same time
assert.Error(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!A1:E31",
PivotTableRange: "Sheet1!G2:M34",
CompactData: true,
ClassicLayout: true,
}), ErrPivotTableClassicLayout)
// Test delete pivot table with not exists worksheet // Test delete pivot table with not exists worksheet
assert.EqualError(t, f.DeletePivotTable("SheetN", "PivotTable1"), "sheet SheetN does not exist") assert.EqualError(t, f.DeletePivotTable("SheetN", "PivotTable1"), "sheet SheetN does not exist")
// Test delete pivot table with not exists pivot table name // Test delete pivot table with not exists pivot table name
assert.EqualError(t, f.DeletePivotTable("Sheet1", "PivotTableN"), "table PivotTableN does not exist") assert.EqualError(t, f.DeletePivotTable("Sheet1", "PivotTableN"), "table PivotTableN does not exist")
// Test adjust range with invalid range // Test adjust range with invalid range
_, _, err = f.adjustRange("") _, _, err = f.adjustRange("")
assert.EqualError(t, err, ErrParameterRequired.Error()) assert.Error(t, err, ErrParameterRequired)
// Test adjust range with incorrect range // Test adjust range with incorrect range
_, _, err = f.adjustRange("sheet1!") _, _, err = f.adjustRange("sheet1!")
assert.EqualError(t, err, "parameter is invalid") assert.EqualError(t, err, "parameter is invalid")

View File

@ -1657,6 +1657,24 @@ func (f *File) GetPageLayout(sheet string) (PageLayoutOptions, error) {
// Comment: "defined name comment", // Comment: "defined name comment",
// Scope: "Sheet2", // Scope: "Sheet2",
// }) // })
//
// If you fill the RefersTo property with only one columns range without a
// comma, it will work as "Columns to repeat at left" only. For example:
//
// err := f.SetDefinedName(&excelize.DefinedName{
// Name: "_xlnm.Print_Titles",
// RefersTo: "Sheet1!$A:$A",
// Scope: "Sheet1",
// })
//
// If you fill the RefersTo property with only one rows range without a comma,
// it will work as "Rows to repeat at top" only. For example:
//
// err := f.SetDefinedName(&excelize.DefinedName{
// Name: "_xlnm.Print_Titles",
// RefersTo: "Sheet1!$1:$1",
// Scope: "Sheet1",
// })
func (f *File) SetDefinedName(definedName *DefinedName) error { func (f *File) SetDefinedName(definedName *DefinedName) error {
if definedName.Name == "" || definedName.RefersTo == "" { if definedName.Name == "" || definedName.RefersTo == "" {
return ErrParameterInvalid return ErrParameterInvalid