From 41c7dd30ce7efe4771624994918afa9cde6cbfd4 Mon Sep 17 00:00:00 2001 From: xuri Date: Sat, 21 Sep 2024 15:39:36 +0800 Subject: [PATCH] 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 --- calc_test.go | 2 +- errors.go | 2 ++ pivotTable.go | 49 ++++++++++++++++++++++++++++++++++++---------- pivotTable_test.go | 18 ++++++++++++----- sheet.go | 18 +++++++++++++++++ 5 files changed, 73 insertions(+), 16 deletions(-) diff --git a/calc_test.go b/calc_test.go index c2ae332..fc28a05 100644 --- a/calc_test.go +++ b/calc_test.go @@ -2126,7 +2126,7 @@ func TestCalcCellValue(t *testing.T) { "=DOLLAR(1234.56,-2)": "$1,200", "=DOLLAR(1234.56,-3)": "$1,000", "=DOLLAR(-1234.56,3)": "($1,234.560)", - "=DOLLAR(-1234.56,-3)": "($1,000)", + "=DOLLAR(-1234.56,-3)": "($1,000)", // DOLLARDE "=DOLLARDE(1.01,16)": "1.0625", // DOLLARFR diff --git a/errors.go b/errors.go index b12b06c..dc58b42 100644 --- a/errors.go +++ b/errors.go @@ -97,6 +97,8 @@ var ( // ErrPasswordLengthInvalid defined the error message on invalid password // length. 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 = errors.New("no path defined for file, consider File.WriteTo or File.Write") // ErrSheetIdx defined the error message on receive the invalid worksheet diff --git a/pivotTable.go b/pivotTable.go index 9caf037..03475c0 100644 --- a/pivotTable.go +++ b/pivotTable.go @@ -51,6 +51,7 @@ type PivotTableOptions struct { UseAutoFormatting bool PageOverThenDown bool MergeItem bool + ClassicLayout bool CompactData bool ShowError bool ShowRowHeaders bool @@ -220,6 +221,9 @@ func (f *File) parseFormatPivotTableSet(opts *PivotTableOptions) (*xlsxWorksheet if !ok { return dataSheet, pivotTableSheetPath, ErrSheetNotExist{pivotTableSheetName} } + if opts.CompactData && opts.ClassicLayout { + return nil, "", ErrPivotTableClassicLayout + } return dataSheet, pivotTableSheetPath, err } @@ -352,6 +356,7 @@ func (f *File) addPivotTable(cacheID, pivotTableID int, opts *PivotTableOptions) MergeItem: &opts.MergeItem, CreatedVersion: pivotTableVersion, CompactData: &opts.CompactData, + GridDropZones: opts.ClassicLayout, ShowError: &opts.ShowError, FieldPrintTitles: opts.FieldPrintTitles, ItemPrintTitles: opts.ItemPrintTitles, @@ -387,6 +392,12 @@ func (f *File) addPivotTable(cacheID, pivotTableID int, opts *PivotTableOptions) if pt.Name == "" { pt.Name = fmt.Sprintf("PivotTable%d", pivotTableID) } + + // set classic layout + if opts.ClassicLayout { + pt.Compact, pt.CompactData = boolPtr(false), boolPtr(false) + } + // pivot fields _ = f.addPivotFields(&pt, opts) @@ -537,6 +548,14 @@ func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opts *PivotTableO 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 // row in the data region by given pivot table definition and option. func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOptions) error { @@ -554,8 +573,7 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOpti } else { items = append(items, &xlsxItem{T: "default"}) } - - pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{ + fld := &xlsxPivotField{ Name: f.getPivotTableFieldName(name, opts.Rows), Axis: "axisRow", DataField: inPivotTableField(opts.Data, name) != -1, @@ -568,11 +586,13 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOpti Count: len(items), Item: items, }, - }) + } + fld.setClassicLayout(opts.ClassicLayout) + pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, fld) continue } if inPivotTableField(opts.Filter, name) != -1 { - pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{ + fld := &xlsxPivotField{ Axis: "axisPage", DataField: inPivotTableField(opts.Data, name) != -1, Name: f.getPivotTableFieldName(name, opts.Columns), @@ -582,7 +602,9 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOpti {T: "default"}, }, }, - }) + } + fld.setClassicLayout(opts.ClassicLayout) + pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, fld) continue } if inPivotTableField(opts.Columns, name) != -1 { @@ -593,7 +615,7 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOpti } else { items = append(items, &xlsxItem{T: "default"}) } - pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{ + fld := &xlsxPivotField{ Name: f.getPivotTableFieldName(name, opts.Columns), Axis: "axisCol", DataField: inPivotTableField(opts.Data, name) != -1, @@ -606,16 +628,22 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOpti Count: len(items), Item: items, }, - }) + } + fld.setClassicLayout(opts.ClassicLayout) + pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, fld) continue } if inPivotTableField(opts.Data, name) != -1 { - pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{ + fld := &xlsxPivotField{ DataField: true, - }) + } + fld.setClassicLayout(opts.ClassicLayout) + pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, fld) 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 } @@ -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), PivotTableRange: fmt.Sprintf("%s!%s", sheet, pt.Location.Ref), Name: pt.Name, + ClassicLayout: pt.GridDropZones, FieldPrintTitles: pt.FieldPrintTitles, ItemPrintTitles: pt.ItemPrintTitles, } diff --git a/pivotTable_test.go b/pivotTable_test.go index 74ce61b..20528cc 100644 --- a/pivotTable_test.go +++ b/pivotTable_test.go @@ -38,12 +38,13 @@ func TestPivotTable(t *testing.T) { RowGrandTotals: true, ColGrandTotals: true, ShowDrill: true, + ClassicLayout: true, + ShowError: true, ShowRowHeaders: true, ShowColHeaders: true, ShowLastColumn: true, - ShowError: true, - ItemPrintTitles: true, FieldPrintTitles: true, + ItemPrintTitles: true, PivotTableStyleName: "PivotStyleLight16", } assert.NoError(t, f.AddPivotTable(expected)) @@ -265,18 +266,25 @@ func TestPivotTable(t *testing.T) { assert.NoError(t, err) // 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", PivotTableRange: "Sheet:1!G2:M34", 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 assert.EqualError(t, f.DeletePivotTable("SheetN", "PivotTable1"), "sheet SheetN does not exist") // Test delete pivot table with not exists pivot table name assert.EqualError(t, f.DeletePivotTable("Sheet1", "PivotTableN"), "table PivotTableN does not exist") // Test adjust range with invalid range _, _, err = f.adjustRange("") - assert.EqualError(t, err, ErrParameterRequired.Error()) + assert.Error(t, err, ErrParameterRequired) // Test adjust range with incorrect range _, _, err = f.adjustRange("sheet1!") assert.EqualError(t, err, "parameter is invalid") diff --git a/sheet.go b/sheet.go index ee66b90..7cb13e2 100644 --- a/sheet.go +++ b/sheet.go @@ -1657,6 +1657,24 @@ func (f *File) GetPageLayout(sheet string) (PageLayoutOptions, error) { // Comment: "defined name comment", // 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 { if definedName.Name == "" || definedName.RefersTo == "" { return ErrParameterInvalid