This closes #1358, made a refactor with breaking changes, see details:

This made a refactor with breaking changes:

Motivation and Context

When I decided to add set horizontal centered support for this library to resolve #1358, the reason I made this huge breaking change was:

- There are too many exported types for set sheet view, properties, and format properties, although a function using the functional options pattern can be optimized by returning an anonymous function, these types or property set or get function has no binding categorization, so I change these functions like `SetAppProps` to accept a pointer of options structure.
- Users can not easily find out which properties should be in the `SetSheetPrOptions` or `SetSheetFormatPr` categories
- Nested properties cannot proceed modify easily

Introduce 5 new export data types:
`HeaderFooterOptions`, `PageLayoutMarginsOptions`, `PageLayoutOptions`, `SheetPropsOptions`, and `ViewOptions`

Rename 4 exported data types:
- Rename `PivotTableOption` to `PivotTableOptions`
- Rename `FormatHeaderFooter` to `HeaderFooterOptions`
- Rename `FormatSheetProtection` to `SheetProtectionOptions`
- Rename `SparklineOption` to `SparklineOptions`

Remove 54 exported types:
`AutoPageBreaks`, `BaseColWidth`, `BlackAndWhite`, `CodeName`, `CustomHeight`, `Date1904`, `DefaultColWidth`, `DefaultGridColor`, `DefaultRowHeight`, `EnableFormatConditionsCalculation`, `FilterPrivacy`, `FirstPageNumber`, `FitToHeight`, `FitToPage`, `FitToWidth`, `OutlineSummaryBelow`, `PageLayoutOption`, `PageLayoutOptionPtr`, `PageLayoutOrientation`, `PageLayoutPaperSize`, `PageLayoutScale`, `PageMarginBottom`, `PageMarginFooter`, `PageMarginHeader`, `PageMarginLeft`, `PageMarginRight`, `PageMarginsOptions`, `PageMarginsOptionsPtr`, `PageMarginTop`, `Published`, `RightToLeft`, `SheetFormatPrOptions`, `SheetFormatPrOptionsPtr`, `SheetPrOption`, `SheetPrOptionPtr`, `SheetViewOption`, `SheetViewOptionPtr`, `ShowFormulas`, `ShowGridLines`, `ShowRowColHeaders`, `ShowRuler`, `ShowZeros`, `TabColorIndexed`, `TabColorRGB`, `TabColorTheme`, `TabColorTint`, `ThickBottom`, `ThickTop`, `TopLeftCell`, `View`, `WorkbookPrOption`, `WorkbookPrOptionPtr`, `ZeroHeight` and `ZoomScale`

Remove 2 exported constants:
`OrientationPortrait` and `OrientationLandscape`

Change 8 functions:
- Change the `func (f *File) SetPageLayout(sheet string, opts ...PageLayoutOption) error` to `func (f *File) SetPageLayout(sheet string, opts *PageLayoutOptions) error`
- Change the `func (f *File) GetPageLayout(sheet string, opts ...PageLayoutOptionPtr) error` to `func (f *File) GetPageLayout(sheet string) (PageLayoutOptions, error)`
- Change the `func (f *File) SetPageMargins(sheet string, opts ...PageMarginsOptions) error` to `func (f *File) SetPageMargins(sheet string, opts *PageLayoutMarginsOptions) error`
- Change the `func (f *File) GetPageMargins(sheet string, opts ...PageMarginsOptionsPtr) error` to `func (f *File) GetPageMargins(sheet string) (PageLayoutMarginsOptions, error)`
- Change the `func (f *File) SetSheetViewOptions(sheet string, viewIndex int, opts ...SheetViewOption) error` to `func (f *File) SetSheetView(sheet string, viewIndex int, opts *ViewOptions) error`
- Change the `func (f *File) GetSheetViewOptions(sheet string, viewIndex int, opts ...SheetViewOptionPtr) error` to `func (f *File) GetSheetView(sheet string, viewIndex int) (ViewOptions, error)`
- Change the `func (f *File) SetWorkbookPrOptions(opts ...WorkbookPrOption) error` to `func (f *File) SetWorkbookProps(opts *WorkbookPropsOptions) error`
- Change the `func (f *File) GetWorkbookPrOptions(opts ...WorkbookPrOptionPtr) error` to `func (f *File) GetWorkbookProps() (WorkbookPropsOptions, error)`

Introduce new function to instead of existing functions:
- New function `func (f *File) SetSheetProps(sheet string, opts *SheetPropsOptions) error` instead of `func (f *File) SetSheetPrOptions(sheet string, opts ...SheetPrOption) error` and `func (f *File) SetSheetFormatPr(sheet string, opts ...SheetFormatPrOption
This commit is contained in:
xuri 2022-09-29 22:00:21 +08:00
parent efcf599dfe
commit 53a495563a
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
33 changed files with 1364 additions and 2643 deletions

View File

@ -469,30 +469,30 @@ var (
}
)
// parseFormatChartSet provides a function to parse the format settings of the
// parseChartOptions provides a function to parse the format settings of the
// chart with default value.
func parseFormatChartSet(formatSet string) (*formatChart, error) {
format := formatChart{
Dimension: formatChartDimension{
func parseChartOptions(opts string) (*chartOptions, error) {
options := chartOptions{
Dimension: chartDimensionOptions{
Width: 480,
Height: 290,
},
Format: formatPicture{
Format: pictureOptions{
FPrintsWithSheet: true,
XScale: 1,
YScale: 1,
},
Legend: formatChartLegend{
Legend: chartLegendOptions{
Position: "bottom",
},
Title: formatChartTitle{
Title: chartTitleOptions{
Name: " ",
},
VaryColors: true,
ShowBlanksAs: "gap",
}
err := json.Unmarshal([]byte(formatSet), &format)
return &format, err
err := json.Unmarshal([]byte(opts), &options)
return &options, err
}
// AddChart provides the method to add chart in a sheet by given chart format
@ -881,13 +881,13 @@ func parseFormatChartSet(formatSet string) (*formatChart, error) {
// fmt.Println(err)
// }
// }
func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
func (f *File) AddChart(sheet, cell, opts string, combo ...string) error {
// Read sheet data.
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
formatSet, comboCharts, err := f.getFormatChart(format, combo)
options, comboCharts, err := f.getChartOptions(opts, combo)
if err != nil {
return err
}
@ -898,11 +898,11 @@ func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
drawingID, drawingXML = f.prepareDrawing(ws, drawingID, sheet, drawingXML)
drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels"
drawingRID := f.addRels(drawingRels, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
err = f.addDrawingChart(sheet, drawingXML, cell, formatSet.Dimension.Width, formatSet.Dimension.Height, drawingRID, &formatSet.Format)
err = f.addDrawingChart(sheet, drawingXML, cell, options.Dimension.Width, options.Dimension.Height, drawingRID, &options.Format)
if err != nil {
return err
}
f.addChart(formatSet, comboCharts)
f.addChart(options, comboCharts)
f.addContentTypePart(chartID, "chart")
f.addContentTypePart(drawingID, "drawings")
f.addSheetNameSpace(sheet, SourceRelationship)
@ -913,12 +913,12 @@ func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
// format set (such as offset, scale, aspect ratio setting and print settings)
// and properties set. In Excel a chartsheet is a worksheet that only contains
// a chart.
func (f *File) AddChartSheet(sheet, format string, combo ...string) error {
func (f *File) AddChartSheet(sheet, opts string, combo ...string) error {
// Check if the worksheet already exists
if f.GetSheetIndex(sheet) != -1 {
return ErrExistsWorksheet
}
formatSet, comboCharts, err := f.getFormatChart(format, combo)
options, comboCharts, err := f.getChartOptions(opts, combo)
if err != nil {
return err
}
@ -945,8 +945,8 @@ func (f *File) AddChartSheet(sheet, format string, combo ...string) error {
f.prepareChartSheetDrawing(&cs, drawingID, sheet)
drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels"
drawingRID := f.addRels(drawingRels, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
f.addSheetDrawingChart(drawingXML, drawingRID, &formatSet.Format)
f.addChart(formatSet, comboCharts)
f.addSheetDrawingChart(drawingXML, drawingRID, &options.Format)
f.addChart(options, comboCharts)
f.addContentTypePart(chartID, "chart")
f.addContentTypePart(sheetID, "chartsheet")
f.addContentTypePart(drawingID, "drawings")
@ -960,45 +960,45 @@ func (f *File) AddChartSheet(sheet, format string, combo ...string) error {
return err
}
// getFormatChart provides a function to check format set of the chart and
// getChartOptions provides a function to check format set of the chart and
// create chart format.
func (f *File) getFormatChart(format string, combo []string) (*formatChart, []*formatChart, error) {
var comboCharts []*formatChart
formatSet, err := parseFormatChartSet(format)
func (f *File) getChartOptions(opts string, combo []string) (*chartOptions, []*chartOptions, error) {
var comboCharts []*chartOptions
options, err := parseChartOptions(opts)
if err != nil {
return formatSet, comboCharts, err
return options, comboCharts, err
}
for _, comboFormat := range combo {
comboChart, err := parseFormatChartSet(comboFormat)
comboChart, err := parseChartOptions(comboFormat)
if err != nil {
return formatSet, comboCharts, err
return options, comboCharts, err
}
if _, ok := chartValAxNumFmtFormatCode[comboChart.Type]; !ok {
return formatSet, comboCharts, newUnsupportedChartType(comboChart.Type)
return options, comboCharts, newUnsupportedChartType(comboChart.Type)
}
comboCharts = append(comboCharts, comboChart)
}
if _, ok := chartValAxNumFmtFormatCode[formatSet.Type]; !ok {
return formatSet, comboCharts, newUnsupportedChartType(formatSet.Type)
if _, ok := chartValAxNumFmtFormatCode[options.Type]; !ok {
return options, comboCharts, newUnsupportedChartType(options.Type)
}
return formatSet, comboCharts, err
return options, comboCharts, err
}
// DeleteChart provides a function to delete chart in spreadsheet by given
// worksheet name and cell reference.
func (f *File) DeleteChart(sheet, cell string) (err error) {
func (f *File) DeleteChart(sheet, cell string) error {
col, row, err := CellNameToCoordinates(cell)
if err != nil {
return
return err
}
col--
row--
ws, err := f.workSheetReader(sheet)
if err != nil {
return
return err
}
if ws.Drawing == nil {
return
return err
}
drawingXML := strings.ReplaceAll(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl")
return f.deleteDrawing(col, row, drawingXML, "Chart")

View File

@ -23,15 +23,15 @@ import (
"strings"
)
// parseFormatCommentsSet provides a function to parse the format settings of
// parseCommentOptions provides a function to parse the format settings of
// the comment with default value.
func parseFormatCommentsSet(formatSet string) (*formatComment, error) {
format := formatComment{
func parseCommentOptions(opts string) (*commentOptions, error) {
options := commentOptions{
Author: "Author:",
Text: " ",
}
err := json.Unmarshal([]byte(formatSet), &format)
return &format, err
err := json.Unmarshal([]byte(opts), &options)
return &options, err
}
// GetComments retrieves all comments and returns a map of worksheet name to
@ -93,8 +93,8 @@ func (f *File) getSheetComments(sheetFile string) string {
// comment in Sheet1!$A$30:
//
// err := f.AddComment("Sheet1", "A30", `{"author":"Excelize: ","text":"This is a comment."}`)
func (f *File) AddComment(sheet, cell, format string) error {
formatSet, err := parseFormatCommentsSet(format)
func (f *File) AddComment(sheet, cell, opts string) error {
options, err := parseCommentOptions(opts)
if err != nil {
return err
}
@ -123,19 +123,19 @@ func (f *File) AddComment(sheet, cell, format string) error {
}
commentsXML := "xl/comments" + strconv.Itoa(commentID) + ".xml"
var colCount int
for i, l := range strings.Split(formatSet.Text, "\n") {
for i, l := range strings.Split(options.Text, "\n") {
if ll := len(l); ll > colCount {
if i == 0 {
ll += len(formatSet.Author)
ll += len(options.Author)
}
colCount = ll
}
}
err = f.addDrawingVML(commentID, drawingVML, cell, strings.Count(formatSet.Text, "\n")+1, colCount)
err = f.addDrawingVML(commentID, drawingVML, cell, strings.Count(options.Text, "\n")+1, colCount)
if err != nil {
return err
}
f.addComment(commentsXML, cell, formatSet)
f.addComment(commentsXML, cell, options)
f.addContentTypePart(commentID, "comments")
return err
}
@ -144,11 +144,12 @@ func (f *File) AddComment(sheet, cell, format string) error {
// worksheet name. For example, delete the comment in Sheet1!$A$30:
//
// err := f.DeleteComment("Sheet1", "A30")
func (f *File) DeleteComment(sheet, cell string) (err error) {
func (f *File) DeleteComment(sheet, cell string) error {
var err error
sheetXMLPath, ok := f.getSheetXMLPath(sheet)
if !ok {
err = newNoExistSheetError(sheet)
return
return err
}
commentsXML := f.getSheetComments(filepath.Base(sheetXMLPath))
if !strings.HasPrefix(commentsXML, "/") {
@ -173,7 +174,7 @@ func (f *File) DeleteComment(sheet, cell string) (err error) {
}
f.Comments[commentsXML] = comments
}
return
return err
}
// addDrawingVML provides a function to create comment as
@ -279,9 +280,9 @@ func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount,
// addComment provides a function to create chart as xl/comments%d.xml by
// given cell and format sets.
func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) {
a := formatSet.Author
t := formatSet.Text
func (f *File) addComment(commentsXML, cell string, opts *commentOptions) {
a := opts.Author
t := opts.Text
if len(a) > MaxFieldLength {
a = a[:MaxFieldLength]
}
@ -291,10 +292,10 @@ func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) {
comments := f.commentsReader(commentsXML)
authorID := 0
if comments == nil {
comments = &xlsxComments{Authors: xlsxAuthor{Author: []string{formatSet.Author}}}
comments = &xlsxComments{Authors: xlsxAuthor{Author: []string{opts.Author}}}
}
if inStrSlice(comments.Authors.Author, formatSet.Author, true) == -1 {
comments.Authors.Author = append(comments.Authors.Author, formatSet.Author)
if inStrSlice(comments.Authors.Author, opts.Author, true) == -1 {
comments.Authors.Author = append(comments.Authors.Author, opts.Author)
authorID = len(comments.Authors.Author) - 1
}
defaultFont := f.GetDefaultFont()

View File

@ -64,19 +64,20 @@ import (
// HyperlinksChanged: true,
// AppVersion: "16.0000",
// })
func (f *File) SetAppProps(appProperties *AppProperties) (err error) {
func (f *File) SetAppProps(appProperties *AppProperties) error {
var (
app *xlsxProperties
fields []string
output []byte
immutable, mutable reflect.Value
err error
field string
fields []string
immutable, mutable reflect.Value
output []byte
)
app = new(xlsxProperties)
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathDocPropsApp)))).
Decode(app); err != nil && err != io.EOF {
err = newDecodeXMLError(err)
return
return err
}
fields = []string{"Application", "ScaleCrop", "DocSecurity", "Company", "LinksUpToDate", "HyperlinksChanged", "AppVersion"}
immutable, mutable = reflect.ValueOf(*appProperties), reflect.ValueOf(app).Elem()
@ -94,7 +95,7 @@ func (f *File) SetAppProps(appProperties *AppProperties) (err error) {
app.Vt = NameSpaceDocumentPropertiesVariantTypes.Value
output, err = xml.Marshal(app)
f.saveFileList(defaultXMLPathDocPropsApp, output)
return
return err
}
// GetAppProps provides a function to get document application properties.
@ -167,23 +168,24 @@ func (f *File) GetAppProps() (ret *AppProperties, err error) {
// Language: "en-US",
// Version: "1.0.0",
// })
func (f *File) SetDocProps(docProperties *DocProperties) (err error) {
func (f *File) SetDocProps(docProperties *DocProperties) error {
var (
core *decodeCoreProperties
newProps *xlsxCoreProperties
fields []string
output []byte
immutable, mutable reflect.Value
err error
field, val string
fields []string
immutable, mutable reflect.Value
newProps *xlsxCoreProperties
output []byte
)
core = new(decodeCoreProperties)
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathDocPropsCore)))).
Decode(core); err != nil && err != io.EOF {
err = newDecodeXMLError(err)
return
return err
}
newProps, err = &xlsxCoreProperties{
newProps = &xlsxCoreProperties{
Dc: NameSpaceDublinCore,
Dcterms: NameSpaceDublinCoreTerms,
Dcmitype: NameSpaceDublinCoreMetadataInitiative,
@ -200,7 +202,7 @@ func (f *File) SetDocProps(docProperties *DocProperties) (err error) {
ContentStatus: core.ContentStatus,
Category: core.Category,
Version: core.Version,
}, nil
}
if core.Created != nil {
newProps.Created = &xlsxDcTerms{Type: core.Created.Type, Text: core.Created.Text}
}
@ -226,7 +228,7 @@ func (f *File) SetDocProps(docProperties *DocProperties) (err error) {
output, err = xml.Marshal(newProps)
f.saveFileList(defaultXMLPathDocPropsCore, output)
return
return err
}
// GetDocProps provides a function to get document core properties.

View File

@ -56,7 +56,7 @@ func (f *File) prepareChartSheetDrawing(cs *xlsxChartsheet, drawingID int, sheet
// addChart provides a function to create chart as xl/charts/chart%d.xml by
// given format sets.
func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
func (f *File) addChart(opts *chartOptions, comboCharts []*chartOptions) {
count := f.countCharts()
xlsxChartSpace := xlsxChartSpace{
XMLNSa: NameSpaceDrawingML.Value,
@ -101,7 +101,7 @@ func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
Lang: "en-US",
AltLang: "en-US",
},
T: formatSet.Title.Name,
T: opts.Title.Name,
},
},
},
@ -124,10 +124,10 @@ func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
Overlay: &attrValBool{Val: boolPtr(false)},
},
View3D: &cView3D{
RotX: &attrValInt{Val: intPtr(chartView3DRotX[formatSet.Type])},
RotY: &attrValInt{Val: intPtr(chartView3DRotY[formatSet.Type])},
Perspective: &attrValInt{Val: intPtr(chartView3DPerspective[formatSet.Type])},
RAngAx: &attrValInt{Val: intPtr(chartView3DRAngAx[formatSet.Type])},
RotX: &attrValInt{Val: intPtr(chartView3DRotX[opts.Type])},
RotY: &attrValInt{Val: intPtr(chartView3DRotY[opts.Type])},
Perspective: &attrValInt{Val: intPtr(chartView3DPerspective[opts.Type])},
RAngAx: &attrValInt{Val: intPtr(chartView3DRAngAx[opts.Type])},
},
Floor: &cThicknessSpPr{
Thickness: &attrValInt{Val: intPtr(0)},
@ -140,12 +140,12 @@ func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
},
PlotArea: &cPlotArea{},
Legend: &cLegend{
LegendPos: &attrValString{Val: stringPtr(chartLegendPosition[formatSet.Legend.Position])},
LegendPos: &attrValString{Val: stringPtr(chartLegendPosition[opts.Legend.Position])},
Overlay: &attrValBool{Val: boolPtr(false)},
},
PlotVisOnly: &attrValBool{Val: boolPtr(false)},
DispBlanksAs: &attrValString{Val: stringPtr(formatSet.ShowBlanksAs)},
DispBlanksAs: &attrValString{Val: stringPtr(opts.ShowBlanksAs)},
ShowDLblsOverMax: &attrValBool{Val: boolPtr(false)},
},
SpPr: &cSpPr{
@ -181,7 +181,7 @@ func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
},
},
}
plotAreaFunc := map[string]func(*formatChart) *cPlotArea{
plotAreaFunc := map[string]func(*chartOptions) *cPlotArea{
Area: f.drawBaseChart,
AreaStacked: f.drawBaseChart,
AreaPercentStacked: f.drawBaseChart,
@ -237,7 +237,7 @@ func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
Bubble: f.drawBaseChart,
Bubble3D: f.drawBaseChart,
}
if formatSet.Legend.None {
if opts.Legend.None {
xlsxChartSpace.Chart.Legend = nil
}
addChart := func(c, p *cPlotArea) {
@ -250,8 +250,8 @@ func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
immutable.FieldByName(mutable.Type().Field(i).Name).Set(field)
}
}
addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[formatSet.Type](formatSet))
order := len(formatSet.Series)
addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[opts.Type](opts))
order := len(opts.Series)
for idx := range comboCharts {
comboCharts[idx].order = order
addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[comboCharts[idx].Type](comboCharts[idx]))
@ -264,7 +264,7 @@ func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
// drawBaseChart provides a function to draw the c:plotArea element for bar,
// and column series charts by given format sets.
func (f *File) drawBaseChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawBaseChart(opts *chartOptions) *cPlotArea {
c := cCharts{
BarDir: &attrValString{
Val: stringPtr("col"),
@ -273,11 +273,11 @@ func (f *File) drawBaseChart(formatSet *formatChart) *cPlotArea {
Val: stringPtr("clustered"),
},
VaryColors: &attrValBool{
Val: boolPtr(formatSet.VaryColors),
Val: boolPtr(opts.VaryColors),
},
Ser: f.drawChartSeries(formatSet),
Shape: f.drawChartShape(formatSet),
DLbls: f.drawChartDLbls(formatSet),
Ser: f.drawChartSeries(opts),
Shape: f.drawChartShape(opts),
DLbls: f.drawChartDLbls(opts),
AxID: []*attrValInt{
{Val: intPtr(754001152)},
{Val: intPtr(753999904)},
@ -285,17 +285,17 @@ func (f *File) drawBaseChart(formatSet *formatChart) *cPlotArea {
Overlap: &attrValInt{Val: intPtr(100)},
}
var ok bool
if *c.BarDir.Val, ok = plotAreaChartBarDir[formatSet.Type]; !ok {
if *c.BarDir.Val, ok = plotAreaChartBarDir[opts.Type]; !ok {
c.BarDir = nil
}
if *c.Grouping.Val, ok = plotAreaChartGrouping[formatSet.Type]; !ok {
if *c.Grouping.Val, ok = plotAreaChartGrouping[opts.Type]; !ok {
c.Grouping = nil
}
if *c.Overlap.Val, ok = plotAreaChartOverlap[formatSet.Type]; !ok {
if *c.Overlap.Val, ok = plotAreaChartOverlap[opts.Type]; !ok {
c.Overlap = nil
}
catAx := f.drawPlotAreaCatAx(formatSet)
valAx := f.drawPlotAreaValAx(formatSet)
catAx := f.drawPlotAreaCatAx(opts)
valAx := f.drawPlotAreaValAx(opts)
charts := map[string]*cPlotArea{
"area": {
AreaChart: &c,
@ -508,23 +508,23 @@ func (f *File) drawBaseChart(formatSet *formatChart) *cPlotArea {
ValAx: valAx,
},
}
return charts[formatSet.Type]
return charts[opts.Type]
}
// drawDoughnutChart provides a function to draw the c:plotArea element for
// doughnut chart by given format sets.
func (f *File) drawDoughnutChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawDoughnutChart(opts *chartOptions) *cPlotArea {
holeSize := 75
if formatSet.HoleSize > 0 && formatSet.HoleSize <= 90 {
holeSize = formatSet.HoleSize
if opts.HoleSize > 0 && opts.HoleSize <= 90 {
holeSize = opts.HoleSize
}
return &cPlotArea{
DoughnutChart: &cCharts{
VaryColors: &attrValBool{
Val: boolPtr(formatSet.VaryColors),
Val: boolPtr(opts.VaryColors),
},
Ser: f.drawChartSeries(formatSet),
Ser: f.drawChartSeries(opts),
HoleSize: &attrValInt{Val: intPtr(holeSize)},
},
}
@ -532,65 +532,65 @@ func (f *File) drawDoughnutChart(formatSet *formatChart) *cPlotArea {
// drawLineChart provides a function to draw the c:plotArea element for line
// chart by given format sets.
func (f *File) drawLineChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawLineChart(opts *chartOptions) *cPlotArea {
return &cPlotArea{
LineChart: &cCharts{
Grouping: &attrValString{
Val: stringPtr(plotAreaChartGrouping[formatSet.Type]),
Val: stringPtr(plotAreaChartGrouping[opts.Type]),
},
VaryColors: &attrValBool{
Val: boolPtr(false),
},
Ser: f.drawChartSeries(formatSet),
DLbls: f.drawChartDLbls(formatSet),
Ser: f.drawChartSeries(opts),
DLbls: f.drawChartDLbls(opts),
AxID: []*attrValInt{
{Val: intPtr(754001152)},
{Val: intPtr(753999904)},
},
},
CatAx: f.drawPlotAreaCatAx(formatSet),
ValAx: f.drawPlotAreaValAx(formatSet),
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
}
}
// drawPieChart provides a function to draw the c:plotArea element for pie
// chart by given format sets.
func (f *File) drawPieChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawPieChart(opts *chartOptions) *cPlotArea {
return &cPlotArea{
PieChart: &cCharts{
VaryColors: &attrValBool{
Val: boolPtr(formatSet.VaryColors),
Val: boolPtr(opts.VaryColors),
},
Ser: f.drawChartSeries(formatSet),
Ser: f.drawChartSeries(opts),
},
}
}
// drawPie3DChart provides a function to draw the c:plotArea element for 3D
// pie chart by given format sets.
func (f *File) drawPie3DChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawPie3DChart(opts *chartOptions) *cPlotArea {
return &cPlotArea{
Pie3DChart: &cCharts{
VaryColors: &attrValBool{
Val: boolPtr(formatSet.VaryColors),
Val: boolPtr(opts.VaryColors),
},
Ser: f.drawChartSeries(formatSet),
Ser: f.drawChartSeries(opts),
},
}
}
// drawPieOfPieChart provides a function to draw the c:plotArea element for
// pie chart by given format sets.
func (f *File) drawPieOfPieChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawPieOfPieChart(opts *chartOptions) *cPlotArea {
return &cPlotArea{
OfPieChart: &cCharts{
OfPieType: &attrValString{
Val: stringPtr("pie"),
},
VaryColors: &attrValBool{
Val: boolPtr(formatSet.VaryColors),
Val: boolPtr(opts.VaryColors),
},
Ser: f.drawChartSeries(formatSet),
Ser: f.drawChartSeries(opts),
SerLines: &attrValString{},
},
}
@ -598,16 +598,16 @@ func (f *File) drawPieOfPieChart(formatSet *formatChart) *cPlotArea {
// drawBarOfPieChart provides a function to draw the c:plotArea element for
// pie chart by given format sets.
func (f *File) drawBarOfPieChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawBarOfPieChart(opts *chartOptions) *cPlotArea {
return &cPlotArea{
OfPieChart: &cCharts{
OfPieType: &attrValString{
Val: stringPtr("bar"),
},
VaryColors: &attrValBool{
Val: boolPtr(formatSet.VaryColors),
Val: boolPtr(opts.VaryColors),
},
Ser: f.drawChartSeries(formatSet),
Ser: f.drawChartSeries(opts),
SerLines: &attrValString{},
},
}
@ -615,7 +615,7 @@ func (f *File) drawBarOfPieChart(formatSet *formatChart) *cPlotArea {
// drawRadarChart provides a function to draw the c:plotArea element for radar
// chart by given format sets.
func (f *File) drawRadarChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawRadarChart(opts *chartOptions) *cPlotArea {
return &cPlotArea{
RadarChart: &cCharts{
RadarStyle: &attrValString{
@ -624,21 +624,21 @@ func (f *File) drawRadarChart(formatSet *formatChart) *cPlotArea {
VaryColors: &attrValBool{
Val: boolPtr(false),
},
Ser: f.drawChartSeries(formatSet),
DLbls: f.drawChartDLbls(formatSet),
Ser: f.drawChartSeries(opts),
DLbls: f.drawChartDLbls(opts),
AxID: []*attrValInt{
{Val: intPtr(754001152)},
{Val: intPtr(753999904)},
},
},
CatAx: f.drawPlotAreaCatAx(formatSet),
ValAx: f.drawPlotAreaValAx(formatSet),
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
}
}
// drawScatterChart provides a function to draw the c:plotArea element for
// scatter chart by given format sets.
func (f *File) drawScatterChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawScatterChart(opts *chartOptions) *cPlotArea {
return &cPlotArea{
ScatterChart: &cCharts{
ScatterStyle: &attrValString{
@ -647,35 +647,35 @@ func (f *File) drawScatterChart(formatSet *formatChart) *cPlotArea {
VaryColors: &attrValBool{
Val: boolPtr(false),
},
Ser: f.drawChartSeries(formatSet),
DLbls: f.drawChartDLbls(formatSet),
Ser: f.drawChartSeries(opts),
DLbls: f.drawChartDLbls(opts),
AxID: []*attrValInt{
{Val: intPtr(754001152)},
{Val: intPtr(753999904)},
},
},
CatAx: f.drawPlotAreaCatAx(formatSet),
ValAx: f.drawPlotAreaValAx(formatSet),
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
}
}
// drawSurface3DChart provides a function to draw the c:surface3DChart element by
// given format sets.
func (f *File) drawSurface3DChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawSurface3DChart(opts *chartOptions) *cPlotArea {
plotArea := &cPlotArea{
Surface3DChart: &cCharts{
Ser: f.drawChartSeries(formatSet),
Ser: f.drawChartSeries(opts),
AxID: []*attrValInt{
{Val: intPtr(754001152)},
{Val: intPtr(753999904)},
{Val: intPtr(832256642)},
},
},
CatAx: f.drawPlotAreaCatAx(formatSet),
ValAx: f.drawPlotAreaValAx(formatSet),
SerAx: f.drawPlotAreaSerAx(formatSet),
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
SerAx: f.drawPlotAreaSerAx(opts),
}
if formatSet.Type == WireframeSurface3D {
if opts.Type == WireframeSurface3D {
plotArea.Surface3DChart.Wireframe = &attrValBool{Val: boolPtr(true)}
}
return plotArea
@ -683,21 +683,21 @@ func (f *File) drawSurface3DChart(formatSet *formatChart) *cPlotArea {
// drawSurfaceChart provides a function to draw the c:surfaceChart element by
// given format sets.
func (f *File) drawSurfaceChart(formatSet *formatChart) *cPlotArea {
func (f *File) drawSurfaceChart(opts *chartOptions) *cPlotArea {
plotArea := &cPlotArea{
SurfaceChart: &cCharts{
Ser: f.drawChartSeries(formatSet),
Ser: f.drawChartSeries(opts),
AxID: []*attrValInt{
{Val: intPtr(754001152)},
{Val: intPtr(753999904)},
{Val: intPtr(832256642)},
},
},
CatAx: f.drawPlotAreaCatAx(formatSet),
ValAx: f.drawPlotAreaValAx(formatSet),
SerAx: f.drawPlotAreaSerAx(formatSet),
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
SerAx: f.drawPlotAreaSerAx(opts),
}
if formatSet.Type == WireframeContour {
if opts.Type == WireframeContour {
plotArea.SurfaceChart.Wireframe = &attrValBool{Val: boolPtr(true)}
}
return plotArea
@ -705,7 +705,7 @@ func (f *File) drawSurfaceChart(formatSet *formatChart) *cPlotArea {
// drawChartShape provides a function to draw the c:shape element by given
// format sets.
func (f *File) drawChartShape(formatSet *formatChart) *attrValString {
func (f *File) drawChartShape(opts *chartOptions) *attrValString {
shapes := map[string]string{
Bar3DConeClustered: "cone",
Bar3DConeStacked: "cone",
@ -729,7 +729,7 @@ func (f *File) drawChartShape(formatSet *formatChart) *attrValString {
Col3DCylinderStacked: "cylinder",
Col3DCylinderPercentStacked: "cylinder",
}
if shape, ok := shapes[formatSet.Type]; ok {
if shape, ok := shapes[opts.Type]; ok {
return &attrValString{Val: stringPtr(shape)}
}
return nil
@ -737,29 +737,29 @@ func (f *File) drawChartShape(formatSet *formatChart) *attrValString {
// drawChartSeries provides a function to draw the c:ser element by given
// format sets.
func (f *File) drawChartSeries(formatSet *formatChart) *[]cSer {
func (f *File) drawChartSeries(opts *chartOptions) *[]cSer {
var ser []cSer
for k := range formatSet.Series {
for k := range opts.Series {
ser = append(ser, cSer{
IDx: &attrValInt{Val: intPtr(k + formatSet.order)},
Order: &attrValInt{Val: intPtr(k + formatSet.order)},
IDx: &attrValInt{Val: intPtr(k + opts.order)},
Order: &attrValInt{Val: intPtr(k + opts.order)},
Tx: &cTx{
StrRef: &cStrRef{
F: formatSet.Series[k].Name,
F: opts.Series[k].Name,
},
},
SpPr: f.drawChartSeriesSpPr(k, formatSet),
Marker: f.drawChartSeriesMarker(k, formatSet),
DPt: f.drawChartSeriesDPt(k, formatSet),
DLbls: f.drawChartSeriesDLbls(formatSet),
SpPr: f.drawChartSeriesSpPr(k, opts),
Marker: f.drawChartSeriesMarker(k, opts),
DPt: f.drawChartSeriesDPt(k, opts),
DLbls: f.drawChartSeriesDLbls(opts),
InvertIfNegative: &attrValBool{Val: boolPtr(false)},
Cat: f.drawChartSeriesCat(formatSet.Series[k], formatSet),
Smooth: &attrValBool{Val: boolPtr(formatSet.Series[k].Line.Smooth)},
Val: f.drawChartSeriesVal(formatSet.Series[k], formatSet),
XVal: f.drawChartSeriesXVal(formatSet.Series[k], formatSet),
YVal: f.drawChartSeriesYVal(formatSet.Series[k], formatSet),
BubbleSize: f.drawCharSeriesBubbleSize(formatSet.Series[k], formatSet),
Bubble3D: f.drawCharSeriesBubble3D(formatSet),
Cat: f.drawChartSeriesCat(opts.Series[k], opts),
Smooth: &attrValBool{Val: boolPtr(opts.Series[k].Line.Smooth)},
Val: f.drawChartSeriesVal(opts.Series[k], opts),
XVal: f.drawChartSeriesXVal(opts.Series[k], opts),
YVal: f.drawChartSeriesYVal(opts.Series[k], opts),
BubbleSize: f.drawCharSeriesBubbleSize(opts.Series[k], opts),
Bubble3D: f.drawCharSeriesBubble3D(opts),
})
}
return &ser
@ -767,15 +767,15 @@ func (f *File) drawChartSeries(formatSet *formatChart) *[]cSer {
// drawChartSeriesSpPr provides a function to draw the c:spPr element by given
// format sets.
func (f *File) drawChartSeriesSpPr(i int, formatSet *formatChart) *cSpPr {
func (f *File) drawChartSeriesSpPr(i int, opts *chartOptions) *cSpPr {
var srgbClr *attrValString
var schemeClr *aSchemeClr
if color := stringPtr(formatSet.Series[i].Line.Color); *color != "" {
if color := stringPtr(opts.Series[i].Line.Color); *color != "" {
*color = strings.TrimPrefix(*color, "#")
srgbClr = &attrValString{Val: color}
} else {
schemeClr = &aSchemeClr{Val: "accent" + strconv.Itoa((formatSet.order+i)%6+1)}
schemeClr = &aSchemeClr{Val: "accent" + strconv.Itoa((opts.order+i)%6+1)}
}
spPrScatter := &cSpPr{
@ -786,7 +786,7 @@ func (f *File) drawChartSeriesSpPr(i int, formatSet *formatChart) *cSpPr {
}
spPrLine := &cSpPr{
Ln: &aLn{
W: f.ptToEMUs(formatSet.Series[i].Line.Width),
W: f.ptToEMUs(opts.Series[i].Line.Width),
Cap: "rnd", // rnd, sq, flat
SolidFill: &aSolidFill{
SchemeClr: schemeClr,
@ -795,12 +795,12 @@ func (f *File) drawChartSeriesSpPr(i int, formatSet *formatChart) *cSpPr {
},
}
chartSeriesSpPr := map[string]*cSpPr{Line: spPrLine, Scatter: spPrScatter}
return chartSeriesSpPr[formatSet.Type]
return chartSeriesSpPr[opts.Type]
}
// drawChartSeriesDPt provides a function to draw the c:dPt element by given
// data index and format sets.
func (f *File) drawChartSeriesDPt(i int, formatSet *formatChart) []*cDPt {
func (f *File) drawChartSeriesDPt(i int, opts *chartOptions) []*cDPt {
dpt := []*cDPt{{
IDx: &attrValInt{Val: intPtr(i)},
Bubble3D: &attrValBool{Val: boolPtr(false)},
@ -824,19 +824,19 @@ func (f *File) drawChartSeriesDPt(i int, formatSet *formatChart) []*cDPt {
},
}}
chartSeriesDPt := map[string][]*cDPt{Pie: dpt, Pie3D: dpt}
return chartSeriesDPt[formatSet.Type]
return chartSeriesDPt[opts.Type]
}
// drawChartSeriesCat provides a function to draw the c:cat element by given
// chart series and format sets.
func (f *File) drawChartSeriesCat(v formatChartSeries, formatSet *formatChart) *cCat {
func (f *File) drawChartSeriesCat(v chartSeriesOptions, opts *chartOptions) *cCat {
cat := &cCat{
StrRef: &cStrRef{
F: v.Categories,
},
}
chartSeriesCat := map[string]*cCat{Scatter: nil, Bubble: nil, Bubble3D: nil}
if _, ok := chartSeriesCat[formatSet.Type]; ok || v.Categories == "" {
if _, ok := chartSeriesCat[opts.Type]; ok || v.Categories == "" {
return nil
}
return cat
@ -844,14 +844,14 @@ func (f *File) drawChartSeriesCat(v formatChartSeries, formatSet *formatChart) *
// drawChartSeriesVal provides a function to draw the c:val element by given
// chart series and format sets.
func (f *File) drawChartSeriesVal(v formatChartSeries, formatSet *formatChart) *cVal {
func (f *File) drawChartSeriesVal(v chartSeriesOptions, opts *chartOptions) *cVal {
val := &cVal{
NumRef: &cNumRef{
F: v.Values,
},
}
chartSeriesVal := map[string]*cVal{Scatter: nil, Bubble: nil, Bubble3D: nil}
if _, ok := chartSeriesVal[formatSet.Type]; ok {
if _, ok := chartSeriesVal[opts.Type]; ok {
return nil
}
return val
@ -859,16 +859,16 @@ func (f *File) drawChartSeriesVal(v formatChartSeries, formatSet *formatChart) *
// drawChartSeriesMarker provides a function to draw the c:marker element by
// given data index and format sets.
func (f *File) drawChartSeriesMarker(i int, formatSet *formatChart) *cMarker {
func (f *File) drawChartSeriesMarker(i int, opts *chartOptions) *cMarker {
defaultSymbol := map[string]*attrValString{Scatter: {Val: stringPtr("circle")}}
marker := &cMarker{
Symbol: defaultSymbol[formatSet.Type],
Symbol: defaultSymbol[opts.Type],
Size: &attrValInt{Val: intPtr(5)},
}
if symbol := stringPtr(formatSet.Series[i].Marker.Symbol); *symbol != "" {
if symbol := stringPtr(opts.Series[i].Marker.Symbol); *symbol != "" {
marker.Symbol = &attrValString{Val: symbol}
}
if size := intPtr(formatSet.Series[i].Marker.Size); *size != 0 {
if size := intPtr(opts.Series[i].Marker.Size); *size != 0 {
marker.Size = &attrValInt{Val: size}
}
if i < 6 {
@ -889,37 +889,37 @@ func (f *File) drawChartSeriesMarker(i int, formatSet *formatChart) *cMarker {
}
}
chartSeriesMarker := map[string]*cMarker{Scatter: marker, Line: marker}
return chartSeriesMarker[formatSet.Type]
return chartSeriesMarker[opts.Type]
}
// drawChartSeriesXVal provides a function to draw the c:xVal element by given
// chart series and format sets.
func (f *File) drawChartSeriesXVal(v formatChartSeries, formatSet *formatChart) *cCat {
func (f *File) drawChartSeriesXVal(v chartSeriesOptions, opts *chartOptions) *cCat {
cat := &cCat{
StrRef: &cStrRef{
F: v.Categories,
},
}
chartSeriesXVal := map[string]*cCat{Scatter: cat}
return chartSeriesXVal[formatSet.Type]
return chartSeriesXVal[opts.Type]
}
// drawChartSeriesYVal provides a function to draw the c:yVal element by given
// chart series and format sets.
func (f *File) drawChartSeriesYVal(v formatChartSeries, formatSet *formatChart) *cVal {
func (f *File) drawChartSeriesYVal(v chartSeriesOptions, opts *chartOptions) *cVal {
val := &cVal{
NumRef: &cNumRef{
F: v.Values,
},
}
chartSeriesYVal := map[string]*cVal{Scatter: val, Bubble: val, Bubble3D: val}
return chartSeriesYVal[formatSet.Type]
return chartSeriesYVal[opts.Type]
}
// drawCharSeriesBubbleSize provides a function to draw the c:bubbleSize
// element by given chart series and format sets.
func (f *File) drawCharSeriesBubbleSize(v formatChartSeries, formatSet *formatChart) *cVal {
if _, ok := map[string]bool{Bubble: true, Bubble3D: true}[formatSet.Type]; !ok {
func (f *File) drawCharSeriesBubbleSize(v chartSeriesOptions, opts *chartOptions) *cVal {
if _, ok := map[string]bool{Bubble: true, Bubble3D: true}[opts.Type]; !ok {
return nil
}
return &cVal{
@ -931,8 +931,8 @@ func (f *File) drawCharSeriesBubbleSize(v formatChartSeries, formatSet *formatCh
// drawCharSeriesBubble3D provides a function to draw the c:bubble3D element
// by given format sets.
func (f *File) drawCharSeriesBubble3D(formatSet *formatChart) *attrValBool {
if _, ok := map[string]bool{Bubble3D: true}[formatSet.Type]; !ok {
func (f *File) drawCharSeriesBubble3D(opts *chartOptions) *attrValBool {
if _, ok := map[string]bool{Bubble3D: true}[opts.Type]; !ok {
return nil
}
return &attrValBool{Val: boolPtr(true)}
@ -940,51 +940,51 @@ func (f *File) drawCharSeriesBubble3D(formatSet *formatChart) *attrValBool {
// drawChartDLbls provides a function to draw the c:dLbls element by given
// format sets.
func (f *File) drawChartDLbls(formatSet *formatChart) *cDLbls {
func (f *File) drawChartDLbls(opts *chartOptions) *cDLbls {
return &cDLbls{
ShowLegendKey: &attrValBool{Val: boolPtr(formatSet.Legend.ShowLegendKey)},
ShowVal: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowVal)},
ShowCatName: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowCatName)},
ShowSerName: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowSerName)},
ShowBubbleSize: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowBubbleSize)},
ShowPercent: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowPercent)},
ShowLeaderLines: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowLeaderLines)},
ShowLegendKey: &attrValBool{Val: boolPtr(opts.Legend.ShowLegendKey)},
ShowVal: &attrValBool{Val: boolPtr(opts.Plotarea.ShowVal)},
ShowCatName: &attrValBool{Val: boolPtr(opts.Plotarea.ShowCatName)},
ShowSerName: &attrValBool{Val: boolPtr(opts.Plotarea.ShowSerName)},
ShowBubbleSize: &attrValBool{Val: boolPtr(opts.Plotarea.ShowBubbleSize)},
ShowPercent: &attrValBool{Val: boolPtr(opts.Plotarea.ShowPercent)},
ShowLeaderLines: &attrValBool{Val: boolPtr(opts.Plotarea.ShowLeaderLines)},
}
}
// drawChartSeriesDLbls provides a function to draw the c:dLbls element by
// given format sets.
func (f *File) drawChartSeriesDLbls(formatSet *formatChart) *cDLbls {
dLbls := f.drawChartDLbls(formatSet)
func (f *File) drawChartSeriesDLbls(opts *chartOptions) *cDLbls {
dLbls := f.drawChartDLbls(opts)
chartSeriesDLbls := map[string]*cDLbls{
Scatter: nil, Surface3D: nil, WireframeSurface3D: nil, Contour: nil, WireframeContour: nil, Bubble: nil, Bubble3D: nil,
}
if _, ok := chartSeriesDLbls[formatSet.Type]; ok {
if _, ok := chartSeriesDLbls[opts.Type]; ok {
return nil
}
return dLbls
}
// drawPlotAreaCatAx provides a function to draw the c:catAx element.
func (f *File) drawPlotAreaCatAx(formatSet *formatChart) []*cAxs {
max := &attrValFloat{Val: formatSet.XAxis.Maximum}
min := &attrValFloat{Val: formatSet.XAxis.Minimum}
if formatSet.XAxis.Maximum == nil {
func (f *File) drawPlotAreaCatAx(opts *chartOptions) []*cAxs {
max := &attrValFloat{Val: opts.XAxis.Maximum}
min := &attrValFloat{Val: opts.XAxis.Minimum}
if opts.XAxis.Maximum == nil {
max = nil
}
if formatSet.XAxis.Minimum == nil {
if opts.XAxis.Minimum == nil {
min = nil
}
axs := []*cAxs{
{
AxID: &attrValInt{Val: intPtr(754001152)},
Scaling: &cScaling{
Orientation: &attrValString{Val: stringPtr(orientation[formatSet.XAxis.ReverseOrder])},
Orientation: &attrValString{Val: stringPtr(orientation[opts.XAxis.ReverseOrder])},
Max: max,
Min: min,
},
Delete: &attrValBool{Val: boolPtr(formatSet.XAxis.None)},
AxPos: &attrValString{Val: stringPtr(catAxPos[formatSet.XAxis.ReverseOrder])},
Delete: &attrValBool{Val: boolPtr(opts.XAxis.None)},
AxPos: &attrValString{Val: stringPtr(catAxPos[opts.XAxis.ReverseOrder])},
NumFmt: &cNumFmt{
FormatCode: "General",
SourceLinked: true,
@ -1002,45 +1002,45 @@ func (f *File) drawPlotAreaCatAx(formatSet *formatChart) []*cAxs {
NoMultiLvlLbl: &attrValBool{Val: boolPtr(false)},
},
}
if formatSet.XAxis.MajorGridlines {
if opts.XAxis.MajorGridlines {
axs[0].MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
}
if formatSet.XAxis.MinorGridlines {
if opts.XAxis.MinorGridlines {
axs[0].MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
}
if formatSet.XAxis.TickLabelSkip != 0 {
axs[0].TickLblSkip = &attrValInt{Val: intPtr(formatSet.XAxis.TickLabelSkip)}
if opts.XAxis.TickLabelSkip != 0 {
axs[0].TickLblSkip = &attrValInt{Val: intPtr(opts.XAxis.TickLabelSkip)}
}
return axs
}
// drawPlotAreaValAx provides a function to draw the c:valAx element.
func (f *File) drawPlotAreaValAx(formatSet *formatChart) []*cAxs {
max := &attrValFloat{Val: formatSet.YAxis.Maximum}
min := &attrValFloat{Val: formatSet.YAxis.Minimum}
if formatSet.YAxis.Maximum == nil {
func (f *File) drawPlotAreaValAx(opts *chartOptions) []*cAxs {
max := &attrValFloat{Val: opts.YAxis.Maximum}
min := &attrValFloat{Val: opts.YAxis.Minimum}
if opts.YAxis.Maximum == nil {
max = nil
}
if formatSet.YAxis.Minimum == nil {
if opts.YAxis.Minimum == nil {
min = nil
}
var logBase *attrValFloat
if formatSet.YAxis.LogBase >= 2 && formatSet.YAxis.LogBase <= 1000 {
logBase = &attrValFloat{Val: float64Ptr(formatSet.YAxis.LogBase)}
if opts.YAxis.LogBase >= 2 && opts.YAxis.LogBase <= 1000 {
logBase = &attrValFloat{Val: float64Ptr(opts.YAxis.LogBase)}
}
axs := []*cAxs{
{
AxID: &attrValInt{Val: intPtr(753999904)},
Scaling: &cScaling{
LogBase: logBase,
Orientation: &attrValString{Val: stringPtr(orientation[formatSet.YAxis.ReverseOrder])},
Orientation: &attrValString{Val: stringPtr(orientation[opts.YAxis.ReverseOrder])},
Max: max,
Min: min,
},
Delete: &attrValBool{Val: boolPtr(formatSet.YAxis.None)},
AxPos: &attrValString{Val: stringPtr(valAxPos[formatSet.YAxis.ReverseOrder])},
Delete: &attrValBool{Val: boolPtr(opts.YAxis.None)},
AxPos: &attrValString{Val: stringPtr(valAxPos[opts.YAxis.ReverseOrder])},
NumFmt: &cNumFmt{
FormatCode: chartValAxNumFmtFormatCode[formatSet.Type],
FormatCode: chartValAxNumFmtFormatCode[opts.Type],
SourceLinked: true,
},
MajorTickMark: &attrValString{Val: stringPtr("none")},
@ -1050,44 +1050,44 @@ func (f *File) drawPlotAreaValAx(formatSet *formatChart) []*cAxs {
TxPr: f.drawPlotAreaTxPr(),
CrossAx: &attrValInt{Val: intPtr(754001152)},
Crosses: &attrValString{Val: stringPtr("autoZero")},
CrossBetween: &attrValString{Val: stringPtr(chartValAxCrossBetween[formatSet.Type])},
CrossBetween: &attrValString{Val: stringPtr(chartValAxCrossBetween[opts.Type])},
},
}
if formatSet.YAxis.MajorGridlines {
if opts.YAxis.MajorGridlines {
axs[0].MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
}
if formatSet.YAxis.MinorGridlines {
if opts.YAxis.MinorGridlines {
axs[0].MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
}
if pos, ok := valTickLblPos[formatSet.Type]; ok {
if pos, ok := valTickLblPos[opts.Type]; ok {
axs[0].TickLblPos.Val = stringPtr(pos)
}
if formatSet.YAxis.MajorUnit != 0 {
axs[0].MajorUnit = &attrValFloat{Val: float64Ptr(formatSet.YAxis.MajorUnit)}
if opts.YAxis.MajorUnit != 0 {
axs[0].MajorUnit = &attrValFloat{Val: float64Ptr(opts.YAxis.MajorUnit)}
}
return axs
}
// drawPlotAreaSerAx provides a function to draw the c:serAx element.
func (f *File) drawPlotAreaSerAx(formatSet *formatChart) []*cAxs {
max := &attrValFloat{Val: formatSet.YAxis.Maximum}
min := &attrValFloat{Val: formatSet.YAxis.Minimum}
if formatSet.YAxis.Maximum == nil {
func (f *File) drawPlotAreaSerAx(opts *chartOptions) []*cAxs {
max := &attrValFloat{Val: opts.YAxis.Maximum}
min := &attrValFloat{Val: opts.YAxis.Minimum}
if opts.YAxis.Maximum == nil {
max = nil
}
if formatSet.YAxis.Minimum == nil {
if opts.YAxis.Minimum == nil {
min = nil
}
return []*cAxs{
{
AxID: &attrValInt{Val: intPtr(832256642)},
Scaling: &cScaling{
Orientation: &attrValString{Val: stringPtr(orientation[formatSet.YAxis.ReverseOrder])},
Orientation: &attrValString{Val: stringPtr(orientation[opts.YAxis.ReverseOrder])},
Max: max,
Min: min,
},
Delete: &attrValBool{Val: boolPtr(formatSet.YAxis.None)},
AxPos: &attrValString{Val: stringPtr(catAxPos[formatSet.XAxis.ReverseOrder])},
Delete: &attrValBool{Val: boolPtr(opts.YAxis.None)},
AxPos: &attrValString{Val: stringPtr(catAxPos[opts.XAxis.ReverseOrder])},
TickLblPos: &attrValString{Val: stringPtr("nextTo")},
SpPr: f.drawPlotAreaSpPr(),
TxPr: f.drawPlotAreaTxPr(),
@ -1207,7 +1207,7 @@ func (f *File) drawingParser(path string) (*xlsxWsDr, int) {
// addDrawingChart provides a function to add chart graphic frame by given
// sheet, drawingXML, cell, width, height, relationship index and format sets.
func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rID int, formatSet *formatPicture) error {
func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rID int, opts *pictureOptions) error {
col, row, err := CellNameToCoordinates(cell)
if err != nil {
return err
@ -1215,17 +1215,17 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
colIdx := col - 1
rowIdx := row - 1
width = int(float64(width) * formatSet.XScale)
height = int(float64(height) * formatSet.YScale)
colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, colIdx, rowIdx, formatSet.OffsetX, formatSet.OffsetY, width, height)
width = int(float64(width) * opts.XScale)
height = int(float64(height) * opts.YScale)
colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, colIdx, rowIdx, opts.OffsetX, opts.OffsetY, width, height)
content, cNvPrID := f.drawingParser(drawingXML)
twoCellAnchor := xdrCellAnchor{}
twoCellAnchor.EditAs = formatSet.Positioning
twoCellAnchor.EditAs = opts.Positioning
from := xlsxFrom{}
from.Col = colStart
from.ColOff = formatSet.OffsetX * EMU
from.ColOff = opts.OffsetX * EMU
from.Row = rowStart
from.RowOff = formatSet.OffsetY * EMU
from.RowOff = opts.OffsetY * EMU
to := xlsxTo{}
to.Col = colEnd
to.ColOff = x2 * EMU
@ -1255,8 +1255,8 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
graphic, _ := xml.Marshal(graphicFrame)
twoCellAnchor.GraphicFrame = string(graphic)
twoCellAnchor.ClientData = &xdrClientData{
FLocksWithSheet: formatSet.FLocksWithSheet,
FPrintsWithSheet: formatSet.FPrintsWithSheet,
FLocksWithSheet: opts.FLocksWithSheet,
FPrintsWithSheet: opts.FPrintsWithSheet,
}
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
f.Drawings.Store(drawingXML, content)
@ -1266,10 +1266,10 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
// addSheetDrawingChart provides a function to add chart graphic frame for
// chartsheet by given sheet, drawingXML, width, height, relationship index
// and format sets.
func (f *File) addSheetDrawingChart(drawingXML string, rID int, formatSet *formatPicture) {
func (f *File) addSheetDrawingChart(drawingXML string, rID int, opts *pictureOptions) {
content, cNvPrID := f.drawingParser(drawingXML)
absoluteAnchor := xdrCellAnchor{
EditAs: formatSet.Positioning,
EditAs: opts.Positioning,
Pos: &xlsxPoint2D{},
Ext: &xlsxExt{},
}
@ -1295,8 +1295,8 @@ func (f *File) addSheetDrawingChart(drawingXML string, rID int, formatSet *forma
graphic, _ := xml.Marshal(graphicFrame)
absoluteAnchor.GraphicFrame = string(graphic)
absoluteAnchor.ClientData = &xdrClientData{
FLocksWithSheet: formatSet.FLocksWithSheet,
FPrintsWithSheet: formatSet.FPrintsWithSheet,
FLocksWithSheet: opts.FLocksWithSheet,
FPrintsWithSheet: opts.FPrintsWithSheet,
}
content.AbsoluteAnchor = append(content.AbsoluteAnchor, &absoluteAnchor)
f.Drawings.Store(drawingXML, content)
@ -1304,8 +1304,9 @@ func (f *File) addSheetDrawingChart(drawingXML string, rID int, formatSet *forma
// deleteDrawing provides a function to delete chart graphic frame by given by
// given coordinates and graphic type.
func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) (err error) {
func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) error {
var (
err error
wsDr *xlsxWsDr
deTwoCellAnchor *decodeTwoCellAnchor
)
@ -1331,7 +1332,7 @@ func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) (err
if err = f.xmlNewDecoder(strings.NewReader("<decodeTwoCellAnchor>" + wsDr.TwoCellAnchor[idx].GraphicFrame + "</decodeTwoCellAnchor>")).
Decode(deTwoCellAnchor); err != nil && err != io.EOF {
err = newDecodeXMLError(err)
return
return err
}
if err = nil; deTwoCellAnchor.From != nil && decodeTwoCellAnchorFuncs[drawingType](deTwoCellAnchor) {
if deTwoCellAnchor.From.Col == col && deTwoCellAnchor.From.Row == row {

View File

@ -319,13 +319,13 @@ func TestNewFile(t *testing.T) {
t.FailNow()
}
// Test add picture to worksheet without formatset.
// Test add picture to worksheet without options.
err = f.AddPicture("Sheet1", "C2", filepath.Join("test", "images", "excel.png"), "")
if !assert.NoError(t, err) {
t.FailNow()
}
// Test add picture to worksheet with invalid formatset.
// Test add picture to worksheet with invalid options.
err = f.AddPicture("Sheet1", "C2", filepath.Join("test", "images", "excel.png"), `{`)
if !assert.Error(t, err) {
t.FailNow()
@ -1021,12 +1021,6 @@ func TestRelsWriter(t *testing.T) {
f.relsWriter()
}
func TestGetSheetView(t *testing.T) {
f := NewFile()
_, err := f.getSheetView("SheetN", 0)
assert.EqualError(t, err, "sheet SheetN does not exist")
}
func TestConditionalFormat(t *testing.T) {
f := NewFile()
sheet1 := f.GetSheetName(0)
@ -1228,7 +1222,7 @@ func TestProtectSheet(t *testing.T) {
sheetName := f.GetSheetName(0)
assert.NoError(t, f.ProtectSheet(sheetName, nil))
// Test protect worksheet with XOR hash algorithm
assert.NoError(t, f.ProtectSheet(sheetName, &FormatSheetProtection{
assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
Password: "password",
EditScenarios: false,
}))
@ -1237,7 +1231,7 @@ func TestProtectSheet(t *testing.T) {
assert.Equal(t, "83AF", ws.SheetProtection.Password)
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestProtectSheet.xlsx")))
// Test protect worksheet with SHA-512 hash algorithm
assert.NoError(t, f.ProtectSheet(sheetName, &FormatSheetProtection{
assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
AlgorithmName: "SHA-512",
Password: "password",
}))
@ -1251,15 +1245,15 @@ func TestProtectSheet(t *testing.T) {
// Test remove sheet protection with password verification
assert.NoError(t, f.UnprotectSheet(sheetName, "password"))
// Test protect worksheet with empty password
assert.NoError(t, f.ProtectSheet(sheetName, &FormatSheetProtection{}))
assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{}))
assert.Equal(t, "", ws.SheetProtection.Password)
// Test protect worksheet with password exceeds the limit length
assert.EqualError(t, f.ProtectSheet(sheetName, &FormatSheetProtection{
assert.EqualError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
AlgorithmName: "MD4",
Password: strings.Repeat("s", MaxFieldLength+1),
}), ErrPasswordLengthInvalid.Error())
// Test protect worksheet with unsupported hash algorithm
assert.EqualError(t, f.ProtectSheet(sheetName, &FormatSheetProtection{
assert.EqualError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
AlgorithmName: "RIPEMD-160",
Password: "password",
}), ErrUnsupportedHashAlgorithm.Error())
@ -1282,13 +1276,13 @@ func TestUnprotectSheet(t *testing.T) {
f = NewFile()
sheetName := f.GetSheetName(0)
assert.NoError(t, f.ProtectSheet(sheetName, &FormatSheetProtection{Password: "password"}))
assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{Password: "password"}))
// Test remove sheet protection with an incorrect password
assert.EqualError(t, f.UnprotectSheet(sheetName, "wrongPassword"), ErrUnprotectSheetPassword.Error())
// Test remove sheet protection with password verification
assert.NoError(t, f.UnprotectSheet(sheetName, "password"))
// Test with invalid salt value
assert.NoError(t, f.ProtectSheet(sheetName, &FormatSheetProtection{
assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
AlgorithmName: "SHA-512",
Password: "password",
}))
@ -1309,7 +1303,7 @@ func TestSetDefaultTimeStyle(t *testing.T) {
func TestAddVBAProject(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetSheetPrOptions("Sheet1", CodeName("Sheet1")))
assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{CodeName: stringPtr("Sheet1")}))
assert.EqualError(t, f.AddVBAProject("macros.bin"), "stat macros.bin: no such file or directory")
assert.EqualError(t, f.AddVBAProject(filepath.Join("test", "Book1.xlsx")), ErrAddVBAProject.Error())
assert.NoError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")))

19
lib.go
View File

@ -422,20 +422,15 @@ func boolPtr(b bool) *bool { return &b }
// intPtr returns a pointer to an int with the given value.
func intPtr(i int) *int { return &i }
// uintPtr returns a pointer to an int with the given value.
func uintPtr(i uint) *uint { return &i }
// float64Ptr returns a pointer to a float64 with the given value.
func float64Ptr(f float64) *float64 { return &f }
// stringPtr returns a pointer to a string with the given value.
func stringPtr(s string) *string { return &s }
// defaultTrue returns true if b is nil, or the pointed value.
func defaultTrue(b *bool) bool {
if b == nil {
return true
}
return *b
}
// MarshalXML convert the boolean data type to literal values 0 or 1 on
// serialization.
func (avb attrValBool) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
@ -499,11 +494,11 @@ func (avb *attrValBool) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err
return nil
}
// parseFormatSet provides a method to convert format string to []byte and
// fallbackOptions provides a method to convert format string to []byte and
// handle empty string.
func parseFormatSet(formatSet string) []byte {
if formatSet != "" {
return []byte(formatSet)
func fallbackOptions(opts string) []byte {
if opts != "" {
return []byte(opts)
}
return []byte("{}")
}

View File

@ -25,15 +25,15 @@ import (
"strings"
)
// parseFormatPictureSet provides a function to parse the format settings of
// parsePictureOptions provides a function to parse the format settings of
// the picture with default value.
func parseFormatPictureSet(formatSet string) (*formatPicture, error) {
format := formatPicture{
func parsePictureOptions(opts string) (*pictureOptions, error) {
format := pictureOptions{
FPrintsWithSheet: true,
XScale: 1,
YScale: 1,
}
err := json.Unmarshal(parseFormatSet(formatSet), &format)
err := json.Unmarshal(fallbackOptions(opts), &format)
return &format, err
}
@ -148,14 +148,14 @@ func (f *File) AddPicture(sheet, cell, picture, format string) error {
// fmt.Println(err)
// }
// }
func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string, file []byte) error {
func (f *File) AddPictureFromBytes(sheet, cell, opts, name, extension string, file []byte) error {
var drawingHyperlinkRID int
var hyperlinkType string
ext, ok := supportedImageTypes[extension]
if !ok {
return ErrImgExt
}
formatSet, err := parseFormatPictureSet(format)
options, err := parsePictureOptions(opts)
if err != nil {
return err
}
@ -177,14 +177,14 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
mediaStr := ".." + strings.TrimPrefix(f.addMedia(file, ext), "xl")
drawingRID := f.addRels(drawingRels, SourceRelationshipImage, mediaStr, hyperlinkType)
// Add picture with hyperlink.
if formatSet.Hyperlink != "" && formatSet.HyperlinkType != "" {
if formatSet.HyperlinkType == "External" {
hyperlinkType = formatSet.HyperlinkType
if options.Hyperlink != "" && options.HyperlinkType != "" {
if options.HyperlinkType == "External" {
hyperlinkType = options.HyperlinkType
}
drawingHyperlinkRID = f.addRels(drawingRels, SourceRelationshipHyperLink, formatSet.Hyperlink, hyperlinkType)
drawingHyperlinkRID = f.addRels(drawingRels, SourceRelationshipHyperLink, options.Hyperlink, hyperlinkType)
}
ws.Unlock()
err = f.addDrawingPicture(sheet, drawingXML, cell, name, img.Width, img.Height, drawingRID, drawingHyperlinkRID, formatSet)
err = f.addDrawingPicture(sheet, drawingXML, cell, name, img.Width, img.Height, drawingRID, drawingHyperlinkRID, options)
if err != nil {
return err
}
@ -264,31 +264,31 @@ func (f *File) countDrawings() (count int) {
// addDrawingPicture provides a function to add picture by given sheet,
// drawingXML, cell, file name, width, height relationship index and format
// sets.
func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, height, rID, hyperlinkRID int, formatSet *formatPicture) error {
func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, height, rID, hyperlinkRID int, opts *pictureOptions) error {
col, row, err := CellNameToCoordinates(cell)
if err != nil {
return err
}
if formatSet.Autofit {
width, height, col, row, err = f.drawingResize(sheet, cell, float64(width), float64(height), formatSet)
if opts.Autofit {
width, height, col, row, err = f.drawingResize(sheet, cell, float64(width), float64(height), opts)
if err != nil {
return err
}
} else {
width = int(float64(width) * formatSet.XScale)
height = int(float64(height) * formatSet.YScale)
width = int(float64(width) * opts.XScale)
height = int(float64(height) * opts.YScale)
}
col--
row--
colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.OffsetX, formatSet.OffsetY, width, height)
colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, opts.OffsetX, opts.OffsetY, width, height)
content, cNvPrID := f.drawingParser(drawingXML)
twoCellAnchor := xdrCellAnchor{}
twoCellAnchor.EditAs = formatSet.Positioning
twoCellAnchor.EditAs = opts.Positioning
from := xlsxFrom{}
from.Col = colStart
from.ColOff = formatSet.OffsetX * EMU
from.ColOff = opts.OffsetX * EMU
from.Row = rowStart
from.RowOff = formatSet.OffsetY * EMU
from.RowOff = opts.OffsetY * EMU
to := xlsxTo{}
to.Col = colEnd
to.ColOff = x2 * EMU
@ -297,7 +297,7 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
twoCellAnchor.From = &from
twoCellAnchor.To = &to
pic := xlsxPic{}
pic.NvPicPr.CNvPicPr.PicLocks.NoChangeAspect = formatSet.NoChangeAspect
pic.NvPicPr.CNvPicPr.PicLocks.NoChangeAspect = opts.NoChangeAspect
pic.NvPicPr.CNvPr.ID = cNvPrID
pic.NvPicPr.CNvPr.Descr = file
pic.NvPicPr.CNvPr.Name = "Picture " + strconv.Itoa(cNvPrID)
@ -313,8 +313,8 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
twoCellAnchor.Pic = &pic
twoCellAnchor.ClientData = &xdrClientData{
FLocksWithSheet: formatSet.FLocksWithSheet,
FPrintsWithSheet: formatSet.FPrintsWithSheet,
FLocksWithSheet: opts.FLocksWithSheet,
FPrintsWithSheet: opts.FPrintsWithSheet,
}
content.Lock()
defer content.Unlock()
@ -514,19 +514,19 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte, error) {
// DeletePicture provides a function to delete charts in spreadsheet by given
// worksheet name and cell reference. Note that the image file won't be deleted
// from the document currently.
func (f *File) DeletePicture(sheet, cell string) (err error) {
func (f *File) DeletePicture(sheet, cell string) error {
col, row, err := CellNameToCoordinates(cell)
if err != nil {
return
return err
}
col--
row--
ws, err := f.workSheetReader(sheet)
if err != nil {
return
return err
}
if ws.Drawing == nil {
return
return err
}
drawingXML := strings.ReplaceAll(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl")
return f.deleteDrawing(col, row, drawingXML, "Pic")
@ -636,7 +636,7 @@ func (f *File) drawingsWriter() {
}
// drawingResize calculate the height and width after resizing.
func (f *File) drawingResize(sheet, cell string, width, height float64, formatSet *formatPicture) (w, h, c, r int, err error) {
func (f *File) drawingResize(sheet, cell string, width, height float64, opts *pictureOptions) (w, h, c, r int, err error) {
var mergeCells []MergeCell
mergeCells, err = f.GetMergeCells(sheet)
if err != nil {
@ -678,7 +678,7 @@ func (f *File) drawingResize(sheet, cell string, width, height float64, formatSe
asp := float64(cellHeight) / height
height, width = float64(cellHeight), width*asp
}
width, height = width-float64(formatSet.OffsetX), height-float64(formatSet.OffsetY)
w, h = int(width*formatSet.XScale), int(height*formatSet.YScale)
width, height = width-float64(opts.OffsetX), height-float64(opts.OffsetY)
w, h = int(width*opts.XScale), int(height*opts.YScale)
return
}

View File

@ -18,14 +18,14 @@ import (
"strings"
)
// PivotTableOption directly maps the format settings of the pivot table.
// PivotTableOptions directly maps the format settings of the pivot table.
//
// PivotTableStyleName: The built-in pivot table style names
//
// PivotStyleLight1 - PivotStyleLight28
// PivotStyleMedium1 - PivotStyleMedium28
// PivotStyleDark1 - PivotStyleDark28
type PivotTableOption struct {
type PivotTableOptions struct {
pivotTableSheetName string
DataRange string `json:"data_range"`
PivotTableRange string `json:"pivot_table_range"`
@ -81,9 +81,9 @@ type PivotTableField struct {
// options. Note that the same fields can not in Columns, Rows and Filter
// fields at the same time.
//
// For example, create a pivot table on the Sheet1!$G$2:$M$34 range reference
// with the region Sheet1!$A$1:$E$31 as the data source, summarize by sum for
// sales:
// For example, create a pivot table on the range reference Sheet1!$G$2:$M$34
// with the range reference Sheet1!$A$1:$E$31 as the data source, summarize by
// sum for sales:
//
// package main
//
@ -129,7 +129,7 @@ type PivotTableField struct {
// fmt.Println(err)
// }
// }
func (f *File) AddPivotTable(opts *PivotTableOption) error {
func (f *File) AddPivotTable(opts *PivotTableOptions) error {
// parameter validation
_, pivotTableSheetPath, err := f.parseFormatPivotTableSet(opts)
if err != nil {
@ -168,7 +168,7 @@ func (f *File) AddPivotTable(opts *PivotTableOption) error {
// parseFormatPivotTableSet provides a function to validate pivot table
// properties.
func (f *File) parseFormatPivotTableSet(opts *PivotTableOption) (*xlsxWorksheet, string, error) {
func (f *File) parseFormatPivotTableSet(opts *PivotTableOptions) (*xlsxWorksheet, string, error) {
if opts == nil {
return nil, "", ErrParameterRequired
}
@ -228,7 +228,7 @@ func (f *File) adjustRange(rangeStr string) (string, []int, error) {
// getPivotFieldsOrder provides a function to get order list of pivot table
// fields.
func (f *File) getPivotFieldsOrder(opts *PivotTableOption) ([]string, error) {
func (f *File) getPivotFieldsOrder(opts *PivotTableOptions) ([]string, error) {
var order []string
dataRange := f.getDefinedNameRefTo(opts.DataRange, opts.pivotTableSheetName)
if dataRange == "" {
@ -250,7 +250,7 @@ func (f *File) getPivotFieldsOrder(opts *PivotTableOption) ([]string, error) {
}
// addPivotCache provides a function to create a pivot cache by given properties.
func (f *File) addPivotCache(pivotCacheXML string, opts *PivotTableOption) error {
func (f *File) addPivotCache(pivotCacheXML string, opts *PivotTableOptions) error {
// validate data range
definedNameRef := true
dataRange := f.getDefinedNameRefTo(opts.DataRange, opts.pivotTableSheetName)
@ -312,7 +312,7 @@ func (f *File) addPivotCache(pivotCacheXML string, opts *PivotTableOption) error
// addPivotTable provides a function to create a pivot table by given pivot
// table ID and properties.
func (f *File) addPivotTable(cacheID, pivotTableID int, pivotTableXML string, opts *PivotTableOption) error {
func (f *File) addPivotTable(cacheID, pivotTableID int, pivotTableXML string, opts *PivotTableOptions) error {
// validate pivot table range
_, coordinates, err := f.adjustRange(opts.PivotTableRange)
if err != nil {
@ -391,7 +391,7 @@ func (f *File) addPivotTable(cacheID, pivotTableID int, pivotTableXML string, op
// addPivotRowFields provides a method to add row fields for pivot table by
// given pivot table options.
func (f *File) addPivotRowFields(pt *xlsxPivotTableDefinition, opts *PivotTableOption) error {
func (f *File) addPivotRowFields(pt *xlsxPivotTableDefinition, opts *PivotTableOptions) error {
// row fields
rowFieldsIndex, err := f.getPivotFieldsIndex(opts.Rows, opts)
if err != nil {
@ -415,7 +415,7 @@ func (f *File) addPivotRowFields(pt *xlsxPivotTableDefinition, opts *PivotTableO
// addPivotPageFields provides a method to add page fields for pivot table by
// given pivot table options.
func (f *File) addPivotPageFields(pt *xlsxPivotTableDefinition, opts *PivotTableOption) error {
func (f *File) addPivotPageFields(pt *xlsxPivotTableDefinition, opts *PivotTableOptions) error {
// page fields
pageFieldsIndex, err := f.getPivotFieldsIndex(opts.Filter, opts)
if err != nil {
@ -441,7 +441,7 @@ func (f *File) addPivotPageFields(pt *xlsxPivotTableDefinition, opts *PivotTable
// addPivotDataFields provides a method to add data fields for pivot table by
// given pivot table options.
func (f *File) addPivotDataFields(pt *xlsxPivotTableDefinition, opts *PivotTableOption) error {
func (f *File) addPivotDataFields(pt *xlsxPivotTableDefinition, opts *PivotTableOptions) error {
// data fields
dataFieldsIndex, err := f.getPivotFieldsIndex(opts.Data, opts)
if err != nil {
@ -481,7 +481,7 @@ func inPivotTableField(a []PivotTableField, x string) int {
// addPivotColFields create pivot column fields by given pivot table
// definition and option.
func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opts *PivotTableOption) error {
func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opts *PivotTableOptions) error {
if len(opts.Columns) == 0 {
if len(opts.Data) <= 1 {
return nil
@ -522,7 +522,7 @@ func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opts *PivotTableO
// 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 *PivotTableOption) error {
func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOptions) error {
order, err := f.getPivotFieldsOrder(opts)
if err != nil {
return err
@ -627,7 +627,7 @@ func (f *File) countPivotCache() int {
// getPivotFieldsIndex convert the column of the first row in the data region
// to a sequential index by given fields and pivot option.
func (f *File) getPivotFieldsIndex(fields []PivotTableField, opts *PivotTableOption) ([]int, error) {
func (f *File) getPivotFieldsIndex(fields []PivotTableField, opts *PivotTableOptions) ([]int, error) {
var pivotFieldsIndex []int
orders, err := f.getPivotFieldsOrder(opts)
if err != nil {

View File

@ -25,7 +25,7 @@ func TestAddPivotTable(t *testing.T) {
assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("D%d", row), rand.Intn(5000)))
assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("E%d", row), region[rand.Intn(4)]))
}
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "Sheet1!$G$2:$M$34",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -41,7 +41,7 @@ func TestAddPivotTable(t *testing.T) {
ShowError: true,
}))
// Use different order of coordinate tests
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "Sheet1!$U$34:$O$2",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -55,7 +55,7 @@ func TestAddPivotTable(t *testing.T) {
ShowLastColumn: true,
}))
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "Sheet1!$W$2:$AC$34",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -68,7 +68,7 @@ func TestAddPivotTable(t *testing.T) {
ShowColHeaders: true,
ShowLastColumn: true,
}))
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "Sheet1!$G$37:$W$50",
Rows: []PivotTableField{{Data: "Month"}},
@ -81,7 +81,7 @@ func TestAddPivotTable(t *testing.T) {
ShowColHeaders: true,
ShowLastColumn: true,
}))
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "Sheet1!$AE$2:$AG$33",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -94,7 +94,7 @@ func TestAddPivotTable(t *testing.T) {
ShowLastColumn: true,
}))
// Create pivot table with empty subtotal field name and specified style
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "Sheet1!$AJ$2:$AP1$35",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -110,7 +110,7 @@ func TestAddPivotTable(t *testing.T) {
PivotTableStyleName: "PivotStyleLight19",
}))
f.NewSheet("Sheet2")
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "Sheet2!$A$1:$AR$15",
Rows: []PivotTableField{{Data: "Month"}},
@ -123,7 +123,7 @@ func TestAddPivotTable(t *testing.T) {
ShowColHeaders: true,
ShowLastColumn: true,
}))
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "Sheet2!$A$18:$AR$54",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Type"}},
@ -143,7 +143,7 @@ func TestAddPivotTable(t *testing.T) {
Comment: "Pivot Table Data Range",
Scope: "Sheet2",
}))
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "dataRange",
PivotTableRange: "Sheet2!$A$57:$AJ$91",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -160,7 +160,7 @@ func TestAddPivotTable(t *testing.T) {
// Test empty pivot table options
assert.EqualError(t, f.AddPivotTable(nil), ErrParameterRequired.Error())
// Test invalid data range
assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
assert.EqualError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$A$1",
PivotTableRange: "Sheet1!$U$34:$O$2",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -168,7 +168,7 @@ func TestAddPivotTable(t *testing.T) {
Data: []PivotTableField{{Data: "Sales"}},
}), `parameter 'DataRange' parsing error: parameter is invalid`)
// Test the data range of the worksheet that is not declared
assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
assert.EqualError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "$A$1:$E$31",
PivotTableRange: "Sheet1!$U$34:$O$2",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -176,7 +176,7 @@ func TestAddPivotTable(t *testing.T) {
Data: []PivotTableField{{Data: "Sales"}},
}), `parameter 'DataRange' parsing error: parameter is invalid`)
// Test the worksheet declared in the data range does not exist
assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
assert.EqualError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "SheetN!$A$1:$E$31",
PivotTableRange: "Sheet1!$U$34:$O$2",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -184,7 +184,7 @@ func TestAddPivotTable(t *testing.T) {
Data: []PivotTableField{{Data: "Sales"}},
}), "sheet SheetN does not exist")
// Test the pivot table range of the worksheet that is not declared
assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
assert.EqualError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "$U$34:$O$2",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -192,7 +192,7 @@ func TestAddPivotTable(t *testing.T) {
Data: []PivotTableField{{Data: "Sales"}},
}), `parameter 'PivotTableRange' parsing error: parameter is invalid`)
// Test the worksheet declared in the pivot table range does not exist
assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
assert.EqualError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "SheetN!$U$34:$O$2",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -200,7 +200,7 @@ func TestAddPivotTable(t *testing.T) {
Data: []PivotTableField{{Data: "Sales"}},
}), "sheet SheetN does not exist")
// Test not exists worksheet in data range
assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
assert.EqualError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "SheetN!$A$1:$E$31",
PivotTableRange: "Sheet1!$U$34:$O$2",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -208,7 +208,7 @@ func TestAddPivotTable(t *testing.T) {
Data: []PivotTableField{{Data: "Sales"}},
}), "sheet SheetN does not exist")
// Test invalid row number in data range
assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
assert.EqualError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$0:$E$31",
PivotTableRange: "Sheet1!$U$34:$O$2",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -217,7 +217,7 @@ func TestAddPivotTable(t *testing.T) {
}), `parameter 'DataRange' parsing error: cannot convert cell "A0" to coordinates: invalid cell name "A0"`)
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddPivotTable1.xlsx")))
// Test with field names that exceed the length limit and invalid subtotal
assert.NoError(t, f.AddPivotTable(&PivotTableOption{
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "Sheet1!$G$2:$M$34",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -232,12 +232,12 @@ func TestAddPivotTable(t *testing.T) {
_, _, err = f.adjustRange("sheet1!")
assert.EqualError(t, err, "parameter is invalid")
// Test get pivot fields order with empty data range
_, err = f.getPivotFieldsOrder(&PivotTableOption{})
_, err = f.getPivotFieldsOrder(&PivotTableOptions{})
assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
// Test add pivot cache with empty data range
assert.EqualError(t, f.addPivotCache("", &PivotTableOption{}), "parameter 'DataRange' parsing error: parameter is required")
assert.EqualError(t, f.addPivotCache("", &PivotTableOptions{}), "parameter 'DataRange' parsing error: parameter is required")
// Test add pivot cache with invalid data range
assert.EqualError(t, f.addPivotCache("", &PivotTableOption{
assert.EqualError(t, f.addPivotCache("", &PivotTableOptions{
DataRange: "$A$1:$E$31",
PivotTableRange: "Sheet1!$U$34:$O$2",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -245,11 +245,11 @@ func TestAddPivotTable(t *testing.T) {
Data: []PivotTableField{{Data: "Sales"}},
}), "parameter 'DataRange' parsing error: parameter is invalid")
// Test add pivot table with empty options
assert.EqualError(t, f.addPivotTable(0, 0, "", &PivotTableOption{}), "parameter 'PivotTableRange' parsing error: parameter is required")
assert.EqualError(t, f.addPivotTable(0, 0, "", &PivotTableOptions{}), "parameter 'PivotTableRange' parsing error: parameter is required")
// Test add pivot table with invalid data range
assert.EqualError(t, f.addPivotTable(0, 0, "", &PivotTableOption{}), "parameter 'PivotTableRange' parsing error: parameter is required")
assert.EqualError(t, f.addPivotTable(0, 0, "", &PivotTableOptions{}), "parameter 'PivotTableRange' parsing error: parameter is required")
// Test add pivot fields with empty data range
assert.EqualError(t, f.addPivotFields(nil, &PivotTableOption{
assert.EqualError(t, f.addPivotFields(nil, &PivotTableOptions{
DataRange: "$A$1:$E$31",
PivotTableRange: "Sheet1!$U$34:$O$2",
Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
@ -257,14 +257,14 @@ func TestAddPivotTable(t *testing.T) {
Data: []PivotTableField{{Data: "Sales"}},
}), `parameter 'DataRange' parsing error: parameter is invalid`)
// Test get pivot fields index with empty data range
_, err = f.getPivotFieldsIndex([]PivotTableField{}, &PivotTableOption{})
_, err = f.getPivotFieldsIndex([]PivotTableField{}, &PivotTableOptions{})
assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
}
func TestAddPivotRowFields(t *testing.T) {
f := NewFile()
// Test invalid data range
assert.EqualError(t, f.addPivotRowFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
assert.EqualError(t, f.addPivotRowFields(&xlsxPivotTableDefinition{}, &PivotTableOptions{
DataRange: "Sheet1!$A$1:$A$1",
}), `parameter 'DataRange' parsing error: parameter is invalid`)
}
@ -272,7 +272,7 @@ func TestAddPivotRowFields(t *testing.T) {
func TestAddPivotPageFields(t *testing.T) {
f := NewFile()
// Test invalid data range
assert.EqualError(t, f.addPivotPageFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
assert.EqualError(t, f.addPivotPageFields(&xlsxPivotTableDefinition{}, &PivotTableOptions{
DataRange: "Sheet1!$A$1:$A$1",
}), `parameter 'DataRange' parsing error: parameter is invalid`)
}
@ -280,7 +280,7 @@ func TestAddPivotPageFields(t *testing.T) {
func TestAddPivotDataFields(t *testing.T) {
f := NewFile()
// Test invalid data range
assert.EqualError(t, f.addPivotDataFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
assert.EqualError(t, f.addPivotDataFields(&xlsxPivotTableDefinition{}, &PivotTableOptions{
DataRange: "Sheet1!$A$1:$A$1",
}), `parameter 'DataRange' parsing error: parameter is invalid`)
}
@ -288,7 +288,7 @@ func TestAddPivotDataFields(t *testing.T) {
func TestAddPivotColFields(t *testing.T) {
f := NewFile()
// Test invalid data range
assert.EqualError(t, f.addPivotColFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
assert.EqualError(t, f.addPivotColFields(&xlsxPivotTableDefinition{}, &PivotTableOptions{
DataRange: "Sheet1!$A$1:$A$1",
Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
}), `parameter 'DataRange' parsing error: parameter is invalid`)
@ -297,7 +297,7 @@ func TestAddPivotColFields(t *testing.T) {
func TestGetPivotFieldsOrder(t *testing.T) {
f := NewFile()
// Test get pivot fields order with not exist worksheet
_, err := f.getPivotFieldsOrder(&PivotTableOption{DataRange: "SheetN!$A$1:$E$31"})
_, err := f.getPivotFieldsOrder(&PivotTableOptions{DataRange: "SheetN!$A$1:$E$31"})
assert.EqualError(t, err, "sheet SheetN does not exist")
}

View File

@ -165,10 +165,10 @@ func TestRowHeight(t *testing.T) {
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get row height with custom default row height.
assert.NoError(t, f.SetSheetFormatPr(sheet1,
DefaultRowHeight(30.0),
CustomHeight(true),
))
assert.NoError(t, f.SetSheetProps(sheet1, &SheetPropsOptions{
DefaultRowHeight: float64Ptr(30.0),
CustomHeight: boolPtr(true),
}))
height, err = f.GetRowHeight(sheet1, 100)
assert.NoError(t, err)
assert.Equal(t, 30.0, height)

View File

@ -17,21 +17,21 @@ import (
"strings"
)
// parseFormatShapeSet provides a function to parse the format settings of the
// parseShapeOptions provides a function to parse the format settings of the
// shape with default value.
func parseFormatShapeSet(formatSet string) (*formatShape, error) {
format := formatShape{
func parseShapeOptions(opts string) (*shapeOptions, error) {
options := shapeOptions{
Width: 160,
Height: 160,
Format: formatPicture{
Format: pictureOptions{
FPrintsWithSheet: true,
XScale: 1,
YScale: 1,
},
Line: formatLine{Width: 1},
Line: lineOptions{Width: 1},
}
err := json.Unmarshal([]byte(formatSet), &format)
return &format, err
err := json.Unmarshal([]byte(opts), &options)
return &options, err
}
// AddShape provides the method to add shape in a sheet by given worksheet
@ -277,8 +277,8 @@ func parseFormatShapeSet(formatSet string) (*formatShape, error) {
// wavy
// wavyHeavy
// wavyDbl
func (f *File) AddShape(sheet, cell, format string) error {
formatSet, err := parseFormatShapeSet(format)
func (f *File) AddShape(sheet, cell, opts string) error {
options, err := parseShapeOptions(opts)
if err != nil {
return err
}
@ -305,7 +305,7 @@ func (f *File) AddShape(sheet, cell, format string) error {
f.addSheetDrawing(sheet, rID)
f.addSheetNameSpace(sheet, SourceRelationship)
}
err = f.addDrawingShape(sheet, drawingXML, cell, formatSet)
err = f.addDrawingShape(sheet, drawingXML, cell, options)
if err != nil {
return err
}
@ -315,7 +315,7 @@ func (f *File) AddShape(sheet, cell, format string) error {
// addDrawingShape provides a function to add preset geometry by given sheet,
// drawingXMLand format sets.
func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *formatShape) error {
func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *shapeOptions) error {
fromCol, fromRow, err := CellNameToCoordinates(cell)
if err != nil {
return err
@ -344,19 +344,19 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
"wavyDbl": true,
}
width := int(float64(formatSet.Width) * formatSet.Format.XScale)
height := int(float64(formatSet.Height) * formatSet.Format.YScale)
width := int(float64(opts.Width) * opts.Format.XScale)
height := int(float64(opts.Height) * opts.Format.YScale)
colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, colIdx, rowIdx, formatSet.Format.OffsetX, formatSet.Format.OffsetY,
colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, colIdx, rowIdx, opts.Format.OffsetX, opts.Format.OffsetY,
width, height)
content, cNvPrID := f.drawingParser(drawingXML)
twoCellAnchor := xdrCellAnchor{}
twoCellAnchor.EditAs = formatSet.Format.Positioning
twoCellAnchor.EditAs = opts.Format.Positioning
from := xlsxFrom{}
from.Col = colStart
from.ColOff = formatSet.Format.OffsetX * EMU
from.ColOff = opts.Format.OffsetX * EMU
from.Row = rowStart
from.RowOff = formatSet.Format.OffsetY * EMU
from.RowOff = opts.Format.OffsetY * EMU
to := xlsxTo{}
to.Col = colEnd
to.ColOff = x2 * EMU
@ -365,7 +365,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
twoCellAnchor.From = &from
twoCellAnchor.To = &to
shape := xdrSp{
Macro: formatSet.Macro,
Macro: opts.Macro,
NvSpPr: &xdrNvSpPr{
CNvPr: &xlsxCNvPr{
ID: cNvPrID,
@ -377,13 +377,13 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
},
SpPr: &xlsxSpPr{
PrstGeom: xlsxPrstGeom{
Prst: formatSet.Type,
Prst: opts.Type,
},
},
Style: &xdrStyle{
LnRef: setShapeRef(formatSet.Color.Line, 2),
FillRef: setShapeRef(formatSet.Color.Fill, 1),
EffectRef: setShapeRef(formatSet.Color.Effect, 0),
LnRef: setShapeRef(opts.Color.Line, 2),
FillRef: setShapeRef(opts.Color.Fill, 1),
EffectRef: setShapeRef(opts.Color.Effect, 0),
FontRef: &aFontRef{
Idx: "minor",
SchemeClr: &attrValString{
@ -401,13 +401,13 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
},
},
}
if formatSet.Line.Width != 1 {
if opts.Line.Width != 1 {
shape.SpPr.Ln = xlsxLineProperties{
W: f.ptToEMUs(formatSet.Line.Width),
W: f.ptToEMUs(opts.Line.Width),
}
}
if len(formatSet.Paragraph) < 1 {
formatSet.Paragraph = []formatShapeParagraph{
if len(opts.Paragraph) < 1 {
opts.Paragraph = []shapeParagraphOptions{
{
Font: Font{
Bold: false,
@ -421,7 +421,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
},
}
}
for _, p := range formatSet.Paragraph {
for _, p := range opts.Paragraph {
u := p.Font.Underline
_, ok := textUnderlineType[u]
if !ok {
@ -460,8 +460,8 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
}
twoCellAnchor.Sp = &shape
twoCellAnchor.ClientData = &xdrClientData{
FLocksWithSheet: formatSet.Format.FLocksWithSheet,
FPrintsWithSheet: formatSet.Format.FPrintsWithSheet,
FLocksWithSheet: opts.Format.FLocksWithSheet,
FPrintsWithSheet: opts.Format.FPrintsWithSheet,
}
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
f.Drawings.Store(drawingXML, content)

328
sheet.go
View File

@ -38,10 +38,10 @@ import (
// Note that when creating a new workbook, the default worksheet named
// `Sheet1` will be created.
func (f *File) NewSheet(sheet string) int {
// Check if the worksheet already exists
if trimSheetName(sheet) == "" {
return -1
}
// Check if the worksheet already exists
index := f.GetSheetIndex(sheet)
if index != -1 {
return index
@ -675,10 +675,10 @@ func (f *File) SetSheetVisible(sheet string, visible bool) error {
return nil
}
// parseFormatPanesSet provides a function to parse the panes settings.
func parseFormatPanesSet(formatSet string) (*formatPanes, error) {
format := formatPanes{}
err := json.Unmarshal([]byte(formatSet), &format)
// parsePanesOptions provides a function to parse the panes settings.
func parsePanesOptions(opts string) (*panesOptions, error) {
format := panesOptions{}
err := json.Unmarshal([]byte(opts), &format)
return &format, err
}
@ -767,7 +767,7 @@ func parseFormatPanesSet(formatSet string) (*formatPanes, error) {
//
// f.SetPanes("Sheet1", `{"freeze":false,"split":false}`)
func (f *File) SetPanes(sheet, panes string) error {
fs, _ := parseFormatPanesSet(panes)
fs, _ := parsePanesOptions(panes)
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
@ -1021,7 +1021,7 @@ func attrValToBool(name string, attrs []xml.Attr) (val bool, err error) {
// |
// &R | Right section
// |
// &S | Strikethrough text format
// &S | Strike through text format
// |
// &T | Current time
// |
@ -1068,7 +1068,7 @@ func attrValToBool(name string, attrs []xml.Attr) (val bool, err error) {
// that same page
//
// - No footer on the first page
func (f *File) SetHeaderFooter(sheet string, settings *FormatHeaderFooter) error {
func (f *File) SetHeaderFooter(sheet string, settings *HeaderFooterOptions) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
@ -1113,13 +1113,13 @@ func (f *File) SetHeaderFooter(sheet string, settings *FormatHeaderFooter) error
// Password: "password",
// EditScenarios: false,
// })
func (f *File) ProtectSheet(sheet string, settings *FormatSheetProtection) error {
func (f *File) ProtectSheet(sheet string, settings *SheetProtectionOptions) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
if settings == nil {
settings = &FormatSheetProtection{
settings = &SheetProtectionOptions{
EditObjects: true,
EditScenarios: true,
SelectLockedCells: true,
@ -1213,173 +1213,8 @@ func trimSheetName(name string) string {
return name
}
// PageLayoutOption is an option of a page layout of a worksheet. See
// SetPageLayout().
type PageLayoutOption interface {
setPageLayout(layout *xlsxPageSetUp)
}
// PageLayoutOptionPtr is a writable PageLayoutOption. See GetPageLayout().
type PageLayoutOptionPtr interface {
PageLayoutOption
getPageLayout(layout *xlsxPageSetUp)
}
type (
// BlackAndWhite specified print black and white.
BlackAndWhite bool
// FirstPageNumber specified the first printed page number. If no value is
// specified, then 'automatic' is assumed.
FirstPageNumber uint
// PageLayoutOrientation defines the orientation of page layout for a
// worksheet.
PageLayoutOrientation string
// PageLayoutPaperSize defines the paper size of the worksheet.
PageLayoutPaperSize int
// FitToHeight specified the number of vertical pages to fit on.
FitToHeight int
// FitToWidth specified the number of horizontal pages to fit on.
FitToWidth int
// PageLayoutScale defines the print scaling. This attribute is restricted
// to value ranging from 10 (10%) to 400 (400%). This setting is
// overridden when fitToWidth and/or fitToHeight are in use.
PageLayoutScale uint
)
const (
// OrientationPortrait indicates page layout orientation id portrait.
OrientationPortrait = "portrait"
// OrientationLandscape indicates page layout orientation id landscape.
OrientationLandscape = "landscape"
)
// setPageLayout provides a method to set the print black and white for the
// worksheet.
func (p BlackAndWhite) setPageLayout(ps *xlsxPageSetUp) {
ps.BlackAndWhite = bool(p)
}
// getPageLayout provides a method to get the print black and white for the
// worksheet.
func (p *BlackAndWhite) getPageLayout(ps *xlsxPageSetUp) {
if ps == nil {
*p = false
return
}
*p = BlackAndWhite(ps.BlackAndWhite)
}
// setPageLayout provides a method to set the first printed page number for
// the worksheet.
func (p FirstPageNumber) setPageLayout(ps *xlsxPageSetUp) {
if 0 < int(p) {
ps.FirstPageNumber = strconv.Itoa(int(p))
ps.UseFirstPageNumber = true
}
}
// getPageLayout provides a method to get the first printed page number for
// the worksheet.
func (p *FirstPageNumber) getPageLayout(ps *xlsxPageSetUp) {
if ps != nil && ps.UseFirstPageNumber {
if number, _ := strconv.Atoi(ps.FirstPageNumber); number != 0 {
*p = FirstPageNumber(number)
return
}
}
*p = 1
}
// setPageLayout provides a method to set the orientation for the worksheet.
func (o PageLayoutOrientation) setPageLayout(ps *xlsxPageSetUp) {
ps.Orientation = string(o)
}
// getPageLayout provides a method to get the orientation for the worksheet.
func (o *PageLayoutOrientation) getPageLayout(ps *xlsxPageSetUp) {
// Excel default: portrait
if ps == nil || ps.Orientation == "" {
*o = OrientationPortrait
return
}
*o = PageLayoutOrientation(ps.Orientation)
}
// setPageLayout provides a method to set the paper size for the worksheet.
func (p PageLayoutPaperSize) setPageLayout(ps *xlsxPageSetUp) {
ps.PaperSize = intPtr(int(p))
}
// getPageLayout provides a method to get the paper size for the worksheet.
func (p *PageLayoutPaperSize) getPageLayout(ps *xlsxPageSetUp) {
// Excel default: 1
if ps == nil || ps.PaperSize == nil {
*p = 1
return
}
*p = PageLayoutPaperSize(*ps.PaperSize)
}
// setPageLayout provides a method to set the fit to height for the worksheet.
func (p FitToHeight) setPageLayout(ps *xlsxPageSetUp) {
if int(p) > 0 {
ps.FitToHeight = intPtr(int(p))
}
}
// getPageLayout provides a method to get the fit to height for the worksheet.
func (p *FitToHeight) getPageLayout(ps *xlsxPageSetUp) {
if ps == nil || ps.FitToHeight == nil {
*p = 1
return
}
*p = FitToHeight(*ps.FitToHeight)
}
// setPageLayout provides a method to set the fit to width for the worksheet.
func (p FitToWidth) setPageLayout(ps *xlsxPageSetUp) {
if int(p) > 0 {
ps.FitToWidth = intPtr(int(p))
}
}
// getPageLayout provides a method to get the fit to width for the worksheet.
func (p *FitToWidth) getPageLayout(ps *xlsxPageSetUp) {
if ps == nil || ps.FitToWidth == nil {
*p = 1
return
}
*p = FitToWidth(*ps.FitToWidth)
}
// setPageLayout provides a method to set the scale for the worksheet.
func (p PageLayoutScale) setPageLayout(ps *xlsxPageSetUp) {
if 10 <= int(p) && int(p) <= 400 {
ps.Scale = int(p)
}
}
// getPageLayout provides a method to get the scale for the worksheet.
func (p *PageLayoutScale) getPageLayout(ps *xlsxPageSetUp) {
if ps == nil || ps.Scale < 10 || ps.Scale > 400 {
*p = 100
return
}
*p = PageLayoutScale(ps.Scale)
}
// SetPageLayout provides a function to sets worksheet page layout.
//
// Available options:
//
// BlackAndWhite(bool)
// FirstPageNumber(uint)
// PageLayoutOrientation(string)
// PageLayoutPaperSize(int)
// FitToHeight(int)
// FitToWidth(int)
// PageLayoutScale(uint)
//
// The following shows the paper size sorted by excelize index number:
//
// Index | Paper Size
@ -1500,42 +1335,93 @@ func (p *PageLayoutScale) getPageLayout(ps *xlsxPageSetUp) {
// 116 | PRC Envelope #8 Rotated (309 mm x 120 mm)
// 117 | PRC Envelope #9 Rotated (324 mm x 229 mm)
// 118 | PRC Envelope #10 Rotated (458 mm x 324 mm)
func (f *File) SetPageLayout(sheet string, opts ...PageLayoutOption) error {
s, err := f.workSheetReader(sheet)
func (f *File) SetPageLayout(sheet string, opts *PageLayoutOptions) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
ps := s.PageSetUp
if ps == nil {
ps = new(xlsxPageSetUp)
s.PageSetUp = ps
}
for _, opt := range opts {
opt.setPageLayout(ps)
if opts == nil {
return err
}
ws.setPageSetUp(opts)
return err
}
// GetPageLayout provides a function to gets worksheet page layout.
//
// Available options:
//
// PageLayoutOrientation(string)
// PageLayoutPaperSize(int)
// FitToHeight(int)
// FitToWidth(int)
func (f *File) GetPageLayout(sheet string, opts ...PageLayoutOptionPtr) error {
s, err := f.workSheetReader(sheet)
if err != nil {
return err
// newPageSetUp initialize page setup settings for the worksheet if which not
// exist.
func (ws *xlsxWorksheet) newPageSetUp() {
if ws.PageSetUp == nil {
ws.PageSetUp = new(xlsxPageSetUp)
}
ps := s.PageSetUp
}
for _, opt := range opts {
opt.getPageLayout(ps)
// setPageSetUp set page setup settings for the worksheet by given options.
func (ws *xlsxWorksheet) setPageSetUp(opts *PageLayoutOptions) {
if opts.Size != nil {
ws.newPageSetUp()
ws.PageSetUp.PaperSize = opts.Size
}
return err
if opts.Orientation != nil && (*opts.Orientation == "portrait" || *opts.Orientation == "landscape") {
ws.newPageSetUp()
ws.PageSetUp.Orientation = *opts.Orientation
}
if opts.FirstPageNumber != nil && *opts.FirstPageNumber > 0 {
ws.newPageSetUp()
ws.PageSetUp.FirstPageNumber = strconv.Itoa(int(*opts.FirstPageNumber))
ws.PageSetUp.UseFirstPageNumber = true
}
if opts.AdjustTo != nil && 10 <= *opts.AdjustTo && *opts.AdjustTo <= 400 {
ws.newPageSetUp()
ws.PageSetUp.Scale = int(*opts.AdjustTo)
}
if opts.FitToHeight != nil {
ws.newPageSetUp()
ws.PageSetUp.FitToHeight = opts.FitToHeight
}
if opts.FitToWidth != nil {
ws.newPageSetUp()
ws.PageSetUp.FitToWidth = opts.FitToWidth
}
if opts.BlackAndWhite != nil {
ws.newPageSetUp()
ws.PageSetUp.BlackAndWhite = *opts.BlackAndWhite
}
}
// GetPageLayout provides a function to gets worksheet page layout.
func (f *File) GetPageLayout(sheet string) (PageLayoutOptions, error) {
opts := PageLayoutOptions{
Size: intPtr(0),
Orientation: stringPtr("portrait"),
FirstPageNumber: uintPtr(1),
AdjustTo: uintPtr(100),
}
ws, err := f.workSheetReader(sheet)
if err != nil {
return opts, err
}
if ws.PageSetUp != nil {
if ws.PageSetUp.PaperSize != nil {
opts.Size = ws.PageSetUp.PaperSize
}
if ws.PageSetUp.Orientation != "" {
opts.Orientation = stringPtr(ws.PageSetUp.Orientation)
}
if num, _ := strconv.Atoi(ws.PageSetUp.FirstPageNumber); num != 0 {
opts.FirstPageNumber = uintPtr(uint(num))
}
if ws.PageSetUp.Scale >= 10 && ws.PageSetUp.Scale <= 400 {
opts.AdjustTo = uintPtr(uint(ws.PageSetUp.Scale))
}
if ws.PageSetUp.FitToHeight != nil {
opts.FitToHeight = ws.PageSetUp.FitToHeight
}
if ws.PageSetUp.FitToWidth != nil {
opts.FitToWidth = ws.PageSetUp.FitToWidth
}
opts.BlackAndWhite = boolPtr(ws.PageSetUp.BlackAndWhite)
}
return opts, err
}
// SetDefinedName provides a function to set the defined names of the workbook
@ -1690,20 +1576,23 @@ func (f *File) UngroupSheets() error {
// ends and where begins the next one by given worksheet name and cell reference, so the
// content before the page break will be printed on one page and after the
// page break on another.
func (f *File) InsertPageBreak(sheet, cell string) (err error) {
var ws *xlsxWorksheet
var row, col int
func (f *File) InsertPageBreak(sheet, cell string) error {
var (
ws *xlsxWorksheet
row, col int
err error
)
rowBrk, colBrk := -1, -1
if ws, err = f.workSheetReader(sheet); err != nil {
return
return err
}
if col, row, err = CellNameToCoordinates(cell); err != nil {
return
return err
}
col--
row--
if col == row && col == 0 {
return
return err
}
if ws.RowBreaks == nil {
ws.RowBreaks = &xlsxBreaks{}
@ -1741,24 +1630,27 @@ func (f *File) InsertPageBreak(sheet, cell string) (err error) {
}
ws.RowBreaks.Count = len(ws.RowBreaks.Brk)
ws.ColBreaks.Count = len(ws.ColBreaks.Brk)
return
return err
}
// RemovePageBreak remove a page break by given worksheet name and cell
// reference.
func (f *File) RemovePageBreak(sheet, cell string) (err error) {
var ws *xlsxWorksheet
var row, col int
func (f *File) RemovePageBreak(sheet, cell string) error {
var (
ws *xlsxWorksheet
row, col int
err error
)
if ws, err = f.workSheetReader(sheet); err != nil {
return
return err
}
if col, row, err = CellNameToCoordinates(cell); err != nil {
return
return err
}
col--
row--
if col == row && col == 0 {
return
return err
}
removeBrk := func(ID int, brks []*xlsxBrk) []*xlsxBrk {
for i, brk := range brks {
@ -1769,7 +1661,7 @@ func (f *File) RemovePageBreak(sheet, cell string) (err error) {
return brks
}
if ws.RowBreaks == nil || ws.ColBreaks == nil {
return
return err
}
rowBrks := len(ws.RowBreaks.Brk)
colBrks := len(ws.ColBreaks.Brk)
@ -1780,20 +1672,20 @@ func (f *File) RemovePageBreak(sheet, cell string) (err error) {
ws.ColBreaks.Count = len(ws.ColBreaks.Brk)
ws.RowBreaks.ManualBreakCount--
ws.ColBreaks.ManualBreakCount--
return
return err
}
if rowBrks > 0 && rowBrks > colBrks {
ws.RowBreaks.Brk = removeBrk(row, ws.RowBreaks.Brk)
ws.RowBreaks.Count = len(ws.RowBreaks.Brk)
ws.RowBreaks.ManualBreakCount--
return
return err
}
if colBrks > 0 && colBrks > rowBrks {
ws.ColBreaks.Brk = removeBrk(col, ws.ColBreaks.Brk)
ws.ColBreaks.Count = len(ws.ColBreaks.Brk)
ws.ColBreaks.ManualBreakCount--
}
return
return err
}
// relsReader provides a function to get the pointer to the structure

View File

@ -8,78 +8,9 @@ import (
"strings"
"testing"
"github.com/mohae/deepcopy"
"github.com/stretchr/testify/assert"
)
func ExampleFile_SetPageLayout() {
f := NewFile()
if err := f.SetPageLayout(
"Sheet1",
BlackAndWhite(true),
FirstPageNumber(2),
PageLayoutOrientation(OrientationLandscape),
PageLayoutPaperSize(10),
FitToHeight(2),
FitToWidth(2),
PageLayoutScale(50),
); err != nil {
fmt.Println(err)
}
// Output:
}
func ExampleFile_GetPageLayout() {
f := NewFile()
var (
blackAndWhite BlackAndWhite
firstPageNumber FirstPageNumber
orientation PageLayoutOrientation
paperSize PageLayoutPaperSize
fitToHeight FitToHeight
fitToWidth FitToWidth
scale PageLayoutScale
)
if err := f.GetPageLayout("Sheet1", &blackAndWhite); err != nil {
fmt.Println(err)
}
if err := f.GetPageLayout("Sheet1", &firstPageNumber); err != nil {
fmt.Println(err)
}
if err := f.GetPageLayout("Sheet1", &orientation); err != nil {
fmt.Println(err)
}
if err := f.GetPageLayout("Sheet1", &paperSize); err != nil {
fmt.Println(err)
}
if err := f.GetPageLayout("Sheet1", &fitToHeight); err != nil {
fmt.Println(err)
}
if err := f.GetPageLayout("Sheet1", &fitToWidth); err != nil {
fmt.Println(err)
}
if err := f.GetPageLayout("Sheet1", &scale); err != nil {
fmt.Println(err)
}
fmt.Println("Defaults:")
fmt.Printf("- print black and white: %t\n", blackAndWhite)
fmt.Printf("- page number for first printed page: %d\n", firstPageNumber)
fmt.Printf("- orientation: %q\n", orientation)
fmt.Printf("- paper size: %d\n", paperSize)
fmt.Printf("- fit to height: %d\n", fitToHeight)
fmt.Printf("- fit to width: %d\n", fitToWidth)
fmt.Printf("- scale: %d\n", scale)
// Output:
// Defaults:
// - print black and white: false
// - page number for first printed page: 1
// - orientation: "portrait"
// - paper size: 1
// - fit to height: 1
// - fit to width: 1
// - scale: 100
}
func TestNewSheet(t *testing.T) {
f := NewFile()
f.NewSheet("Sheet2")
@ -114,68 +45,6 @@ func TestSetPane(t *testing.T) {
assert.NoError(t, f.SetPanes("Sheet1", `{"freeze":true,"split":false,"x_split":1,"y_split":0,"top_left_cell":"B1","active_pane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}`))
}
func TestPageLayoutOption(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
container PageLayoutOptionPtr
nonDefault PageLayoutOption
}{
{new(BlackAndWhite), BlackAndWhite(true)},
{new(FirstPageNumber), FirstPageNumber(2)},
{new(PageLayoutOrientation), PageLayoutOrientation(OrientationLandscape)},
{new(PageLayoutPaperSize), PageLayoutPaperSize(10)},
{new(FitToHeight), FitToHeight(2)},
{new(FitToWidth), FitToWidth(2)},
{new(PageLayoutScale), PageLayoutScale(50)},
}
for i, test := range testData {
t.Run(fmt.Sprintf("TestData%d", i), func(t *testing.T) {
opts := test.nonDefault
t.Logf("option %T", opts)
def := deepcopy.Copy(test.container).(PageLayoutOptionPtr)
val1 := deepcopy.Copy(def).(PageLayoutOptionPtr)
val2 := deepcopy.Copy(def).(PageLayoutOptionPtr)
f := NewFile()
// Get the default value
assert.NoError(t, f.GetPageLayout(sheet, def), opts)
// Get again and check
assert.NoError(t, f.GetPageLayout(sheet, val1), opts)
if !assert.Equal(t, val1, def, opts) {
t.FailNow()
}
// Set the same value
assert.NoError(t, f.SetPageLayout(sheet, val1), opts)
// Get again and check
assert.NoError(t, f.GetPageLayout(sheet, val1), opts)
if !assert.Equal(t, val1, def, "%T: value should not have changed", opts) {
t.FailNow()
}
// Set a different value
assert.NoError(t, f.SetPageLayout(sheet, test.nonDefault), opts)
assert.NoError(t, f.GetPageLayout(sheet, val1), opts)
// Get again and compare
assert.NoError(t, f.GetPageLayout(sheet, val2), opts)
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opts) {
t.FailNow()
}
// Value should not be the same as the default
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opts) {
t.FailNow()
}
// Restore the default value
assert.NoError(t, f.SetPageLayout(sheet, def), opts)
assert.NoError(t, f.GetPageLayout(sheet, val1), opts)
if !assert.Equal(t, def, val1) {
t.FailNow()
}
})
}
}
func TestSearchSheet(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
if !assert.NoError(t, err) {
@ -226,14 +95,32 @@ func TestSearchSheet(t *testing.T) {
func TestSetPageLayout(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetPageLayout("Sheet1", nil))
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).PageSetUp = nil
expected := PageLayoutOptions{
Size: intPtr(1),
Orientation: stringPtr("landscape"),
FirstPageNumber: uintPtr(1),
AdjustTo: uintPtr(120),
FitToHeight: intPtr(2),
FitToWidth: intPtr(2),
BlackAndWhite: boolPtr(true),
}
assert.NoError(t, f.SetPageLayout("Sheet1", &expected))
opts, err := f.GetPageLayout("Sheet1")
assert.NoError(t, err)
assert.Equal(t, expected, opts)
// Test set page layout on not exists worksheet.
assert.EqualError(t, f.SetPageLayout("SheetN"), "sheet SheetN does not exist")
assert.EqualError(t, f.SetPageLayout("SheetN", nil), "sheet SheetN does not exist")
}
func TestGetPageLayout(t *testing.T) {
f := NewFile()
// Test get page layout on not exists worksheet.
assert.EqualError(t, f.GetPageLayout("SheetN"), "sheet SheetN does not exist")
_, err := f.GetPageLayout("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
}
func TestSetHeaderFooter(t *testing.T) {
@ -242,20 +129,20 @@ func TestSetHeaderFooter(t *testing.T) {
// Test set header and footer on not exists worksheet.
assert.EqualError(t, f.SetHeaderFooter("SheetN", nil), "sheet SheetN does not exist")
// Test set header and footer with illegal setting.
assert.EqualError(t, f.SetHeaderFooter("Sheet1", &FormatHeaderFooter{
assert.EqualError(t, f.SetHeaderFooter("Sheet1", &HeaderFooterOptions{
OddHeader: strings.Repeat("c", MaxFieldLength+1),
}), newFieldLengthError("OddHeader").Error())
assert.NoError(t, f.SetHeaderFooter("Sheet1", nil))
text := strings.Repeat("一", MaxFieldLength)
assert.NoError(t, f.SetHeaderFooter("Sheet1", &FormatHeaderFooter{
assert.NoError(t, f.SetHeaderFooter("Sheet1", &HeaderFooterOptions{
OddHeader: text,
OddFooter: text,
EvenHeader: text,
EvenFooter: text,
FirstHeader: text,
}))
assert.NoError(t, f.SetHeaderFooter("Sheet1", &FormatHeaderFooter{
assert.NoError(t, f.SetHeaderFooter("Sheet1", &HeaderFooterOptions{
DifferentFirst: true,
DifferentOddEven: true,
OddHeader: "&R&P",

View File

@ -11,647 +11,249 @@
package excelize
import "strings"
// SheetPrOption is an option of a view of a worksheet. See SetSheetPrOptions().
type SheetPrOption interface {
setSheetPrOption(view *xlsxSheetPr)
}
// SheetPrOptionPtr is a writable SheetPrOption. See GetSheetPrOptions().
type SheetPrOptionPtr interface {
SheetPrOption
getSheetPrOption(view *xlsxSheetPr)
}
type (
// CodeName is an option used for SheetPrOption and WorkbookPrOption
CodeName string
// EnableFormatConditionsCalculation is a SheetPrOption
EnableFormatConditionsCalculation bool
// Published is a SheetPrOption
Published bool
// FitToPage is a SheetPrOption
FitToPage bool
// TabColorIndexed is a TabColor option, within SheetPrOption
TabColorIndexed int
// TabColorRGB is a TabColor option, within SheetPrOption
TabColorRGB string
// TabColorTheme is a TabColor option, within SheetPrOption
TabColorTheme int
// TabColorTint is a TabColor option, within SheetPrOption
TabColorTint float64
// AutoPageBreaks is a SheetPrOption
AutoPageBreaks bool
// OutlineSummaryBelow is an outlinePr, within SheetPr option
OutlineSummaryBelow bool
)
// setSheetPrOption implements the SheetPrOption interface.
func (o OutlineSummaryBelow) setSheetPrOption(pr *xlsxSheetPr) {
if pr.OutlinePr == nil {
pr.OutlinePr = new(xlsxOutlinePr)
}
pr.OutlinePr.SummaryBelow = bool(o)
}
// getSheetPrOption implements the SheetPrOptionPtr interface.
func (o *OutlineSummaryBelow) getSheetPrOption(pr *xlsxSheetPr) {
// Excel default: true
if pr == nil || pr.OutlinePr == nil {
*o = true
return
}
*o = OutlineSummaryBelow(defaultTrue(&pr.OutlinePr.SummaryBelow))
}
// setSheetPrOption implements the SheetPrOption interface and specifies a
// stable name of the sheet.
func (o CodeName) setSheetPrOption(pr *xlsxSheetPr) {
pr.CodeName = string(o)
}
// getSheetPrOption implements the SheetPrOptionPtr interface and get the
// stable name of the sheet.
func (o *CodeName) getSheetPrOption(pr *xlsxSheetPr) {
if pr == nil {
*o = ""
return
}
*o = CodeName(pr.CodeName)
}
// setSheetPrOption implements the SheetPrOption interface and flag indicating
// whether the conditional formatting calculations shall be evaluated.
func (o EnableFormatConditionsCalculation) setSheetPrOption(pr *xlsxSheetPr) {
pr.EnableFormatConditionsCalculation = boolPtr(bool(o))
}
// getSheetPrOption implements the SheetPrOptionPtr interface and get the
// settings of whether the conditional formatting calculations shall be
// evaluated.
func (o *EnableFormatConditionsCalculation) getSheetPrOption(pr *xlsxSheetPr) {
if pr == nil {
*o = true
return
}
*o = EnableFormatConditionsCalculation(defaultTrue(pr.EnableFormatConditionsCalculation))
}
// setSheetPrOption implements the SheetPrOption interface and flag indicating
// whether the worksheet is published.
func (o Published) setSheetPrOption(pr *xlsxSheetPr) {
pr.Published = boolPtr(bool(o))
}
// getSheetPrOption implements the SheetPrOptionPtr interface and get the
// settings of whether the worksheet is published.
func (o *Published) getSheetPrOption(pr *xlsxSheetPr) {
if pr == nil {
*o = true
return
}
*o = Published(defaultTrue(pr.Published))
}
// setSheetPrOption implements the SheetPrOption interface.
func (o FitToPage) setSheetPrOption(pr *xlsxSheetPr) {
if pr.PageSetUpPr == nil {
if !o {
return
}
pr.PageSetUpPr = new(xlsxPageSetUpPr)
}
pr.PageSetUpPr.FitToPage = bool(o)
}
// getSheetPrOption implements the SheetPrOptionPtr interface.
func (o *FitToPage) getSheetPrOption(pr *xlsxSheetPr) {
// Excel default: false
if pr == nil || pr.PageSetUpPr == nil {
*o = false
return
}
*o = FitToPage(pr.PageSetUpPr.FitToPage)
}
// setSheetPrOption implements the SheetPrOption interface and sets the
// TabColor Indexed.
func (o TabColorIndexed) setSheetPrOption(pr *xlsxSheetPr) {
if pr.TabColor == nil {
pr.TabColor = new(xlsxTabColor)
}
pr.TabColor.Indexed = int(o)
}
// getSheetPrOption implements the SheetPrOptionPtr interface and gets the
// TabColor Indexed. Defaults to -1 if no indexed has been set.
func (o *TabColorIndexed) getSheetPrOption(pr *xlsxSheetPr) {
if pr == nil || pr.TabColor == nil {
*o = TabColorIndexed(ColorMappingTypeUnset)
return
}
*o = TabColorIndexed(pr.TabColor.Indexed)
}
// setSheetPrOption implements the SheetPrOption interface and specifies a
// stable name of the sheet.
func (o TabColorRGB) setSheetPrOption(pr *xlsxSheetPr) {
if pr.TabColor == nil {
if string(o) == "" {
return
}
pr.TabColor = new(xlsxTabColor)
}
pr.TabColor.RGB = getPaletteColor(string(o))
}
// getSheetPrOption implements the SheetPrOptionPtr interface and get the
// stable name of the sheet.
func (o *TabColorRGB) getSheetPrOption(pr *xlsxSheetPr) {
if pr == nil || pr.TabColor == nil {
*o = ""
return
}
*o = TabColorRGB(strings.TrimPrefix(pr.TabColor.RGB, "FF"))
}
// setSheetPrOption implements the SheetPrOption interface and sets the
// TabColor Theme. Warning: it does not create a clrScheme!
func (o TabColorTheme) setSheetPrOption(pr *xlsxSheetPr) {
if pr.TabColor == nil {
pr.TabColor = new(xlsxTabColor)
}
pr.TabColor.Theme = int(o)
}
// getSheetPrOption implements the SheetPrOptionPtr interface and gets the
// TabColor Theme. Defaults to -1 if no theme has been set.
func (o *TabColorTheme) getSheetPrOption(pr *xlsxSheetPr) {
if pr == nil || pr.TabColor == nil {
*o = TabColorTheme(ColorMappingTypeUnset)
return
}
*o = TabColorTheme(pr.TabColor.Theme)
}
// setSheetPrOption implements the SheetPrOption interface and sets the
// TabColor Tint.
func (o TabColorTint) setSheetPrOption(pr *xlsxSheetPr) {
if pr.TabColor == nil {
pr.TabColor = new(xlsxTabColor)
}
pr.TabColor.Tint = float64(o)
}
// getSheetPrOption implements the SheetPrOptionPtr interface and gets the
// TabColor Tint. Defaults to 0.0 if no tint has been set.
func (o *TabColorTint) getSheetPrOption(pr *xlsxSheetPr) {
if pr == nil || pr.TabColor == nil {
*o = 0.0
return
}
*o = TabColorTint(pr.TabColor.Tint)
}
// setSheetPrOption implements the SheetPrOption interface.
func (o AutoPageBreaks) setSheetPrOption(pr *xlsxSheetPr) {
if pr.PageSetUpPr == nil {
if !o {
return
}
pr.PageSetUpPr = new(xlsxPageSetUpPr)
}
pr.PageSetUpPr.AutoPageBreaks = bool(o)
}
// getSheetPrOption implements the SheetPrOptionPtr interface.
func (o *AutoPageBreaks) getSheetPrOption(pr *xlsxSheetPr) {
// Excel default: false
if pr == nil || pr.PageSetUpPr == nil {
*o = false
return
}
*o = AutoPageBreaks(pr.PageSetUpPr.AutoPageBreaks)
}
// SetSheetPrOptions provides a function to sets worksheet properties.
//
// Available options:
//
// CodeName(string)
// EnableFormatConditionsCalculation(bool)
// Published(bool)
// FitToPage(bool)
// TabColorIndexed(int)
// TabColorRGB(string)
// TabColorTheme(int)
// TabColorTint(float64)
// AutoPageBreaks(bool)
// OutlineSummaryBelow(bool)
func (f *File) SetSheetPrOptions(sheet string, opts ...SheetPrOption) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
pr := ws.SheetPr
if pr == nil {
pr = new(xlsxSheetPr)
ws.SheetPr = pr
}
for _, opt := range opts {
opt.setSheetPrOption(pr)
}
return err
}
// GetSheetPrOptions provides a function to gets worksheet properties.
//
// Available options:
//
// CodeName(string)
// EnableFormatConditionsCalculation(bool)
// Published(bool)
// FitToPage(bool)
// TabColorIndexed(int)
// TabColorRGB(string)
// TabColorTheme(int)
// TabColorTint(float64)
// AutoPageBreaks(bool)
// OutlineSummaryBelow(bool)
func (f *File) GetSheetPrOptions(sheet string, opts ...SheetPrOptionPtr) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
pr := ws.SheetPr
for _, opt := range opts {
opt.getSheetPrOption(pr)
}
return err
}
type (
// PageMarginBottom specifies the bottom margin for the page.
PageMarginBottom float64
// PageMarginFooter specifies the footer margin for the page.
PageMarginFooter float64
// PageMarginHeader specifies the header margin for the page.
PageMarginHeader float64
// PageMarginLeft specifies the left margin for the page.
PageMarginLeft float64
// PageMarginRight specifies the right margin for the page.
PageMarginRight float64
// PageMarginTop specifies the top margin for the page.
PageMarginTop float64
)
// setPageMargins provides a method to set the bottom margin for the worksheet.
func (p PageMarginBottom) setPageMargins(pm *xlsxPageMargins) {
pm.Bottom = float64(p)
}
// setPageMargins provides a method to get the bottom margin for the worksheet.
func (p *PageMarginBottom) getPageMargins(pm *xlsxPageMargins) {
// Excel default: 0.75
if pm == nil || pm.Bottom == 0 {
*p = 0.75
return
}
*p = PageMarginBottom(pm.Bottom)
}
// setPageMargins provides a method to set the footer margin for the worksheet.
func (p PageMarginFooter) setPageMargins(pm *xlsxPageMargins) {
pm.Footer = float64(p)
}
// setPageMargins provides a method to get the footer margin for the worksheet.
func (p *PageMarginFooter) getPageMargins(pm *xlsxPageMargins) {
// Excel default: 0.3
if pm == nil || pm.Footer == 0 {
*p = 0.3
return
}
*p = PageMarginFooter(pm.Footer)
}
// setPageMargins provides a method to set the header margin for the worksheet.
func (p PageMarginHeader) setPageMargins(pm *xlsxPageMargins) {
pm.Header = float64(p)
}
// setPageMargins provides a method to get the header margin for the worksheet.
func (p *PageMarginHeader) getPageMargins(pm *xlsxPageMargins) {
// Excel default: 0.3
if pm == nil || pm.Header == 0 {
*p = 0.3
return
}
*p = PageMarginHeader(pm.Header)
}
// setPageMargins provides a method to set the left margin for the worksheet.
func (p PageMarginLeft) setPageMargins(pm *xlsxPageMargins) {
pm.Left = float64(p)
}
// setPageMargins provides a method to get the left margin for the worksheet.
func (p *PageMarginLeft) getPageMargins(pm *xlsxPageMargins) {
// Excel default: 0.7
if pm == nil || pm.Left == 0 {
*p = 0.7
return
}
*p = PageMarginLeft(pm.Left)
}
// setPageMargins provides a method to set the right margin for the worksheet.
func (p PageMarginRight) setPageMargins(pm *xlsxPageMargins) {
pm.Right = float64(p)
}
// setPageMargins provides a method to get the right margin for the worksheet.
func (p *PageMarginRight) getPageMargins(pm *xlsxPageMargins) {
// Excel default: 0.7
if pm == nil || pm.Right == 0 {
*p = 0.7
return
}
*p = PageMarginRight(pm.Right)
}
// setPageMargins provides a method to set the top margin for the worksheet.
func (p PageMarginTop) setPageMargins(pm *xlsxPageMargins) {
pm.Top = float64(p)
}
// setPageMargins provides a method to get the top margin for the worksheet.
func (p *PageMarginTop) getPageMargins(pm *xlsxPageMargins) {
// Excel default: 0.75
if pm == nil || pm.Top == 0 {
*p = 0.75
return
}
*p = PageMarginTop(pm.Top)
}
// PageMarginsOptions is an option of a page margin of a worksheet. See
// SetPageMargins().
type PageMarginsOptions interface {
setPageMargins(layout *xlsxPageMargins)
}
// PageMarginsOptionsPtr is a writable PageMarginsOptions. See
// GetPageMargins().
type PageMarginsOptionsPtr interface {
PageMarginsOptions
getPageMargins(layout *xlsxPageMargins)
}
// SetPageMargins provides a function to set worksheet page margins.
//
// Available options:
//
// PageMarginBottom(float64)
// PageMarginFooter(float64)
// PageMarginHeader(float64)
// PageMarginLeft(float64)
// PageMarginRight(float64)
// PageMarginTop(float64)
func (f *File) SetPageMargins(sheet string, opts ...PageMarginsOptions) error {
s, err := f.workSheetReader(sheet)
func (f *File) SetPageMargins(sheet string, opts *PageLayoutMarginsOptions) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
pm := s.PageMargins
if pm == nil {
pm = new(xlsxPageMargins)
s.PageMargins = pm
if opts == nil {
return err
}
for _, opt := range opts {
opt.setPageMargins(pm)
preparePageMargins := func(ws *xlsxWorksheet) {
if ws.PageMargins == nil {
ws.PageMargins = new(xlsxPageMargins)
}
}
preparePrintOptions := func(ws *xlsxWorksheet) {
if ws.PrintOptions == nil {
ws.PrintOptions = new(xlsxPrintOptions)
}
}
if opts.Bottom != nil {
preparePageMargins(ws)
ws.PageMargins.Bottom = *opts.Bottom
}
if opts.Footer != nil {
preparePageMargins(ws)
ws.PageMargins.Footer = *opts.Footer
}
if opts.Header != nil {
preparePageMargins(ws)
ws.PageMargins.Header = *opts.Header
}
if opts.Left != nil {
preparePageMargins(ws)
ws.PageMargins.Left = *opts.Left
}
if opts.Right != nil {
preparePageMargins(ws)
ws.PageMargins.Right = *opts.Right
}
if opts.Top != nil {
preparePageMargins(ws)
ws.PageMargins.Top = *opts.Top
}
if opts.Horizontally != nil {
preparePrintOptions(ws)
ws.PrintOptions.HorizontalCentered = *opts.Horizontally
}
if opts.Vertically != nil {
preparePrintOptions(ws)
ws.PrintOptions.VerticalCentered = *opts.Vertically
}
return err
}
// GetPageMargins provides a function to get worksheet page margins.
//
// Available options:
//
// PageMarginBottom(float64)
// PageMarginFooter(float64)
// PageMarginHeader(float64)
// PageMarginLeft(float64)
// PageMarginRight(float64)
// PageMarginTop(float64)
func (f *File) GetPageMargins(sheet string, opts ...PageMarginsOptionsPtr) error {
s, err := f.workSheetReader(sheet)
func (f *File) GetPageMargins(sheet string) (PageLayoutMarginsOptions, error) {
opts := PageLayoutMarginsOptions{
Bottom: float64Ptr(0.75),
Footer: float64Ptr(0.3),
Header: float64Ptr(0.3),
Left: float64Ptr(0.7),
Right: float64Ptr(0.7),
Top: float64Ptr(0.75),
}
ws, err := f.workSheetReader(sheet)
if err != nil {
return opts, err
}
if ws.PageMargins != nil {
if ws.PageMargins.Bottom != 0 {
opts.Bottom = float64Ptr(ws.PageMargins.Bottom)
}
if ws.PageMargins.Footer != 0 {
opts.Footer = float64Ptr(ws.PageMargins.Footer)
}
if ws.PageMargins.Header != 0 {
opts.Header = float64Ptr(ws.PageMargins.Header)
}
if ws.PageMargins.Left != 0 {
opts.Left = float64Ptr(ws.PageMargins.Left)
}
if ws.PageMargins.Right != 0 {
opts.Right = float64Ptr(ws.PageMargins.Right)
}
if ws.PageMargins.Top != 0 {
opts.Top = float64Ptr(ws.PageMargins.Top)
}
}
if ws.PrintOptions != nil {
opts.Horizontally = boolPtr(ws.PrintOptions.HorizontalCentered)
opts.Vertically = boolPtr(ws.PrintOptions.VerticalCentered)
}
return opts, err
}
// setSheetProps set worksheet format properties by given options.
func (ws *xlsxWorksheet) setSheetProps(opts *SheetPropsOptions) {
prepareSheetPr := func(ws *xlsxWorksheet) {
if ws.SheetPr == nil {
ws.SheetPr = new(xlsxSheetPr)
}
}
preparePageSetUpPr := func(ws *xlsxWorksheet) {
prepareSheetPr(ws)
if ws.SheetPr.PageSetUpPr == nil {
ws.SheetPr.PageSetUpPr = new(xlsxPageSetUpPr)
}
}
prepareOutlinePr := func(ws *xlsxWorksheet) {
prepareSheetPr(ws)
if ws.SheetPr.OutlinePr == nil {
ws.SheetPr.OutlinePr = new(xlsxOutlinePr)
}
}
prepareTabColor := func(ws *xlsxWorksheet) {
prepareSheetPr(ws)
if ws.SheetPr.TabColor == nil {
ws.SheetPr.TabColor = new(xlsxTabColor)
}
}
if opts.CodeName != nil {
prepareSheetPr(ws)
ws.SheetPr.CodeName = *opts.CodeName
}
if opts.EnableFormatConditionsCalculation != nil {
prepareSheetPr(ws)
ws.SheetPr.EnableFormatConditionsCalculation = opts.EnableFormatConditionsCalculation
}
if opts.Published != nil {
prepareSheetPr(ws)
ws.SheetPr.Published = opts.Published
}
if opts.AutoPageBreaks != nil {
preparePageSetUpPr(ws)
ws.SheetPr.PageSetUpPr.AutoPageBreaks = *opts.AutoPageBreaks
}
if opts.FitToPage != nil {
preparePageSetUpPr(ws)
ws.SheetPr.PageSetUpPr.FitToPage = *opts.FitToPage
}
if opts.OutlineSummaryBelow != nil {
prepareOutlinePr(ws)
ws.SheetPr.OutlinePr.SummaryBelow = *opts.OutlineSummaryBelow
}
if opts.TabColorIndexed != nil {
prepareTabColor(ws)
ws.SheetPr.TabColor.Indexed = *opts.TabColorIndexed
}
if opts.TabColorRGB != nil {
prepareTabColor(ws)
ws.SheetPr.TabColor.RGB = *opts.TabColorRGB
}
if opts.TabColorTheme != nil {
prepareTabColor(ws)
ws.SheetPr.TabColor.Theme = *opts.TabColorTheme
}
if opts.TabColorTint != nil {
prepareTabColor(ws)
ws.SheetPr.TabColor.Tint = *opts.TabColorTint
}
}
// SetSheetProps provides a function to set worksheet properties.
func (f *File) SetSheetProps(sheet string, opts *SheetPropsOptions) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
pm := s.PageMargins
for _, opt := range opts {
opt.getPageMargins(pm)
if opts == nil {
return err
}
ws.setSheetProps(opts)
if ws.SheetFormatPr == nil {
ws.SheetFormatPr = &xlsxSheetFormatPr{DefaultRowHeight: defaultRowHeight}
}
if opts.BaseColWidth != nil {
ws.SheetFormatPr.BaseColWidth = *opts.BaseColWidth
}
if opts.DefaultColWidth != nil {
ws.SheetFormatPr.DefaultColWidth = *opts.DefaultColWidth
}
if opts.DefaultRowHeight != nil {
ws.SheetFormatPr.DefaultRowHeight = *opts.DefaultRowHeight
}
if opts.CustomHeight != nil {
ws.SheetFormatPr.CustomHeight = *opts.CustomHeight
}
if opts.ZeroHeight != nil {
ws.SheetFormatPr.ZeroHeight = *opts.ZeroHeight
}
if opts.ThickTop != nil {
ws.SheetFormatPr.ThickTop = *opts.ThickTop
}
if opts.ThickBottom != nil {
ws.SheetFormatPr.ThickBottom = *opts.ThickBottom
}
return err
}
// SheetFormatPrOptions is an option of the formatting properties of a
// worksheet. See SetSheetFormatPr().
type SheetFormatPrOptions interface {
setSheetFormatPr(formatPr *xlsxSheetFormatPr)
}
// SheetFormatPrOptionsPtr is a writable SheetFormatPrOptions. See
// GetSheetFormatPr().
type SheetFormatPrOptionsPtr interface {
SheetFormatPrOptions
getSheetFormatPr(formatPr *xlsxSheetFormatPr)
}
type (
// BaseColWidth specifies the number of characters of the maximum digit width
// of the normal style's font. This value does not include margin padding or
// extra padding for gridlines. It is only the number of characters.
BaseColWidth uint8
// DefaultColWidth specifies the default column width measured as the number
// of characters of the maximum digit width of the normal style's font.
DefaultColWidth float64
// DefaultRowHeight specifies the default row height measured in point size.
// Optimization so we don't have to write the height on all rows. This can be
// written out if most rows have custom height, to achieve the optimization.
DefaultRowHeight float64
// CustomHeight specifies the custom height.
CustomHeight bool
// ZeroHeight specifies if rows are hidden.
ZeroHeight bool
// ThickTop specifies if rows have a thick top border by default.
ThickTop bool
// ThickBottom specifies if rows have a thick bottom border by default.
ThickBottom bool
)
// setSheetFormatPr provides a method to set the number of characters of the
// maximum digit width of the normal style's font.
func (p BaseColWidth) setSheetFormatPr(fp *xlsxSheetFormatPr) {
fp.BaseColWidth = uint8(p)
}
// setSheetFormatPr provides a method to set the number of characters of the
// maximum digit width of the normal style's font.
func (p *BaseColWidth) getSheetFormatPr(fp *xlsxSheetFormatPr) {
if fp == nil {
*p = 0
return
// GetSheetProps provides a function to get worksheet properties.
func (f *File) GetSheetProps(sheet string) (SheetPropsOptions, error) {
baseColWidth := uint8(8)
opts := SheetPropsOptions{
EnableFormatConditionsCalculation: boolPtr(true),
Published: boolPtr(true),
AutoPageBreaks: boolPtr(true),
OutlineSummaryBelow: boolPtr(true),
BaseColWidth: &baseColWidth,
}
*p = BaseColWidth(fp.BaseColWidth)
}
// setSheetFormatPr provides a method to set the default column width measured
// as the number of characters of the maximum digit width of the normal
// style's font.
func (p DefaultColWidth) setSheetFormatPr(fp *xlsxSheetFormatPr) {
fp.DefaultColWidth = float64(p)
}
// getSheetFormatPr provides a method to get the default column width measured
// as the number of characters of the maximum digit width of the normal
// style's font.
func (p *DefaultColWidth) getSheetFormatPr(fp *xlsxSheetFormatPr) {
if fp == nil {
*p = 0
return
}
*p = DefaultColWidth(fp.DefaultColWidth)
}
// setSheetFormatPr provides a method to set the default row height measured
// in point size.
func (p DefaultRowHeight) setSheetFormatPr(fp *xlsxSheetFormatPr) {
fp.DefaultRowHeight = float64(p)
}
// getSheetFormatPr provides a method to get the default row height measured
// in point size.
func (p *DefaultRowHeight) getSheetFormatPr(fp *xlsxSheetFormatPr) {
if fp == nil {
*p = 15
return
}
*p = DefaultRowHeight(fp.DefaultRowHeight)
}
// setSheetFormatPr provides a method to set the custom height.
func (p CustomHeight) setSheetFormatPr(fp *xlsxSheetFormatPr) {
fp.CustomHeight = bool(p)
}
// getSheetFormatPr provides a method to get the custom height.
func (p *CustomHeight) getSheetFormatPr(fp *xlsxSheetFormatPr) {
if fp == nil {
*p = false
return
}
*p = CustomHeight(fp.CustomHeight)
}
// setSheetFormatPr provides a method to set if rows are hidden.
func (p ZeroHeight) setSheetFormatPr(fp *xlsxSheetFormatPr) {
fp.ZeroHeight = bool(p)
}
// getSheetFormatPr provides a method to get if rows are hidden.
func (p *ZeroHeight) getSheetFormatPr(fp *xlsxSheetFormatPr) {
if fp == nil {
*p = false
return
}
*p = ZeroHeight(fp.ZeroHeight)
}
// setSheetFormatPr provides a method to set if rows have a thick top border
// by default.
func (p ThickTop) setSheetFormatPr(fp *xlsxSheetFormatPr) {
fp.ThickTop = bool(p)
}
// getSheetFormatPr provides a method to get if rows have a thick top border
// by default.
func (p *ThickTop) getSheetFormatPr(fp *xlsxSheetFormatPr) {
if fp == nil {
*p = false
return
}
*p = ThickTop(fp.ThickTop)
}
// setSheetFormatPr provides a method to set if rows have a thick bottom
// border by default.
func (p ThickBottom) setSheetFormatPr(fp *xlsxSheetFormatPr) {
fp.ThickBottom = bool(p)
}
// setSheetFormatPr provides a method to set if rows have a thick bottom
// border by default.
func (p *ThickBottom) getSheetFormatPr(fp *xlsxSheetFormatPr) {
if fp == nil {
*p = false
return
}
*p = ThickBottom(fp.ThickBottom)
}
// SetSheetFormatPr provides a function to set worksheet formatting properties.
//
// Available options:
//
// BaseColWidth(uint8)
// DefaultColWidth(float64)
// DefaultRowHeight(float64)
// CustomHeight(bool)
// ZeroHeight(bool)
// ThickTop(bool)
// ThickBottom(bool)
func (f *File) SetSheetFormatPr(sheet string, opts ...SheetFormatPrOptions) error {
s, err := f.workSheetReader(sheet)
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
return opts, err
}
fp := s.SheetFormatPr
if fp == nil {
fp = new(xlsxSheetFormatPr)
s.SheetFormatPr = fp
if ws.SheetPr != nil {
opts.CodeName = stringPtr(ws.SheetPr.CodeName)
if ws.SheetPr.EnableFormatConditionsCalculation != nil {
opts.EnableFormatConditionsCalculation = ws.SheetPr.EnableFormatConditionsCalculation
}
if ws.SheetPr.Published != nil {
opts.Published = ws.SheetPr.Published
}
if ws.SheetPr.PageSetUpPr != nil {
opts.AutoPageBreaks = boolPtr(ws.SheetPr.PageSetUpPr.AutoPageBreaks)
opts.FitToPage = boolPtr(ws.SheetPr.PageSetUpPr.FitToPage)
}
if ws.SheetPr.OutlinePr != nil {
opts.OutlineSummaryBelow = boolPtr(ws.SheetPr.OutlinePr.SummaryBelow)
}
if ws.SheetPr.TabColor != nil {
opts.TabColorIndexed = intPtr(ws.SheetPr.TabColor.Indexed)
opts.TabColorRGB = stringPtr(ws.SheetPr.TabColor.RGB)
opts.TabColorTheme = intPtr(ws.SheetPr.TabColor.Theme)
opts.TabColorTint = float64Ptr(ws.SheetPr.TabColor.Tint)
}
}
for _, opt := range opts {
opt.setSheetFormatPr(fp)
if ws.SheetFormatPr != nil {
opts.BaseColWidth = &ws.SheetFormatPr.BaseColWidth
opts.DefaultColWidth = float64Ptr(ws.SheetFormatPr.DefaultColWidth)
opts.DefaultRowHeight = float64Ptr(ws.SheetFormatPr.DefaultRowHeight)
opts.CustomHeight = boolPtr(ws.SheetFormatPr.CustomHeight)
opts.ZeroHeight = boolPtr(ws.SheetFormatPr.ZeroHeight)
opts.ThickTop = boolPtr(ws.SheetFormatPr.ThickTop)
opts.ThickBottom = boolPtr(ws.SheetFormatPr.ThickBottom)
}
return err
}
// GetSheetFormatPr provides a function to get worksheet formatting properties.
//
// Available options:
//
// BaseColWidth(uint8)
// DefaultColWidth(float64)
// DefaultRowHeight(float64)
// CustomHeight(bool)
// ZeroHeight(bool)
// ThickTop(bool)
// ThickBottom(bool)
func (f *File) GetSheetFormatPr(sheet string, opts ...SheetFormatPrOptionsPtr) error {
s, err := f.workSheetReader(sheet)
if err != nil {
return err
}
fp := s.SheetFormatPr
for _, opt := range opts {
opt.getSheetFormatPr(fp)
}
return err
return opts, err
}

View File

@ -1,501 +1,107 @@
package excelize
import (
"fmt"
"path/filepath"
"testing"
"github.com/mohae/deepcopy"
"github.com/stretchr/testify/assert"
)
var _ = []SheetPrOption{
CodeName("hello"),
EnableFormatConditionsCalculation(false),
Published(false),
FitToPage(true),
TabColorIndexed(42),
TabColorRGB("#FFFF00"),
TabColorTheme(ColorMappingTypeLight2),
TabColorTint(0.5),
AutoPageBreaks(true),
OutlineSummaryBelow(true),
}
var _ = []SheetPrOptionPtr{
(*CodeName)(nil),
(*EnableFormatConditionsCalculation)(nil),
(*Published)(nil),
(*FitToPage)(nil),
(*TabColorIndexed)(nil),
(*TabColorRGB)(nil),
(*TabColorTheme)(nil),
(*TabColorTint)(nil),
(*AutoPageBreaks)(nil),
(*OutlineSummaryBelow)(nil),
}
func ExampleFile_SetSheetPrOptions() {
f := NewFile()
const sheet = "Sheet1"
if err := f.SetSheetPrOptions(sheet,
CodeName("code"),
EnableFormatConditionsCalculation(false),
Published(false),
FitToPage(true),
TabColorIndexed(42),
TabColorRGB("#FFFF00"),
TabColorTheme(ColorMappingTypeLight2),
TabColorTint(0.5),
AutoPageBreaks(true),
OutlineSummaryBelow(false),
); err != nil {
fmt.Println(err)
}
// Output:
}
func ExampleFile_GetSheetPrOptions() {
f := NewFile()
const sheet = "Sheet1"
var (
codeName CodeName
enableFormatConditionsCalculation EnableFormatConditionsCalculation
published Published
fitToPage FitToPage
tabColorIndexed TabColorIndexed
tabColorRGB TabColorRGB
tabColorTheme TabColorTheme
tabColorTint TabColorTint
autoPageBreaks AutoPageBreaks
outlineSummaryBelow OutlineSummaryBelow
)
if err := f.GetSheetPrOptions(sheet,
&codeName,
&enableFormatConditionsCalculation,
&published,
&fitToPage,
&tabColorIndexed,
&tabColorRGB,
&tabColorTheme,
&tabColorTint,
&autoPageBreaks,
&outlineSummaryBelow,
); err != nil {
fmt.Println(err)
}
fmt.Println("Defaults:")
fmt.Printf("- codeName: %q\n", codeName)
fmt.Println("- enableFormatConditionsCalculation:", enableFormatConditionsCalculation)
fmt.Println("- published:", published)
fmt.Println("- fitToPage:", fitToPage)
fmt.Printf("- tabColorIndexed: %d\n", tabColorIndexed)
fmt.Printf("- tabColorRGB: %q\n", tabColorRGB)
fmt.Printf("- tabColorTheme: %d\n", tabColorTheme)
fmt.Printf("- tabColorTint: %f\n", tabColorTint)
fmt.Println("- autoPageBreaks:", autoPageBreaks)
fmt.Println("- outlineSummaryBelow:", outlineSummaryBelow)
// Output:
// Defaults:
// - codeName: ""
// - enableFormatConditionsCalculation: true
// - published: true
// - fitToPage: false
// - tabColorIndexed: -1
// - tabColorRGB: ""
// - tabColorTheme: -1
// - tabColorTint: 0.000000
// - autoPageBreaks: false
// - outlineSummaryBelow: true
}
func TestSheetPrOptions(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
container SheetPrOptionPtr
nonDefault SheetPrOption
}{
{new(CodeName), CodeName("xx")},
{new(EnableFormatConditionsCalculation), EnableFormatConditionsCalculation(false)},
{new(Published), Published(false)},
{new(FitToPage), FitToPage(true)},
{new(TabColorIndexed), TabColorIndexed(42)},
{new(TabColorRGB), TabColorRGB("FFFF00")},
{new(TabColorTheme), TabColorTheme(ColorMappingTypeLight2)},
{new(TabColorTint), TabColorTint(0.5)},
{new(AutoPageBreaks), AutoPageBreaks(true)},
{new(OutlineSummaryBelow), OutlineSummaryBelow(false)},
}
for i, test := range testData {
t.Run(fmt.Sprintf("TestData%d", i), func(t *testing.T) {
opts := test.nonDefault
t.Logf("option %T", opts)
def := deepcopy.Copy(test.container).(SheetPrOptionPtr)
val1 := deepcopy.Copy(def).(SheetPrOptionPtr)
val2 := deepcopy.Copy(def).(SheetPrOptionPtr)
f := NewFile()
// Get the default value
assert.NoError(t, f.GetSheetPrOptions(sheet, def), opts)
// Get again and check
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opts)
if !assert.Equal(t, val1, def, opts) {
t.FailNow()
}
// Set the same value
assert.NoError(t, f.SetSheetPrOptions(sheet, val1), opts)
// Get again and check
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opts)
if !assert.Equal(t, val1, def, "%T: value should not have changed", opts) {
t.FailNow()
}
// Set a different value
assert.NoError(t, f.SetSheetPrOptions(sheet, test.nonDefault), opts)
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opts)
// Get again and compare
assert.NoError(t, f.GetSheetPrOptions(sheet, val2), opts)
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opts) {
t.FailNow()
}
// Value should not be the same as the default
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opts) {
t.FailNow()
}
// Restore the default value
assert.NoError(t, f.SetSheetPrOptions(sheet, def), opts)
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opts)
if !assert.Equal(t, def, val1) {
t.FailNow()
}
})
}
}
func TestSetSheetPrOptions(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetSheetPrOptions("Sheet1", TabColorRGB("")))
// Test SetSheetPrOptions on not exists worksheet.
assert.EqualError(t, f.SetSheetPrOptions("SheetN"), "sheet SheetN does not exist")
}
func TestGetSheetPrOptions(t *testing.T) {
f := NewFile()
// Test GetSheetPrOptions on not exists worksheet.
assert.EqualError(t, f.GetSheetPrOptions("SheetN"), "sheet SheetN does not exist")
}
var _ = []PageMarginsOptions{
PageMarginBottom(1.0),
PageMarginFooter(1.0),
PageMarginHeader(1.0),
PageMarginLeft(1.0),
PageMarginRight(1.0),
PageMarginTop(1.0),
}
var _ = []PageMarginsOptionsPtr{
(*PageMarginBottom)(nil),
(*PageMarginFooter)(nil),
(*PageMarginHeader)(nil),
(*PageMarginLeft)(nil),
(*PageMarginRight)(nil),
(*PageMarginTop)(nil),
}
func ExampleFile_SetPageMargins() {
f := NewFile()
const sheet = "Sheet1"
if err := f.SetPageMargins(sheet,
PageMarginBottom(1.0),
PageMarginFooter(1.0),
PageMarginHeader(1.0),
PageMarginLeft(1.0),
PageMarginRight(1.0),
PageMarginTop(1.0),
); err != nil {
fmt.Println(err)
}
// Output:
}
func ExampleFile_GetPageMargins() {
f := NewFile()
const sheet = "Sheet1"
var (
marginBottom PageMarginBottom
marginFooter PageMarginFooter
marginHeader PageMarginHeader
marginLeft PageMarginLeft
marginRight PageMarginRight
marginTop PageMarginTop
)
if err := f.GetPageMargins(sheet,
&marginBottom,
&marginFooter,
&marginHeader,
&marginLeft,
&marginRight,
&marginTop,
); err != nil {
fmt.Println(err)
}
fmt.Println("Defaults:")
fmt.Println("- marginBottom:", marginBottom)
fmt.Println("- marginFooter:", marginFooter)
fmt.Println("- marginHeader:", marginHeader)
fmt.Println("- marginLeft:", marginLeft)
fmt.Println("- marginRight:", marginRight)
fmt.Println("- marginTop:", marginTop)
// Output:
// Defaults:
// - marginBottom: 0.75
// - marginFooter: 0.3
// - marginHeader: 0.3
// - marginLeft: 0.7
// - marginRight: 0.7
// - marginTop: 0.75
}
func TestPageMarginsOption(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
container PageMarginsOptionsPtr
nonDefault PageMarginsOptions
}{
{new(PageMarginTop), PageMarginTop(1.0)},
{new(PageMarginBottom), PageMarginBottom(1.0)},
{new(PageMarginLeft), PageMarginLeft(1.0)},
{new(PageMarginRight), PageMarginRight(1.0)},
{new(PageMarginHeader), PageMarginHeader(1.0)},
{new(PageMarginFooter), PageMarginFooter(1.0)},
}
for i, test := range testData {
t.Run(fmt.Sprintf("TestData%d", i), func(t *testing.T) {
opts := test.nonDefault
t.Logf("option %T", opts)
def := deepcopy.Copy(test.container).(PageMarginsOptionsPtr)
val1 := deepcopy.Copy(def).(PageMarginsOptionsPtr)
val2 := deepcopy.Copy(def).(PageMarginsOptionsPtr)
f := NewFile()
// Get the default value
assert.NoError(t, f.GetPageMargins(sheet, def), opts)
// Get again and check
assert.NoError(t, f.GetPageMargins(sheet, val1), opts)
if !assert.Equal(t, val1, def, opts) {
t.FailNow()
}
// Set the same value
assert.NoError(t, f.SetPageMargins(sheet, val1), opts)
// Get again and check
assert.NoError(t, f.GetPageMargins(sheet, val1), opts)
if !assert.Equal(t, val1, def, "%T: value should not have changed", opts) {
t.FailNow()
}
// Set a different value
assert.NoError(t, f.SetPageMargins(sheet, test.nonDefault), opts)
assert.NoError(t, f.GetPageMargins(sheet, val1), opts)
// Get again and compare
assert.NoError(t, f.GetPageMargins(sheet, val2), opts)
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opts) {
t.FailNow()
}
// Value should not be the same as the default
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opts) {
t.FailNow()
}
// Restore the default value
assert.NoError(t, f.SetPageMargins(sheet, def), opts)
assert.NoError(t, f.GetPageMargins(sheet, val1), opts)
if !assert.Equal(t, def, val1) {
t.FailNow()
}
})
}
}
func TestSetPageMargins(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetPageMargins("Sheet1", nil))
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).PageMargins = nil
ws.(*xlsxWorksheet).PrintOptions = nil
expected := PageLayoutMarginsOptions{
Bottom: float64Ptr(1.0),
Footer: float64Ptr(1.0),
Header: float64Ptr(1.0),
Left: float64Ptr(1.0),
Right: float64Ptr(1.0),
Top: float64Ptr(1.0),
Horizontally: boolPtr(true),
Vertically: boolPtr(true),
}
assert.NoError(t, f.SetPageMargins("Sheet1", &expected))
opts, err := f.GetPageMargins("Sheet1")
assert.NoError(t, err)
assert.Equal(t, expected, opts)
// Test set page margins on not exists worksheet.
assert.EqualError(t, f.SetPageMargins("SheetN"), "sheet SheetN does not exist")
assert.EqualError(t, f.SetPageMargins("SheetN", nil), "sheet SheetN does not exist")
}
func TestGetPageMargins(t *testing.T) {
f := NewFile()
// Test get page margins on not exists worksheet.
assert.EqualError(t, f.GetPageMargins("SheetN"), "sheet SheetN does not exist")
_, err := f.GetPageMargins("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
}
func ExampleFile_SetSheetFormatPr() {
func TestDebug(t *testing.T) {
f := NewFile()
const sheet = "Sheet1"
if err := f.SetSheetFormatPr(sheet,
BaseColWidth(1.0),
DefaultColWidth(1.0),
DefaultRowHeight(1.0),
CustomHeight(true),
ZeroHeight(true),
ThickTop(true),
ThickBottom(true),
); err != nil {
fmt.Println(err)
}
// Output:
}
func ExampleFile_GetSheetFormatPr() {
f := NewFile()
const sheet = "Sheet1"
var (
baseColWidth BaseColWidth
defaultColWidth DefaultColWidth
defaultRowHeight DefaultRowHeight
customHeight CustomHeight
zeroHeight ZeroHeight
thickTop ThickTop
thickBottom ThickBottom
)
if err := f.GetSheetFormatPr(sheet,
&baseColWidth,
&defaultColWidth,
&defaultRowHeight,
&customHeight,
&zeroHeight,
&thickTop,
&thickBottom,
); err != nil {
fmt.Println(err)
}
fmt.Println("Defaults:")
fmt.Println("- baseColWidth:", baseColWidth)
fmt.Println("- defaultColWidth:", defaultColWidth)
fmt.Println("- defaultRowHeight:", defaultRowHeight)
fmt.Println("- customHeight:", customHeight)
fmt.Println("- zeroHeight:", zeroHeight)
fmt.Println("- thickTop:", thickTop)
fmt.Println("- thickBottom:", thickBottom)
// Output:
// Defaults:
// - baseColWidth: 0
// - defaultColWidth: 0
// - defaultRowHeight: 15
// - customHeight: false
// - zeroHeight: false
// - thickTop: false
// - thickBottom: false
}
func TestSheetFormatPrOptions(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
container SheetFormatPrOptionsPtr
nonDefault SheetFormatPrOptions
}{
{new(BaseColWidth), BaseColWidth(1.0)},
{new(DefaultColWidth), DefaultColWidth(1.0)},
{new(DefaultRowHeight), DefaultRowHeight(1.0)},
{new(CustomHeight), CustomHeight(true)},
{new(ZeroHeight), ZeroHeight(true)},
{new(ThickTop), ThickTop(true)},
{new(ThickBottom), ThickBottom(true)},
}
for i, test := range testData {
t.Run(fmt.Sprintf("TestData%d", i), func(t *testing.T) {
opts := test.nonDefault
t.Logf("option %T", opts)
def := deepcopy.Copy(test.container).(SheetFormatPrOptionsPtr)
val1 := deepcopy.Copy(def).(SheetFormatPrOptionsPtr)
val2 := deepcopy.Copy(def).(SheetFormatPrOptionsPtr)
f := NewFile()
// Get the default value
assert.NoError(t, f.GetSheetFormatPr(sheet, def), opts)
// Get again and check
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opts)
if !assert.Equal(t, val1, def, opts) {
t.FailNow()
}
// Set the same value
assert.NoError(t, f.SetSheetFormatPr(sheet, val1), opts)
// Get again and check
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opts)
if !assert.Equal(t, val1, def, "%T: value should not have changed", opts) {
t.FailNow()
}
// Set a different value
assert.NoError(t, f.SetSheetFormatPr(sheet, test.nonDefault), opts)
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opts)
// Get again and compare
assert.NoError(t, f.GetSheetFormatPr(sheet, val2), opts)
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opts) {
t.FailNow()
}
// Value should not be the same as the default
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opts) {
t.FailNow()
}
// Restore the default value
assert.NoError(t, f.SetSheetFormatPr(sheet, def), opts)
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opts)
if !assert.Equal(t, def, val1) {
t.FailNow()
}
})
}
}
func TestSetSheetFormatPr(t *testing.T) {
f := NewFile()
assert.NoError(t, f.GetSheetFormatPr("Sheet1"))
assert.NoError(t, f.SetSheetProps("Sheet1", nil))
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).PageMargins = nil
ws.(*xlsxWorksheet).PrintOptions = nil
ws.(*xlsxWorksheet).SheetPr = nil
ws.(*xlsxWorksheet).SheetFormatPr = nil
assert.NoError(t, f.SetSheetFormatPr("Sheet1", BaseColWidth(1.0)))
// Test set formatting properties on not exists worksheet.
assert.EqualError(t, f.SetSheetFormatPr("SheetN"), "sheet SheetN does not exist")
// w := uint8(10)
// f.SetSheetProps("Sheet1", &SheetPropsOptions{BaseColWidth: &w})
f.SetPageMargins("Sheet1", &PageLayoutMarginsOptions{Horizontally: boolPtr(true)})
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDebug.xlsx")))
}
func TestGetSheetFormatPr(t *testing.T) {
func TestSetSheetProps(t *testing.T) {
f := NewFile()
assert.NoError(t, f.GetSheetFormatPr("Sheet1"))
assert.NoError(t, f.SetSheetProps("Sheet1", nil))
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).SheetPr = nil
ws.(*xlsxWorksheet).SheetFormatPr = nil
var (
baseColWidth BaseColWidth
defaultColWidth DefaultColWidth
defaultRowHeight DefaultRowHeight
customHeight CustomHeight
zeroHeight ZeroHeight
thickTop ThickTop
thickBottom ThickBottom
)
assert.NoError(t, f.GetSheetFormatPr("Sheet1",
&baseColWidth,
&defaultColWidth,
&defaultRowHeight,
&customHeight,
&zeroHeight,
&thickTop,
&thickBottom,
))
// Test get formatting properties on not exists worksheet.
assert.EqualError(t, f.GetSheetFormatPr("SheetN"), "sheet SheetN does not exist")
baseColWidth := uint8(8)
expected := SheetPropsOptions{
CodeName: stringPtr("code"),
EnableFormatConditionsCalculation: boolPtr(true),
Published: boolPtr(true),
AutoPageBreaks: boolPtr(true),
FitToPage: boolPtr(true),
TabColorIndexed: intPtr(1),
TabColorRGB: stringPtr("#FFFF00"),
TabColorTheme: intPtr(1),
TabColorTint: float64Ptr(1),
OutlineSummaryBelow: boolPtr(true),
BaseColWidth: &baseColWidth,
DefaultColWidth: float64Ptr(10),
DefaultRowHeight: float64Ptr(10),
CustomHeight: boolPtr(true),
ZeroHeight: boolPtr(true),
ThickTop: boolPtr(true),
ThickBottom: boolPtr(true),
}
assert.NoError(t, f.SetSheetProps("Sheet1", &expected))
opts, err := f.GetSheetProps("Sheet1")
assert.NoError(t, err)
assert.Equal(t, expected, opts)
ws.(*xlsxWorksheet).SheetPr = nil
assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{FitToPage: boolPtr(true)}))
ws.(*xlsxWorksheet).SheetPr = nil
assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{TabColorRGB: stringPtr("#FFFF00")}))
ws.(*xlsxWorksheet).SheetPr = nil
assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{TabColorTheme: intPtr(1)}))
ws.(*xlsxWorksheet).SheetPr = nil
assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{TabColorTint: float64Ptr(1)}))
// Test SetSheetProps on not exists worksheet.
assert.EqualError(t, f.SetSheetProps("SheetN", nil), "sheet SheetN does not exist")
}
func TestGetSheetProps(t *testing.T) {
f := NewFile()
// Test GetSheetProps on not exists worksheet.
_, err := f.GetSheetProps("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
}

View File

@ -13,150 +13,6 @@ package excelize
import "fmt"
// SheetViewOption is an option of a view of a worksheet. See
// SetSheetViewOptions().
type SheetViewOption interface {
setSheetViewOption(view *xlsxSheetView)
}
// SheetViewOptionPtr is a writable SheetViewOption. See
// GetSheetViewOptions().
type SheetViewOptionPtr interface {
SheetViewOption
getSheetViewOption(view *xlsxSheetView)
}
type (
// DefaultGridColor is a SheetViewOption. It specifies a flag indicating
// that the consuming application should use the default grid lines color
// (system dependent). Overrides any color specified in colorId.
DefaultGridColor bool
// ShowFormulas is a SheetViewOption. It specifies a flag indicating
// whether this sheet should display formulas.
ShowFormulas bool
// ShowGridLines is a SheetViewOption. It specifies a flag indicating
// whether this sheet should display gridlines.
ShowGridLines bool
// ShowRowColHeaders is a SheetViewOption. It specifies a flag indicating
// whether the sheet should display row and column headings.
ShowRowColHeaders bool
// ShowZeros is a SheetViewOption. It specifies a flag indicating whether
// to "show a zero in cells that have zero value". When using a formula to
// reference another cell which is empty, the referenced value becomes 0
// when the flag is true. (Default setting is true.)
ShowZeros bool
// RightToLeft is a SheetViewOption. It specifies a flag indicating whether
// the sheet is in 'right to left' display mode. When in this mode, Column
// A is on the far right, Column B ;is one column left of Column A, and so
// on. Also, information in cells is displayed in the Right to Left format.
RightToLeft bool
// ShowRuler is a SheetViewOption. It specifies a flag indicating this
// sheet should display ruler.
ShowRuler bool
// View is a SheetViewOption. It specifies a flag indicating how sheet is
// displayed, by default it uses empty string available options: normal,
// pageLayout, pageBreakPreview
View string
// TopLeftCell is a SheetViewOption. It specifies a location of the top
// left visible cell Location of the top left visible cell in the bottom
// right pane (when in Left-to-Right mode).
TopLeftCell string
// ZoomScale is a SheetViewOption. It specifies a window zoom magnification
// for current view representing percent values. This attribute is
// restricted to values ranging from 10 to 400. Horizontal & Vertical
// scale together.
ZoomScale float64
)
// Defaults for each option are described in XML schema for CT_SheetView
func (o DefaultGridColor) setSheetViewOption(view *xlsxSheetView) {
view.DefaultGridColor = boolPtr(bool(o))
}
func (o *DefaultGridColor) getSheetViewOption(view *xlsxSheetView) {
*o = DefaultGridColor(defaultTrue(view.DefaultGridColor)) // Excel default: true
}
func (o ShowFormulas) setSheetViewOption(view *xlsxSheetView) {
view.ShowFormulas = bool(o) // Excel default: false
}
func (o *ShowFormulas) getSheetViewOption(view *xlsxSheetView) {
*o = ShowFormulas(view.ShowFormulas) // Excel default: false
}
func (o ShowGridLines) setSheetViewOption(view *xlsxSheetView) {
view.ShowGridLines = boolPtr(bool(o))
}
func (o *ShowGridLines) getSheetViewOption(view *xlsxSheetView) {
*o = ShowGridLines(defaultTrue(view.ShowGridLines)) // Excel default: true
}
func (o ShowRowColHeaders) setSheetViewOption(view *xlsxSheetView) {
view.ShowRowColHeaders = boolPtr(bool(o))
}
func (o *ShowRowColHeaders) getSheetViewOption(view *xlsxSheetView) {
*o = ShowRowColHeaders(defaultTrue(view.ShowRowColHeaders)) // Excel default: true
}
func (o ShowZeros) setSheetViewOption(view *xlsxSheetView) {
view.ShowZeros = boolPtr(bool(o))
}
func (o *ShowZeros) getSheetViewOption(view *xlsxSheetView) {
*o = ShowZeros(defaultTrue(view.ShowZeros)) // Excel default: true
}
func (o RightToLeft) setSheetViewOption(view *xlsxSheetView) {
view.RightToLeft = bool(o) // Excel default: false
}
func (o *RightToLeft) getSheetViewOption(view *xlsxSheetView) {
*o = RightToLeft(view.RightToLeft)
}
func (o ShowRuler) setSheetViewOption(view *xlsxSheetView) {
view.ShowRuler = boolPtr(bool(o))
}
func (o *ShowRuler) getSheetViewOption(view *xlsxSheetView) {
*o = ShowRuler(defaultTrue(view.ShowRuler)) // Excel default: true
}
func (o View) setSheetViewOption(view *xlsxSheetView) {
view.View = string(o)
}
func (o *View) getSheetViewOption(view *xlsxSheetView) {
if view.View != "" {
*o = View(view.View)
return
}
*o = "normal"
}
func (o TopLeftCell) setSheetViewOption(view *xlsxSheetView) {
view.TopLeftCell = string(o)
}
func (o *TopLeftCell) getSheetViewOption(view *xlsxSheetView) {
*o = TopLeftCell(view.TopLeftCell)
}
func (o ZoomScale) setSheetViewOption(view *xlsxSheetView) {
// This attribute is restricted to values ranging from 10 to 400.
if float64(o) >= 10 && float64(o) <= 400 {
view.ZoomScale = float64(o)
}
}
func (o *ZoomScale) getSheetViewOption(view *xlsxSheetView) {
*o = ZoomScale(view.ZoomScale)
}
// getSheetView returns the SheetView object
func (f *File) getSheetView(sheet string, viewIndex int) (*xlsxSheetView, error) {
ws, err := f.workSheetReader(sheet)
@ -180,65 +36,100 @@ func (f *File) getSheetView(sheet string, viewIndex int) (*xlsxSheetView, error)
return &(ws.SheetViews.SheetView[viewIndex]), err
}
// SetSheetViewOptions sets sheet view options. The viewIndex may be negative
// and if so is counted backward (-1 is the last view).
//
// Available options:
//
// DefaultGridColor(bool)
// ShowFormulas(bool)
// ShowGridLines(bool)
// ShowRowColHeaders(bool)
// ShowZeros(bool)
// RightToLeft(bool)
// ShowRuler(bool)
// View(string)
// TopLeftCell(string)
// ZoomScale(float64)
//
// Example:
//
// err = f.SetSheetViewOptions("Sheet1", -1, ShowGridLines(false))
func (f *File) SetSheetViewOptions(sheet string, viewIndex int, opts ...SheetViewOption) error {
// setSheetView set sheet view by given options.
func (view *xlsxSheetView) setSheetView(opts *ViewOptions) {
if opts.DefaultGridColor != nil {
view.DefaultGridColor = opts.DefaultGridColor
}
if opts.RightToLeft != nil {
view.RightToLeft = *opts.RightToLeft
}
if opts.ShowFormulas != nil {
view.ShowFormulas = *opts.ShowFormulas
}
if opts.ShowGridLines != nil {
view.ShowGridLines = opts.ShowGridLines
}
if opts.ShowRowColHeaders != nil {
view.ShowRowColHeaders = opts.ShowRowColHeaders
}
if opts.ShowRuler != nil {
view.ShowRuler = opts.ShowRuler
}
if opts.ShowZeros != nil {
view.ShowZeros = opts.ShowZeros
}
if opts.TopLeftCell != nil {
view.TopLeftCell = *opts.TopLeftCell
}
if opts.View != nil {
if _, ok := map[string]interface{}{
"normal": nil,
"pageLayout": nil,
"pageBreakPreview": nil,
}[*opts.View]; ok {
view.View = *opts.View
}
}
if opts.ZoomScale != nil && *opts.ZoomScale >= 10 && *opts.ZoomScale <= 400 {
view.ZoomScale = *opts.ZoomScale
}
}
// SetSheetView sets sheet view options. The viewIndex may be negative and if
// so is counted backward (-1 is the last view).
func (f *File) SetSheetView(sheet string, viewIndex int, opts *ViewOptions) error {
view, err := f.getSheetView(sheet, viewIndex)
if err != nil {
return err
}
for _, opt := range opts {
opt.setSheetViewOption(view)
}
return nil
}
// GetSheetViewOptions gets the value of sheet view options. The viewIndex may
// be negative and if so is counted backward (-1 is the last view).
//
// Available options:
//
// DefaultGridColor(bool)
// ShowFormulas(bool)
// ShowGridLines(bool)
// ShowRowColHeaders(bool)
// ShowZeros(bool)
// RightToLeft(bool)
// ShowRuler(bool)
// View(string)
// TopLeftCell(string)
// ZoomScale(float64)
//
// Example:
//
// var showGridLines excelize.ShowGridLines
// err = f.GetSheetViewOptions("Sheet1", -1, &showGridLines)
func (f *File) GetSheetViewOptions(sheet string, viewIndex int, opts ...SheetViewOptionPtr) error {
view, err := f.getSheetView(sheet, viewIndex)
if err != nil {
if opts == nil {
return err
}
for _, opt := range opts {
opt.getSheetViewOption(view)
}
view.setSheetView(opts)
return nil
}
// GetSheetView gets the value of sheet view options. The viewIndex may be
// negative and if so is counted backward (-1 is the last view).
func (f *File) GetSheetView(sheet string, viewIndex int) (ViewOptions, error) {
opts := ViewOptions{
DefaultGridColor: boolPtr(true),
ShowFormulas: boolPtr(true),
ShowGridLines: boolPtr(true),
ShowRowColHeaders: boolPtr(true),
ShowRuler: boolPtr(true),
ShowZeros: boolPtr(true),
View: stringPtr("normal"),
ZoomScale: float64Ptr(100),
}
view, err := f.getSheetView(sheet, viewIndex)
if err != nil {
return opts, err
}
if view.DefaultGridColor != nil {
opts.DefaultGridColor = view.DefaultGridColor
}
opts.RightToLeft = boolPtr(view.RightToLeft)
opts.ShowFormulas = boolPtr(view.ShowFormulas)
if view.ShowGridLines != nil {
opts.ShowGridLines = view.ShowGridLines
}
if view.ShowRowColHeaders != nil {
opts.ShowRowColHeaders = view.ShowRowColHeaders
}
if view.ShowRuler != nil {
opts.ShowRuler = view.ShowRuler
}
if view.ShowZeros != nil {
opts.ShowZeros = view.ShowZeros
}
opts.TopLeftCell = stringPtr(view.TopLeftCell)
if view.View != "" {
opts.View = stringPtr(view.View)
}
if view.ZoomScale >= 10 && view.ZoomScale <= 400 {
opts.ZoomScale = float64Ptr(view.ZoomScale)
}
return opts, err
}

View File

@ -1,218 +1,50 @@
package excelize
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
var _ = []SheetViewOption{
DefaultGridColor(true),
ShowFormulas(false),
ShowGridLines(true),
ShowRowColHeaders(true),
ShowZeros(true),
RightToLeft(false),
ShowRuler(false),
View("pageLayout"),
TopLeftCell("B2"),
ZoomScale(100),
// SheetViewOptionPtr are also SheetViewOption
new(DefaultGridColor),
new(ShowFormulas),
new(ShowGridLines),
new(ShowRowColHeaders),
new(ShowZeros),
new(RightToLeft),
new(ShowRuler),
new(View),
new(TopLeftCell),
new(ZoomScale),
}
var _ = []SheetViewOptionPtr{
(*DefaultGridColor)(nil),
(*ShowFormulas)(nil),
(*ShowGridLines)(nil),
(*ShowRowColHeaders)(nil),
(*ShowZeros)(nil),
(*RightToLeft)(nil),
(*ShowRuler)(nil),
(*View)(nil),
(*TopLeftCell)(nil),
(*ZoomScale)(nil),
}
func ExampleFile_SetSheetViewOptions() {
func TestSetView(t *testing.T) {
f := NewFile()
const sheet = "Sheet1"
if err := f.SetSheetViewOptions(sheet, 0,
DefaultGridColor(false),
ShowFormulas(true),
ShowGridLines(true),
ShowRowColHeaders(true),
RightToLeft(false),
ShowRuler(false),
View("pageLayout"),
TopLeftCell("C3"),
ZoomScale(80),
); err != nil {
fmt.Println(err)
}
var zoomScale ZoomScale
fmt.Println("Default:")
fmt.Println("- zoomScale: 80")
if err := f.SetSheetViewOptions(sheet, 0, ZoomScale(500)); err != nil {
fmt.Println(err)
}
if err := f.GetSheetViewOptions(sheet, 0, &zoomScale); err != nil {
fmt.Println(err)
}
fmt.Println("Used out of range value:")
fmt.Println("- zoomScale:", zoomScale)
if err := f.SetSheetViewOptions(sheet, 0, ZoomScale(123)); err != nil {
fmt.Println(err)
}
if err := f.GetSheetViewOptions(sheet, 0, &zoomScale); err != nil {
fmt.Println(err)
}
fmt.Println("Used correct value:")
fmt.Println("- zoomScale:", zoomScale)
// Output:
// Default:
// - zoomScale: 80
// Used out of range value:
// - zoomScale: 80
// Used correct value:
// - zoomScale: 123
}
func ExampleFile_GetSheetViewOptions() {
f := NewFile()
const sheet = "Sheet1"
var (
defaultGridColor DefaultGridColor
showFormulas ShowFormulas
showGridLines ShowGridLines
showRowColHeaders ShowRowColHeaders
showZeros ShowZeros
rightToLeft RightToLeft
showRuler ShowRuler
view View
topLeftCell TopLeftCell
zoomScale ZoomScale
)
if err := f.GetSheetViewOptions(sheet, 0,
&defaultGridColor,
&showFormulas,
&showGridLines,
&showRowColHeaders,
&showZeros,
&rightToLeft,
&showRuler,
&view,
&topLeftCell,
&zoomScale,
); err != nil {
fmt.Println(err)
}
fmt.Println("Default:")
fmt.Println("- defaultGridColor:", defaultGridColor)
fmt.Println("- showFormulas:", showFormulas)
fmt.Println("- showGridLines:", showGridLines)
fmt.Println("- showRowColHeaders:", showRowColHeaders)
fmt.Println("- showZeros:", showZeros)
fmt.Println("- rightToLeft:", rightToLeft)
fmt.Println("- showRuler:", showRuler)
fmt.Println("- view:", view)
fmt.Println("- topLeftCell:", `"`+topLeftCell+`"`)
fmt.Println("- zoomScale:", zoomScale)
if err := f.SetSheetViewOptions(sheet, 0, ShowGridLines(false)); err != nil {
fmt.Println(err)
}
if err := f.GetSheetViewOptions(sheet, 0, &showGridLines); err != nil {
fmt.Println(err)
}
if err := f.SetSheetViewOptions(sheet, 0, ShowZeros(false)); err != nil {
fmt.Println(err)
}
if err := f.GetSheetViewOptions(sheet, 0, &showZeros); err != nil {
fmt.Println(err)
}
if err := f.SetSheetViewOptions(sheet, 0, View("pageLayout")); err != nil {
fmt.Println(err)
}
if err := f.GetSheetViewOptions(sheet, 0, &view); err != nil {
fmt.Println(err)
}
if err := f.SetSheetViewOptions(sheet, 0, TopLeftCell("B2")); err != nil {
fmt.Println(err)
}
if err := f.GetSheetViewOptions(sheet, 0, &topLeftCell); err != nil {
fmt.Println(err)
}
fmt.Println("After change:")
fmt.Println("- showGridLines:", showGridLines)
fmt.Println("- showZeros:", showZeros)
fmt.Println("- view:", view)
fmt.Println("- topLeftCell:", topLeftCell)
// Output:
// Default:
// - defaultGridColor: true
// - showFormulas: false
// - showGridLines: true
// - showRowColHeaders: true
// - showZeros: true
// - rightToLeft: false
// - showRuler: true
// - view: normal
// - topLeftCell: ""
// - zoomScale: 0
// After change:
// - showGridLines: false
// - showZeros: false
// - view: pageLayout
// - topLeftCell: B2
}
func TestSheetViewOptionsErrors(t *testing.T) {
f := NewFile()
const sheet = "Sheet1"
assert.NoError(t, f.GetSheetViewOptions(sheet, 0))
assert.NoError(t, f.GetSheetViewOptions(sheet, -1))
assert.Error(t, f.GetSheetViewOptions(sheet, 1))
assert.Error(t, f.GetSheetViewOptions(sheet, -2))
assert.NoError(t, f.SetSheetViewOptions(sheet, 0))
assert.NoError(t, f.SetSheetViewOptions(sheet, -1))
assert.Error(t, f.SetSheetViewOptions(sheet, 1))
assert.Error(t, f.SetSheetViewOptions(sheet, -2))
assert.NoError(t, f.SetSheetView("Sheet1", -1, nil))
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).SheetViews = nil
assert.NoError(t, f.GetSheetViewOptions(sheet, 0))
expected := ViewOptions{
DefaultGridColor: boolPtr(false),
RightToLeft: boolPtr(false),
ShowFormulas: boolPtr(false),
ShowGridLines: boolPtr(false),
ShowRowColHeaders: boolPtr(false),
ShowRuler: boolPtr(false),
ShowZeros: boolPtr(false),
TopLeftCell: stringPtr("A1"),
View: stringPtr("normal"),
ZoomScale: float64Ptr(120),
}
assert.NoError(t, f.SetSheetView("Sheet1", 0, &expected))
opts, err := f.GetSheetView("Sheet1", 0)
assert.NoError(t, err)
assert.Equal(t, expected, opts)
// Test set sheet view options with invalid view index.
assert.EqualError(t, f.SetSheetView("Sheet1", 1, nil), "view index 1 out of range")
assert.EqualError(t, f.SetSheetView("Sheet1", -2, nil), "view index -2 out of range")
// Test set sheet view options on not exists worksheet.
assert.EqualError(t, f.SetSheetView("SheetN", 0, nil), "sheet SheetN does not exist")
}
func TestGetView(t *testing.T) {
f := NewFile()
_, err := f.getSheetView("SheetN", 0)
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get sheet view options with invalid view index.
_, err = f.GetSheetView("Sheet1", 1)
assert.EqualError(t, err, "view index 1 out of range")
_, err = f.GetSheetView("Sheet1", -2)
assert.EqualError(t, err, "view index -2 out of range")
// Test get sheet view options on not exists worksheet.
_, err = f.GetSheetView("SheetN", 0)
assert.EqualError(t, err, "sheet SheetN does not exist")
}

View File

@ -387,8 +387,9 @@ func (f *File) addSparklineGroupByStyle(ID int) *xlsxX14SparklineGroup {
// Markers | Toggle sparkline markers
// ColorAxis | An RGB Color is specified as RRGGBB
// Axis | Show sparkline axis
func (f *File) AddSparkline(sheet string, opts *SparklineOption) (err error) {
func (f *File) AddSparkline(sheet string, opts *SparklineOptions) error {
var (
err error
ws *xlsxWorksheet
sparkType string
sparkTypes map[string]string
@ -401,7 +402,7 @@ func (f *File) AddSparkline(sheet string, opts *SparklineOption) (err error) {
// parameter validation
if ws, err = f.parseFormatAddSparklineSet(sheet, opts); err != nil {
return
return err
}
// Handle the sparkline type
sparkType = "line"
@ -409,7 +410,7 @@ func (f *File) AddSparkline(sheet string, opts *SparklineOption) (err error) {
if opts.Type != "" {
if specifiedSparkTypes, ok = sparkTypes[opts.Type]; !ok {
err = ErrSparklineType
return
return err
}
sparkType = specifiedSparkTypes
}
@ -435,7 +436,7 @@ func (f *File) AddSparkline(sheet string, opts *SparklineOption) (err error) {
f.addSparkline(opts, group)
if ws.ExtLst.Ext != "" { // append mode ext
if err = f.appendSparkline(ws, group, groups); err != nil {
return
return err
}
} else {
groups = &xlsxX14SparklineGroups{
@ -443,23 +444,23 @@ func (f *File) AddSparkline(sheet string, opts *SparklineOption) (err error) {
SparklineGroups: []*xlsxX14SparklineGroup{group},
}
if sparklineGroupsBytes, err = xml.Marshal(groups); err != nil {
return
return err
}
if extBytes, err = xml.Marshal(&xlsxWorksheetExt{
URI: ExtURISparklineGroups,
Content: string(sparklineGroupsBytes),
}); err != nil {
return
return err
}
ws.ExtLst.Ext = string(extBytes)
}
f.addSheetNameSpace(sheet, NameSpaceSpreadSheetX14)
return
return err
}
// parseFormatAddSparklineSet provides a function to validate sparkline
// properties.
func (f *File) parseFormatAddSparklineSet(sheet string, opts *SparklineOption) (*xlsxWorksheet, error) {
func (f *File) parseFormatAddSparklineSet(sheet string, opts *SparklineOptions) (*xlsxWorksheet, error) {
ws, err := f.workSheetReader(sheet)
if err != nil {
return ws, err
@ -488,7 +489,7 @@ func (f *File) parseFormatAddSparklineSet(sheet string, opts *SparklineOption) (
// addSparkline provides a function to create a sparkline in a sparkline group
// by given properties.
func (f *File) addSparkline(opts *SparklineOption, group *xlsxX14SparklineGroup) {
func (f *File) addSparkline(opts *SparklineOptions, group *xlsxX14SparklineGroup) {
for idx, location := range opts.Location {
group.Sparklines.Sparkline = append(group.Sparklines.Sparkline, &xlsxX14Sparkline{
F: opts.Range[idx],
@ -499,8 +500,9 @@ func (f *File) addSparkline(opts *SparklineOption, group *xlsxX14SparklineGroup)
// appendSparkline provides a function to append sparkline to sparkline
// groups.
func (f *File) appendSparkline(ws *xlsxWorksheet, group *xlsxX14SparklineGroup, groups *xlsxX14SparklineGroups) (err error) {
func (f *File) appendSparkline(ws *xlsxWorksheet, group *xlsxX14SparklineGroup, groups *xlsxX14SparklineGroups) error {
var (
err error
idx int
decodeExtLst *decodeWorksheetExt
decodeSparklineGroups *decodeX14SparklineGroups
@ -510,17 +512,17 @@ func (f *File) appendSparkline(ws *xlsxWorksheet, group *xlsxX14SparklineGroup,
decodeExtLst = new(decodeWorksheetExt)
if err = f.xmlNewDecoder(strings.NewReader("<extLst>" + ws.ExtLst.Ext + "</extLst>")).
Decode(decodeExtLst); err != nil && err != io.EOF {
return
return err
}
for idx, ext = range decodeExtLst.Ext {
if ext.URI == ExtURISparklineGroups {
decodeSparklineGroups = new(decodeX14SparklineGroups)
if err = f.xmlNewDecoder(strings.NewReader(ext.Content)).
Decode(decodeSparklineGroups); err != nil && err != io.EOF {
return
return err
}
if sparklineGroupBytes, err = xml.Marshal(group); err != nil {
return
return err
}
if groups == nil {
groups = &xlsxX14SparklineGroups{}
@ -528,16 +530,16 @@ func (f *File) appendSparkline(ws *xlsxWorksheet, group *xlsxX14SparklineGroup,
groups.XMLNSXM = NameSpaceSpreadSheetExcel2006Main.Value
groups.Content = decodeSparklineGroups.Content + string(sparklineGroupBytes)
if sparklineGroupsBytes, err = xml.Marshal(groups); err != nil {
return
return err
}
decodeExtLst.Ext[idx].Content = string(sparklineGroupsBytes)
}
}
if extLstBytes, err = xml.Marshal(decodeExtLst); err != nil {
return
return err
}
ws.ExtLst = &xlsxExtLst{
Ext: strings.TrimSuffix(strings.TrimPrefix(string(extLstBytes), "<extLst>"), "</extLst>"),
}
return
return err
}

View File

@ -15,7 +15,10 @@ func TestAddSparkline(t *testing.T) {
style, err := f.NewStyle(`{"font":{"bold":true}}`)
assert.NoError(t, err)
assert.NoError(t, f.SetCellStyle("Sheet1", "A1", "B1", style))
assert.NoError(t, f.SetSheetViewOptions("Sheet1", 0, ZoomScale(150)))
viewOpts, err := f.GetSheetView("Sheet1", 0)
assert.NoError(t, err)
viewOpts.ZoomScale = float64Ptr(150)
assert.NoError(t, f.SetSheetView("Sheet1", 0, &viewOpts))
assert.NoError(t, f.SetColWidth("Sheet1", "A", "A", 14))
assert.NoError(t, f.SetColWidth("Sheet1", "B", "B", 50))
@ -24,34 +27,34 @@ func TestAddSparkline(t *testing.T) {
assert.NoError(t, f.SetCellValue("Sheet1", "B1", "Description"))
assert.NoError(t, f.SetCellValue("Sheet1", "B2", `A default "line" sparkline.`))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A2"},
Range: []string{"Sheet3!A1:J1"},
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B3", `A default "column" sparkline.`))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A3"},
Range: []string{"Sheet3!A2:J2"},
Type: "column",
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B4", `A default "win/loss" sparkline.`))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A4"},
Range: []string{"Sheet3!A3:J3"},
Type: "win_loss",
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B6", "Line with markers."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A6"},
Range: []string{"Sheet3!A1:J1"},
Markers: true,
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B7", "Line with high and low points."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A7"},
Range: []string{"Sheet3!A1:J1"},
High: true,
@ -59,7 +62,7 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B8", "Line with first and last point markers."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A8"},
Range: []string{"Sheet3!A1:J1"},
First: true,
@ -67,28 +70,28 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B9", "Line with negative point markers."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A9"},
Range: []string{"Sheet3!A1:J1"},
Negative: true,
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B10", "Line with axis."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A10"},
Range: []string{"Sheet3!A1:J1"},
Axis: true,
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B12", "Column with default style (1)."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A12"},
Range: []string{"Sheet3!A2:J2"},
Type: "column",
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B13", "Column with style 2."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A13"},
Range: []string{"Sheet3!A2:J2"},
Type: "column",
@ -96,7 +99,7 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B14", "Column with style 3."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A14"},
Range: []string{"Sheet3!A2:J2"},
Type: "column",
@ -104,7 +107,7 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B15", "Column with style 4."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A15"},
Range: []string{"Sheet3!A2:J2"},
Type: "column",
@ -112,7 +115,7 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B16", "Column with style 5."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A16"},
Range: []string{"Sheet3!A2:J2"},
Type: "column",
@ -120,7 +123,7 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B17", "Column with style 6."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A17"},
Range: []string{"Sheet3!A2:J2"},
Type: "column",
@ -128,7 +131,7 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B18", "Column with a user defined color."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A18"},
Range: []string{"Sheet3!A2:J2"},
Type: "column",
@ -136,14 +139,14 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B20", "A win/loss sparkline."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A20"},
Range: []string{"Sheet3!A3:J3"},
Type: "win_loss",
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B21", "A win/loss sparkline with negative points highlighted."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A21"},
Range: []string{"Sheet3!A3:J3"},
Type: "win_loss",
@ -151,7 +154,7 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B23", "A left to right column (the default)."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A23"},
Range: []string{"Sheet3!A4:J4"},
Type: "column",
@ -159,7 +162,7 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B24", "A right to left column."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A24"},
Range: []string{"Sheet3!A4:J4"},
Type: "column",
@ -168,7 +171,7 @@ func TestAddSparkline(t *testing.T) {
}))
assert.NoError(t, f.SetCellValue("Sheet1", "B25", "Sparkline and text in one cell."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A25"},
Range: []string{"Sheet3!A4:J4"},
Type: "column",
@ -177,34 +180,34 @@ func TestAddSparkline(t *testing.T) {
assert.NoError(t, f.SetCellValue("Sheet1", "A25", "Growth"))
assert.NoError(t, f.SetCellValue("Sheet1", "B27", "A grouped sparkline. Changes are applied to all three."))
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A27", "A28", "A29"},
Range: []string{"Sheet3!A5:J5", "Sheet3!A6:J6", "Sheet3!A7:J7"},
Markers: true,
}))
// Sheet2 sections
assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOptions{
Location: []string{"F3"},
Range: []string{"Sheet2!A3:E3"},
Type: "win_loss",
Negative: true,
}))
assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOptions{
Location: []string{"F1"},
Range: []string{"Sheet2!A1:E1"},
Markers: true,
}))
assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOptions{
Location: []string{"F2"},
Range: []string{"Sheet2!A2:E2"},
Type: "column",
Style: 12,
}))
assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOption{
assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOptions{
Location: []string{"F3"},
Range: []string{"Sheet2!A3:E3"},
Type: "win_loss",
@ -215,39 +218,39 @@ func TestAddSparkline(t *testing.T) {
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddSparkline.xlsx")))
// Test error exceptions
assert.EqualError(t, f.AddSparkline("SheetN", &SparklineOption{
assert.EqualError(t, f.AddSparkline("SheetN", &SparklineOptions{
Location: []string{"F3"},
Range: []string{"Sheet2!A3:E3"},
}), "sheet SheetN does not exist")
assert.EqualError(t, f.AddSparkline("Sheet1", nil), ErrParameterRequired.Error())
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Range: []string{"Sheet2!A3:E3"},
}), ErrSparklineLocation.Error())
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"F3"},
}), ErrSparklineRange.Error())
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"F2", "F3"},
Range: []string{"Sheet2!A3:E3"},
}), ErrSparkline.Error())
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"F3"},
Range: []string{"Sheet2!A3:E3"},
Type: "unknown_type",
}), ErrSparklineType.Error())
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"F3"},
Range: []string{"Sheet2!A3:E3"},
Style: -1,
}), ErrSparklineStyle.Error())
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"F3"},
Range: []string{"Sheet2!A3:E3"},
Style: -1,
@ -265,7 +268,7 @@ func TestAddSparkline(t *testing.T) {
</x14:sparklineGroups>
</ext>
</extLst>`
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Location: []string{"A2"},
Range: []string{"Sheet3!A1:J1"},
}), "XML syntax error on line 6: element <sparklineGroup> closed by </sparklines>")

View File

@ -139,8 +139,8 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
// called after the rows are written but before Flush.
//
// See File.AddTable for details on the table format.
func (sw *StreamWriter) AddTable(hCell, vCell, format string) error {
formatSet, err := parseFormatTableSet(format)
func (sw *StreamWriter) AddTable(hCell, vCell, opts string) error {
options, err := parseTableOptions(opts)
if err != nil {
return err
}
@ -177,7 +177,7 @@ func (sw *StreamWriter) AddTable(hCell, vCell, format string) error {
tableID := sw.File.countTables() + 1
name := formatSet.TableName
name := options.TableName
if name == "" {
name = "Table" + strconv.Itoa(tableID)
}
@ -196,11 +196,11 @@ func (sw *StreamWriter) AddTable(hCell, vCell, format string) error {
TableColumn: tableColumn,
},
TableStyleInfo: &xlsxTableStyleInfo{
Name: formatSet.TableStyle,
ShowFirstColumn: formatSet.ShowFirstColumn,
ShowLastColumn: formatSet.ShowLastColumn,
ShowRowStripes: formatSet.ShowRowStripes,
ShowColumnStripes: formatSet.ShowColumnStripes,
Name: options.TableStyle,
ShowFirstColumn: options.ShowFirstColumn,
ShowLastColumn: options.ShowLastColumn,
ShowRowStripes: options.ShowRowStripes,
ShowColumnStripes: options.ShowColumnStripes,
},
}

View File

@ -173,7 +173,7 @@ func TestStreamTable(t *testing.T) {
assert.NoError(t, streamWriter.AddTable("A1", "C1", ``))
// Test add table with illegal formatset.
// Test add table with illegal options.
assert.EqualError(t, streamWriter.AddTable("B26", "A21", `{x}`), "invalid character 'x' looking for beginning of object key string")
// Test add table with illegal cell reference.
assert.EqualError(t, streamWriter.AddTable("A", "B1", `{}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())

View File

@ -2859,13 +2859,13 @@ func (f *File) SetCellStyle(sheet, hCell, vCell string, styleID int) error {
// max_color - Same as min_color, see above.
//
// bar_color - Used for data_bar. Same as min_color, see above.
func (f *File) SetConditionalFormat(sheet, reference, formatSet string) error {
var format []*formatConditional
err := json.Unmarshal([]byte(formatSet), &format)
func (f *File) SetConditionalFormat(sheet, reference, opts string) error {
var format []*conditionalOptions
err := json.Unmarshal([]byte(opts), &format)
if err != nil {
return err
}
drawContFmtFunc := map[string]func(p int, ct string, fmtCond *formatConditional) *xlsxCfRule{
drawContFmtFunc := map[string]func(p int, ct string, fmtCond *conditionalOptions) *xlsxCfRule{
"cellIs": drawCondFmtCellIs,
"top10": drawCondFmtTop10,
"aboveAverage": drawCondFmtAboveAverage,
@ -2909,8 +2909,8 @@ func (f *File) SetConditionalFormat(sheet, reference, formatSet string) error {
// extractCondFmtCellIs provides a function to extract conditional format
// settings for cell value (include between, not between, equal, not equal,
// greater than and less than) by given conditional formatting rule.
func extractCondFmtCellIs(c *xlsxCfRule) *formatConditional {
format := formatConditional{Type: "cell", Criteria: operatorType[c.Operator], Format: *c.DxfID}
func extractCondFmtCellIs(c *xlsxCfRule) *conditionalOptions {
format := conditionalOptions{Type: "cell", Criteria: operatorType[c.Operator], Format: *c.DxfID}
if len(c.Formula) == 2 {
format.Minimum, format.Maximum = c.Formula[0], c.Formula[1]
return &format
@ -2922,8 +2922,8 @@ func extractCondFmtCellIs(c *xlsxCfRule) *formatConditional {
// extractCondFmtTop10 provides a function to extract conditional format
// settings for top N (default is top 10) by given conditional formatting
// rule.
func extractCondFmtTop10(c *xlsxCfRule) *formatConditional {
format := formatConditional{
func extractCondFmtTop10(c *xlsxCfRule) *conditionalOptions {
format := conditionalOptions{
Type: "top",
Criteria: "=",
Format: *c.DxfID,
@ -2939,8 +2939,8 @@ func extractCondFmtTop10(c *xlsxCfRule) *formatConditional {
// extractCondFmtAboveAverage provides a function to extract conditional format
// settings for above average and below average by given conditional formatting
// rule.
func extractCondFmtAboveAverage(c *xlsxCfRule) *formatConditional {
return &formatConditional{
func extractCondFmtAboveAverage(c *xlsxCfRule) *conditionalOptions {
return &conditionalOptions{
Type: "average",
Criteria: "=",
Format: *c.DxfID,
@ -2951,8 +2951,8 @@ func extractCondFmtAboveAverage(c *xlsxCfRule) *formatConditional {
// extractCondFmtDuplicateUniqueValues provides a function to extract
// conditional format settings for duplicate and unique values by given
// conditional formatting rule.
func extractCondFmtDuplicateUniqueValues(c *xlsxCfRule) *formatConditional {
return &formatConditional{
func extractCondFmtDuplicateUniqueValues(c *xlsxCfRule) *conditionalOptions {
return &conditionalOptions{
Type: map[string]string{
"duplicateValues": "duplicate",
"uniqueValues": "unique",
@ -2965,8 +2965,8 @@ func extractCondFmtDuplicateUniqueValues(c *xlsxCfRule) *formatConditional {
// extractCondFmtColorScale provides a function to extract conditional format
// settings for color scale (include 2 color scale and 3 color scale) by given
// conditional formatting rule.
func extractCondFmtColorScale(c *xlsxCfRule) *formatConditional {
var format formatConditional
func extractCondFmtColorScale(c *xlsxCfRule) *conditionalOptions {
var format conditionalOptions
format.Type, format.Criteria = "2_color_scale", "="
values := len(c.ColorScale.Cfvo)
colors := len(c.ColorScale.Color)
@ -3000,8 +3000,8 @@ func extractCondFmtColorScale(c *xlsxCfRule) *formatConditional {
// extractCondFmtDataBar provides a function to extract conditional format
// settings for data bar by given conditional formatting rule.
func extractCondFmtDataBar(c *xlsxCfRule) *formatConditional {
format := formatConditional{Type: "data_bar", Criteria: "="}
func extractCondFmtDataBar(c *xlsxCfRule) *conditionalOptions {
format := conditionalOptions{Type: "data_bar", Criteria: "="}
if c.DataBar != nil {
format.MinType = c.DataBar.Cfvo[0].Type
format.MaxType = c.DataBar.Cfvo[1].Type
@ -3012,8 +3012,8 @@ func extractCondFmtDataBar(c *xlsxCfRule) *formatConditional {
// extractCondFmtExp provides a function to extract conditional format settings
// for expression by given conditional formatting rule.
func extractCondFmtExp(c *xlsxCfRule) *formatConditional {
format := formatConditional{Type: "formula", Format: *c.DxfID}
func extractCondFmtExp(c *xlsxCfRule) *conditionalOptions {
format := conditionalOptions{Type: "formula", Format: *c.DxfID}
if len(c.Formula) > 0 {
format.Criteria = c.Formula[0]
}
@ -3023,7 +3023,7 @@ func extractCondFmtExp(c *xlsxCfRule) *formatConditional {
// GetConditionalFormats returns conditional format settings by given worksheet
// name.
func (f *File) GetConditionalFormats(sheet string) (map[string]string, error) {
extractContFmtFunc := map[string]func(c *xlsxCfRule) *formatConditional{
extractContFmtFunc := map[string]func(c *xlsxCfRule) *conditionalOptions{
"cellIs": extractCondFmtCellIs,
"top10": extractCondFmtTop10,
"aboveAverage": extractCondFmtAboveAverage,
@ -3040,14 +3040,14 @@ func (f *File) GetConditionalFormats(sheet string) (map[string]string, error) {
return conditionalFormats, err
}
for _, cf := range ws.ConditionalFormatting {
var format []*formatConditional
var opts []*conditionalOptions
for _, cr := range cf.CfRule {
if extractFunc, ok := extractContFmtFunc[cr.Type]; ok {
format = append(format, extractFunc(cr))
opts = append(opts, extractFunc(cr))
}
}
formatSet, _ := json.Marshal(format)
conditionalFormats[cf.SQRef] = string(formatSet)
options, _ := json.Marshal(opts)
conditionalFormats[cf.SQRef] = string(options)
}
return conditionalFormats, err
}
@ -3071,7 +3071,7 @@ func (f *File) UnsetConditionalFormat(sheet, reference string) error {
// drawCondFmtCellIs provides a function to create conditional formatting rule
// for cell value (include between, not between, equal, not equal, greater
// than and less than) by given priority, criteria type and format settings.
func drawCondFmtCellIs(p int, ct string, format *formatConditional) *xlsxCfRule {
func drawCondFmtCellIs(p int, ct string, format *conditionalOptions) *xlsxCfRule {
c := &xlsxCfRule{
Priority: p + 1,
Type: validType[format.Type],
@ -3094,7 +3094,7 @@ func drawCondFmtCellIs(p int, ct string, format *formatConditional) *xlsxCfRule
// drawCondFmtTop10 provides a function to create conditional formatting rule
// for top N (default is top 10) by given priority, criteria type and format
// settings.
func drawCondFmtTop10(p int, ct string, format *formatConditional) *xlsxCfRule {
func drawCondFmtTop10(p int, ct string, format *conditionalOptions) *xlsxCfRule {
c := &xlsxCfRule{
Priority: p + 1,
Bottom: format.Type == "bottom",
@ -3113,7 +3113,7 @@ func drawCondFmtTop10(p int, ct string, format *formatConditional) *xlsxCfRule {
// drawCondFmtAboveAverage provides a function to create conditional
// formatting rule for above average and below average by given priority,
// criteria type and format settings.
func drawCondFmtAboveAverage(p int, ct string, format *formatConditional) *xlsxCfRule {
func drawCondFmtAboveAverage(p int, ct string, format *conditionalOptions) *xlsxCfRule {
return &xlsxCfRule{
Priority: p + 1,
Type: validType[format.Type],
@ -3125,7 +3125,7 @@ func drawCondFmtAboveAverage(p int, ct string, format *formatConditional) *xlsxC
// drawCondFmtDuplicateUniqueValues provides a function to create conditional
// formatting rule for duplicate and unique values by given priority, criteria
// type and format settings.
func drawCondFmtDuplicateUniqueValues(p int, ct string, format *formatConditional) *xlsxCfRule {
func drawCondFmtDuplicateUniqueValues(p int, ct string, format *conditionalOptions) *xlsxCfRule {
return &xlsxCfRule{
Priority: p + 1,
Type: validType[format.Type],
@ -3136,7 +3136,7 @@ func drawCondFmtDuplicateUniqueValues(p int, ct string, format *formatConditiona
// drawCondFmtColorScale provides a function to create conditional formatting
// rule for color scale (include 2 color scale and 3 color scale) by given
// priority, criteria type and format settings.
func drawCondFmtColorScale(p int, ct string, format *formatConditional) *xlsxCfRule {
func drawCondFmtColorScale(p int, ct string, format *conditionalOptions) *xlsxCfRule {
minValue := format.MinValue
if minValue == "" {
minValue = "0"
@ -3173,7 +3173,7 @@ func drawCondFmtColorScale(p int, ct string, format *formatConditional) *xlsxCfR
// drawCondFmtDataBar provides a function to create conditional formatting
// rule for data bar by given priority, criteria type and format settings.
func drawCondFmtDataBar(p int, ct string, format *formatConditional) *xlsxCfRule {
func drawCondFmtDataBar(p int, ct string, format *conditionalOptions) *xlsxCfRule {
return &xlsxCfRule{
Priority: p + 1,
Type: validType[format.Type],
@ -3186,7 +3186,7 @@ func drawCondFmtDataBar(p int, ct string, format *formatConditional) *xlsxCfRule
// drawCondFmtExp provides a function to create conditional formatting rule
// for expression by given priority, criteria type and format settings.
func drawCondFmtExp(p int, ct string, format *formatConditional) *xlsxCfRule {
func drawCondFmtExp(p int, ct string, format *conditionalOptions) *xlsxCfRule {
return &xlsxCfRule{
Priority: p + 1,
Type: validType[format.Type],

View File

@ -192,9 +192,9 @@ func TestGetConditionalFormats(t *testing.T) {
f := NewFile()
err := f.SetConditionalFormat("Sheet1", "A1:A2", format)
assert.NoError(t, err)
formatSet, err := f.GetConditionalFormats("Sheet1")
opts, err := f.GetConditionalFormats("Sheet1")
assert.NoError(t, err)
assert.Equal(t, format, formatSet["A1:A2"])
assert.Equal(t, format, opts["A1:A2"])
}
// Test get conditional formats on no exists worksheet
f := NewFile()

View File

@ -20,12 +20,12 @@ import (
"strings"
)
// parseFormatTableSet provides a function to parse the format settings of the
// parseTableOptions provides a function to parse the format settings of the
// table with default value.
func parseFormatTableSet(formatSet string) (*formatTable, error) {
format := formatTable{ShowRowStripes: true}
err := json.Unmarshal(parseFormatSet(formatSet), &format)
return &format, err
func parseTableOptions(opts string) (*tableOptions, error) {
options := tableOptions{ShowRowStripes: true}
err := json.Unmarshal(fallbackOptions(opts), &options)
return &options, err
}
// AddTable provides the method to add table in a worksheet by given worksheet
@ -57,8 +57,8 @@ func parseFormatTableSet(formatSet string) (*formatTable, error) {
// TableStyleLight1 - TableStyleLight21
// TableStyleMedium1 - TableStyleMedium28
// TableStyleDark1 - TableStyleDark11
func (f *File) AddTable(sheet, hCell, vCell, format string) error {
formatSet, err := parseFormatTableSet(format)
func (f *File) AddTable(sheet, hCell, vCell, opts string) error {
options, err := parseTableOptions(opts)
if err != nil {
return err
}
@ -91,7 +91,7 @@ func (f *File) AddTable(sheet, hCell, vCell, format string) error {
return err
}
f.addSheetNameSpace(sheet, SourceRelationship)
if err = f.addTable(sheet, tableXML, hCol, hRow, vCol, vRow, tableID, formatSet); err != nil {
if err = f.addTable(sheet, tableXML, hCol, hRow, vCol, vRow, tableID, options); err != nil {
return err
}
f.addContentTypePart(tableID, "table")
@ -160,7 +160,7 @@ func (f *File) setTableHeader(sheet string, x1, y1, x2 int) ([]*xlsxTableColumn,
// addTable provides a function to add table by given worksheet name,
// range reference and format set.
func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, formatSet *formatTable) error {
func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, opts *tableOptions) error {
// Correct the minimum number of rows, the table at least two lines.
if y1 == y2 {
y2++
@ -172,7 +172,7 @@ func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, formatSet
return err
}
tableColumns, _ := f.setTableHeader(sheet, x1, y1, x2)
name := formatSet.TableName
name := opts.TableName
if name == "" {
name = "Table" + strconv.Itoa(i)
}
@ -190,11 +190,11 @@ func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, formatSet
TableColumn: tableColumns,
},
TableStyleInfo: &xlsxTableStyleInfo{
Name: formatSet.TableStyle,
ShowFirstColumn: formatSet.ShowFirstColumn,
ShowLastColumn: formatSet.ShowLastColumn,
ShowRowStripes: formatSet.ShowRowStripes,
ShowColumnStripes: formatSet.ShowColumnStripes,
Name: opts.TableStyle,
ShowFirstColumn: opts.ShowFirstColumn,
ShowLastColumn: opts.ShowLastColumn,
ShowRowStripes: opts.ShowRowStripes,
ShowColumnStripes: opts.ShowColumnStripes,
},
}
table, _ := xml.Marshal(t)
@ -202,12 +202,12 @@ func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, formatSet
return nil
}
// parseAutoFilterSet provides a function to parse the settings of the auto
// parseAutoFilterOptions provides a function to parse the settings of the auto
// filter.
func parseAutoFilterSet(formatSet string) (*formatAutoFilter, error) {
format := formatAutoFilter{}
err := json.Unmarshal([]byte(formatSet), &format)
return &format, err
func parseAutoFilterOptions(opts string) (*autoFilterOptions, error) {
options := autoFilterOptions{}
err := json.Unmarshal([]byte(opts), &options)
return &options, err
}
// AutoFilter provides the method to add auto filter in a worksheet by given
@ -279,7 +279,7 @@ func parseAutoFilterSet(formatSet string) (*formatAutoFilter, error) {
// x < 2000
// col < 2000
// Price < 2000
func (f *File) AutoFilter(sheet, hCell, vCell, format string) error {
func (f *File) AutoFilter(sheet, hCell, vCell, opts string) error {
hCol, hRow, err := CellNameToCoordinates(hCell)
if err != nil {
return err
@ -297,7 +297,7 @@ func (f *File) AutoFilter(sheet, hCell, vCell, format string) error {
vRow, hRow = hRow, vRow
}
formatSet, _ := parseAutoFilterSet(format)
options, _ := parseAutoFilterOptions(opts)
cellStart, _ := CoordinatesToCellName(hCol, hRow, true)
cellEnd, _ := CoordinatesToCellName(vCol, vRow, true)
ref, filterDB := cellStart+":"+cellEnd, "_xlnm._FilterDatabase"
@ -328,12 +328,12 @@ func (f *File) AutoFilter(sheet, hCell, vCell, format string) error {
}
}
refRange := vCol - hCol
return f.autoFilter(sheet, ref, refRange, hCol, formatSet)
return f.autoFilter(sheet, ref, refRange, hCol, options)
}
// autoFilter provides a function to extract the tokens from the filter
// expression. The tokens are mainly non-whitespace groups.
func (f *File) autoFilter(sheet, ref string, refRange, col int, formatSet *formatAutoFilter) error {
func (f *File) autoFilter(sheet, ref string, refRange, col int, opts *autoFilterOptions) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
@ -346,28 +346,28 @@ func (f *File) autoFilter(sheet, ref string, refRange, col int, formatSet *forma
Ref: ref,
}
ws.AutoFilter = filter
if formatSet.Column == "" || formatSet.Expression == "" {
if opts.Column == "" || opts.Expression == "" {
return nil
}
fsCol, err := ColumnNameToNumber(formatSet.Column)
fsCol, err := ColumnNameToNumber(opts.Column)
if err != nil {
return err
}
offset := fsCol - col
if offset < 0 || offset > refRange {
return fmt.Errorf("incorrect index of column '%s'", formatSet.Column)
return fmt.Errorf("incorrect index of column '%s'", opts.Column)
}
filter.FilterColumn = append(filter.FilterColumn, &xlsxFilterColumn{
ColID: offset,
})
re := regexp.MustCompile(`"(?:[^"]|"")*"|\S+`)
token := re.FindAllString(formatSet.Expression, -1)
token := re.FindAllString(opts.Expression, -1)
if len(token) != 3 && len(token) != 7 {
return fmt.Errorf("incorrect number of tokens in criteria '%s'", formatSet.Expression)
return fmt.Errorf("incorrect number of tokens in criteria '%s'", opts.Expression)
}
expressions, tokens, err := f.parseFilterExpression(formatSet.Expression, token)
expressions, tokens, err := f.parseFilterExpression(opts.Expression, token)
if err != nil {
return err
}

View File

@ -31,7 +31,7 @@ func TestAddTable(t *testing.T) {
// Test add table in not exist worksheet.
assert.EqualError(t, f.AddTable("SheetN", "B26", "A21", `{}`), "sheet SheetN does not exist")
// Test add table with illegal formatset.
// Test add table with illegal options.
assert.EqualError(t, f.AddTable("Sheet1", "B26", "A21", `{x}`), "invalid character 'x' looking for beginning of object key string")
// Test add table with illegal cell reference.
assert.EqualError(t, f.AddTable("Sheet1", "A", "B1", `{}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
@ -108,19 +108,19 @@ func TestAutoFilterError(t *testing.T) {
})
}
assert.EqualError(t, f.autoFilter("SheetN", "A1", 1, 1, &formatAutoFilter{
assert.EqualError(t, f.autoFilter("SheetN", "A1", 1, 1, &autoFilterOptions{
Column: "A",
Expression: "",
}), "sheet SheetN does not exist")
assert.EqualError(t, f.autoFilter("Sheet1", "A1", 1, 1, &formatAutoFilter{
assert.EqualError(t, f.autoFilter("Sheet1", "A1", 1, 1, &autoFilterOptions{
Column: "-",
Expression: "-",
}), newInvalidColumnNameError("-").Error())
assert.EqualError(t, f.autoFilter("Sheet1", "A1", 1, 100, &formatAutoFilter{
assert.EqualError(t, f.autoFilter("Sheet1", "A1", 1, 100, &autoFilterOptions{
Column: "A",
Expression: "-",
}), `incorrect index of column 'A'`)
assert.EqualError(t, f.autoFilter("Sheet1", "A1", 1, 1, &formatAutoFilter{
assert.EqualError(t, f.autoFilter("Sheet1", "A1", 1, 1, &autoFilterOptions{
Column: "A",
Expression: "-",
}), `incorrect number of tokens in criteria '-'`)

View File

@ -21,26 +21,38 @@ import (
"strings"
)
// WorkbookPrOption is an option of a view of a workbook. See SetWorkbookPrOptions().
type WorkbookPrOption interface {
setWorkbookPrOption(pr *xlsxWorkbookPr)
// SetWorkbookProps provides a function to sets workbook properties.
func (f *File) SetWorkbookProps(opts *WorkbookPropsOptions) error {
wb := f.workbookReader()
if wb.WorkbookPr == nil {
wb.WorkbookPr = new(xlsxWorkbookPr)
}
if opts == nil {
return nil
}
if opts.Date1904 != nil {
wb.WorkbookPr.Date1904 = *opts.Date1904
}
if opts.FilterPrivacy != nil {
wb.WorkbookPr.FilterPrivacy = *opts.FilterPrivacy
}
if opts.CodeName != nil {
wb.WorkbookPr.CodeName = *opts.CodeName
}
return nil
}
// WorkbookPrOptionPtr is a writable WorkbookPrOption. See GetWorkbookPrOptions().
type WorkbookPrOptionPtr interface {
WorkbookPrOption
getWorkbookPrOption(pr *xlsxWorkbookPr)
// GetWorkbookProps provides a function to gets workbook properties.
func (f *File) GetWorkbookProps() (WorkbookPropsOptions, error) {
wb, opts := f.workbookReader(), WorkbookPropsOptions{}
if wb.WorkbookPr != nil {
opts.Date1904 = boolPtr(wb.WorkbookPr.Date1904)
opts.FilterPrivacy = boolPtr(wb.WorkbookPr.FilterPrivacy)
opts.CodeName = stringPtr(wb.WorkbookPr.CodeName)
}
return opts, nil
}
type (
// Date1904 is an option used for WorkbookPrOption, that indicates whether
// to use a 1900 or 1904 date system when converting serial date-times in
// the workbook to dates
Date1904 bool
// FilterPrivacy is an option used for WorkbookPrOption
FilterPrivacy bool
)
// setWorkbook update workbook property of the spreadsheet. Maximum 31
// characters are allowed in sheet title.
func (f *File) setWorkbook(name string, sheetID, rid int) {
@ -116,84 +128,3 @@ func (f *File) workBookWriter() {
f.saveFileList(f.getWorkbookPath(), replaceRelationshipsBytes(f.replaceNameSpaceBytes(f.getWorkbookPath(), output)))
}
}
// SetWorkbookPrOptions provides a function to sets workbook properties.
//
// Available options:
//
// Date1904(bool)
// FilterPrivacy(bool)
// CodeName(string)
func (f *File) SetWorkbookPrOptions(opts ...WorkbookPrOption) error {
wb := f.workbookReader()
pr := wb.WorkbookPr
if pr == nil {
pr = new(xlsxWorkbookPr)
wb.WorkbookPr = pr
}
for _, opt := range opts {
opt.setWorkbookPrOption(pr)
}
return nil
}
// setWorkbookPrOption implements the WorkbookPrOption interface.
func (o Date1904) setWorkbookPrOption(pr *xlsxWorkbookPr) {
pr.Date1904 = bool(o)
}
// setWorkbookPrOption implements the WorkbookPrOption interface.
func (o FilterPrivacy) setWorkbookPrOption(pr *xlsxWorkbookPr) {
pr.FilterPrivacy = bool(o)
}
// setWorkbookPrOption implements the WorkbookPrOption interface.
func (o CodeName) setWorkbookPrOption(pr *xlsxWorkbookPr) {
pr.CodeName = string(o)
}
// GetWorkbookPrOptions provides a function to gets workbook properties.
//
// Available options:
//
// Date1904(bool)
// FilterPrivacy(bool)
// CodeName(string)
func (f *File) GetWorkbookPrOptions(opts ...WorkbookPrOptionPtr) error {
wb := f.workbookReader()
pr := wb.WorkbookPr
for _, opt := range opts {
opt.getWorkbookPrOption(pr)
}
return nil
}
// getWorkbookPrOption implements the WorkbookPrOption interface and get the
// date1904 of the workbook.
func (o *Date1904) getWorkbookPrOption(pr *xlsxWorkbookPr) {
if pr == nil {
*o = false
return
}
*o = Date1904(pr.Date1904)
}
// getWorkbookPrOption implements the WorkbookPrOption interface and get the
// filter privacy of the workbook.
func (o *FilterPrivacy) getWorkbookPrOption(pr *xlsxWorkbookPr) {
if pr == nil {
*o = false
return
}
*o = FilterPrivacy(pr.FilterPrivacy)
}
// getWorkbookPrOption implements the WorkbookPrOption interface and get the
// code name of the workbook.
func (o *CodeName) getWorkbookPrOption(pr *xlsxWorkbookPr) {
if pr == nil {
*o = ""
return
}
*o = CodeName(pr.CodeName)
}

View File

@ -1,69 +1,23 @@
package excelize
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func ExampleFile_SetWorkbookPrOptions() {
f := NewFile()
if err := f.SetWorkbookPrOptions(
Date1904(false),
FilterPrivacy(false),
CodeName("code"),
); err != nil {
fmt.Println(err)
}
// Output:
}
func ExampleFile_GetWorkbookPrOptions() {
f := NewFile()
var (
date1904 Date1904
filterPrivacy FilterPrivacy
codeName CodeName
)
if err := f.GetWorkbookPrOptions(&date1904); err != nil {
fmt.Println(err)
}
if err := f.GetWorkbookPrOptions(&filterPrivacy); err != nil {
fmt.Println(err)
}
if err := f.GetWorkbookPrOptions(&codeName); err != nil {
fmt.Println(err)
}
fmt.Println("Defaults:")
fmt.Printf("- date1904: %t\n", date1904)
fmt.Printf("- filterPrivacy: %t\n", filterPrivacy)
fmt.Printf("- codeName: %q\n", codeName)
// Output:
// Defaults:
// - date1904: false
// - filterPrivacy: true
// - codeName: ""
}
func TestWorkbookPr(t *testing.T) {
func TestWorkbookProps(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetWorkbookProps(nil))
wb := f.workbookReader()
wb.WorkbookPr = nil
var date1904 Date1904
assert.NoError(t, f.GetWorkbookPrOptions(&date1904))
assert.Equal(t, false, bool(date1904))
wb.WorkbookPr = nil
var codeName CodeName
assert.NoError(t, f.GetWorkbookPrOptions(&codeName))
assert.Equal(t, "", string(codeName))
assert.NoError(t, f.SetWorkbookPrOptions(CodeName("code")))
assert.NoError(t, f.GetWorkbookPrOptions(&codeName))
assert.Equal(t, "code", string(codeName))
wb.WorkbookPr = nil
var filterPrivacy FilterPrivacy
assert.NoError(t, f.GetWorkbookPrOptions(&filterPrivacy))
assert.Equal(t, false, bool(filterPrivacy))
expected := WorkbookPropsOptions{
Date1904: boolPtr(true),
FilterPrivacy: boolPtr(true),
CodeName: stringPtr("code"),
}
assert.NoError(t, f.SetWorkbookProps(&expected))
opts, err := f.GetWorkbookProps()
assert.NoError(t, err)
assert.Equal(t, expected, opts)
}

View File

@ -518,8 +518,8 @@ type cPageMargins struct {
T float64 `xml:"t,attr"`
}
// formatChartAxis directly maps the format settings of the chart axis.
type formatChartAxis struct {
// chartAxisOptions directly maps the format settings of the chart axis.
type chartAxisOptions struct {
None bool `json:"none"`
Crossing string `json:"crossing"`
MajorGridlines bool `json:"major_grid_lines"`
@ -543,26 +543,27 @@ type formatChartAxis struct {
Italic bool `json:"italic"`
Underline bool `json:"underline"`
} `json:"num_font"`
LogBase float64 `json:"logbase"`
NameLayout formatLayout `json:"name_layout"`
LogBase float64 `json:"logbase"`
NameLayout layoutOptions `json:"name_layout"`
}
type formatChartDimension struct {
// chartDimensionOptions directly maps the dimension of the chart.
type chartDimensionOptions struct {
Width int `json:"width"`
Height int `json:"height"`
}
// formatChart directly maps the format settings of the chart.
type formatChart struct {
Type string `json:"type"`
Series []formatChartSeries `json:"series"`
Format formatPicture `json:"format"`
Dimension formatChartDimension `json:"dimension"`
Legend formatChartLegend `json:"legend"`
Title formatChartTitle `json:"title"`
VaryColors bool `json:"vary_colors"`
XAxis formatChartAxis `json:"x_axis"`
YAxis formatChartAxis `json:"y_axis"`
// chartOptions directly maps the format settings of the chart.
type chartOptions struct {
Type string `json:"type"`
Series []chartSeriesOptions `json:"series"`
Format pictureOptions `json:"format"`
Dimension chartDimensionOptions `json:"dimension"`
Legend chartLegendOptions `json:"legend"`
Title chartTitleOptions `json:"title"`
VaryColors bool `json:"vary_colors"`
XAxis chartAxisOptions `json:"x_axis"`
YAxis chartAxisOptions `json:"y_axis"`
Chartarea struct {
Border struct {
None bool `json:"none"`
@ -594,7 +595,7 @@ type formatChart struct {
Fill struct {
Color string `json:"color"`
} `json:"fill"`
Layout formatLayout `json:"layout"`
Layout layoutOptions `json:"layout"`
} `json:"plotarea"`
ShowBlanksAs string `json:"show_blanks_as"`
ShowHiddenData bool `json:"show_hidden_data"`
@ -603,19 +604,19 @@ type formatChart struct {
order int
}
// formatChartLegend directly maps the format settings of the chart legend.
type formatChartLegend struct {
None bool `json:"none"`
DeleteSeries []int `json:"delete_series"`
Font Font `json:"font"`
Layout formatLayout `json:"layout"`
Position string `json:"position"`
ShowLegendEntry bool `json:"show_legend_entry"`
ShowLegendKey bool `json:"show_legend_key"`
// chartLegendOptions directly maps the format settings of the chart legend.
type chartLegendOptions struct {
None bool `json:"none"`
DeleteSeries []int `json:"delete_series"`
Font Font `json:"font"`
Layout layoutOptions `json:"layout"`
Position string `json:"position"`
ShowLegendEntry bool `json:"show_legend_entry"`
ShowLegendKey bool `json:"show_legend_key"`
}
// formatChartSeries directly maps the format settings of the chart series.
type formatChartSeries struct {
// chartSeriesOptions directly maps the format settings of the chart series.
type chartSeriesOptions struct {
Name string `json:"name"`
Categories string `json:"categories"`
Values string `json:"values"`
@ -640,16 +641,16 @@ type formatChartSeries struct {
} `json:"marker"`
}
// formatChartTitle directly maps the format settings of the chart title.
type formatChartTitle struct {
None bool `json:"none"`
Name string `json:"name"`
Overlay bool `json:"overlay"`
Layout formatLayout `json:"layout"`
// chartTitleOptions directly maps the format settings of the chart title.
type chartTitleOptions struct {
None bool `json:"none"`
Name string `json:"name"`
Overlay bool `json:"overlay"`
Layout layoutOptions `json:"layout"`
}
// formatLayout directly maps the format settings of the element layout.
type formatLayout struct {
// layoutOptions directly maps the format settings of the element layout.
type layoutOptions struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Width float64 `json:"width"`

View File

@ -72,8 +72,8 @@ type xlsxPhoneticRun struct {
T string `xml:"t"`
}
// formatComment directly maps the format settings of the comment.
type formatComment struct {
// commentOptions directly maps the format settings of the comment.
type commentOptions struct {
Author string `json:"author"`
Text string `json:"text"`
}

View File

@ -493,8 +493,8 @@ type xdrTxBody struct {
P []*aP `xml:"a:p"`
}
// formatPicture directly maps the format settings of the picture.
type formatPicture struct {
// pictureOptions directly maps the format settings of the picture.
type pictureOptions struct {
FPrintsWithSheet bool `json:"print_obj"`
FLocksWithSheet bool `json:"locked"`
NoChangeAspect bool `json:"lock_aspect_ratio"`
@ -508,33 +508,33 @@ type formatPicture struct {
Positioning string `json:"positioning"`
}
// formatShape directly maps the format settings of the shape.
type formatShape struct {
Macro string `json:"macro"`
Type string `json:"type"`
Width int `json:"width"`
Height int `json:"height"`
Format formatPicture `json:"format"`
Color formatShapeColor `json:"color"`
Line formatLine `json:"line"`
Paragraph []formatShapeParagraph `json:"paragraph"`
// shapeOptions directly maps the format settings of the shape.
type shapeOptions struct {
Macro string `json:"macro"`
Type string `json:"type"`
Width int `json:"width"`
Height int `json:"height"`
Format pictureOptions `json:"format"`
Color shapeColorOptions `json:"color"`
Line lineOptions `json:"line"`
Paragraph []shapeParagraphOptions `json:"paragraph"`
}
// formatShapeParagraph directly maps the format settings of the paragraph in
// shapeParagraphOptions directly maps the format settings of the paragraph in
// the shape.
type formatShapeParagraph struct {
type shapeParagraphOptions struct {
Font Font `json:"font"`
Text string `json:"text"`
}
// formatShapeColor directly maps the color settings of the shape.
type formatShapeColor struct {
// shapeColorOptions directly maps the color settings of the shape.
type shapeColorOptions struct {
Line string `json:"line"`
Fill string `json:"fill"`
Effect string `json:"effect"`
}
// formatLine directly maps the line settings of the shape.
type formatLine struct {
// lineOptions directly maps the line settings of the shape.
type lineOptions struct {
Width float64 `json:"width"`
}

View File

@ -196,8 +196,8 @@ type xlsxTableStyleInfo struct {
ShowColumnStripes bool `xml:"showColumnStripes,attr"`
}
// formatTable directly maps the format settings of the table.
type formatTable struct {
// tableOptions directly maps the format settings of the table.
type tableOptions struct {
TableName string `json:"table_name"`
TableStyle string `json:"table_style"`
ShowFirstColumn bool `json:"show_first_column"`
@ -206,8 +206,8 @@ type formatTable struct {
ShowColumnStripes bool `json:"show_column_stripes"`
}
// formatAutoFilter directly maps the auto filter settings.
type formatAutoFilter struct {
// autoFilterOptions directly maps the auto filter settings.
type autoFilterOptions struct {
Column string `json:"column"`
Expression string `json:"expression"`
FilterList []struct {

View File

@ -308,8 +308,15 @@ type xlsxCustomWorkbookView struct {
// DefinedName directly maps the name for a cell or cell range on a
// worksheet.
type DefinedName struct {
Name string
Comment string
RefersTo string
Scope string
Name string `json:"name,omitempty"`
Comment string `json:"comment,omitempty"`
RefersTo string `json:"refers_to,omitempty"`
Scope string `json:"scope,omitempty"`
}
// WorkbookPropsOptions directly maps the settings of workbook proprieties.
type WorkbookPropsOptions struct {
Date1904 *bool `json:"date_1994,omitempty"`
FilterPrivacy *bool `json:"filter_privacy,omitempty"`
CodeName *string `json:"code_name,omitempty"`
}

View File

@ -454,7 +454,11 @@ type DataValidation struct {
// b (Boolean) | Cell containing a boolean.
// d (Date) | Cell contains a date in the ISO 8601 format.
// e (Error) | Cell containing an error.
// inlineStr (Inline String) | Cell containing an (inline) rich string, i.e., one not in the shared string table. If this cell type is used, then the cell value is in the is element rather than the v element in the cell (c element).
// inlineStr (Inline String) | Cell containing an (inline) rich string, i.e.,
// | one not in the shared string table. If this
// | cell type is used, then the cell value is in
// | the is element rather than the v element in
// | the cell (c element).
// n (Number) | Cell containing a number.
// s (Shared String) | Cell containing a shared string.
// str (String) | Cell containing a formula string.
@ -777,39 +781,39 @@ type xlsxX14Sparkline struct {
Sqref string `xml:"xm:sqref"`
}
// SparklineOption directly maps the settings of the sparkline.
type SparklineOption struct {
Location []string
Range []string
Max int
CustMax int
Min int
CustMin int
Type string
Weight float64
DateAxis bool
Markers bool
High bool
Low bool
First bool
Last bool
Negative bool
Axis bool
Hidden bool
Reverse bool
Style int
SeriesColor string
NegativeColor string
MarkersColor string
FirstColor string
LastColor string
HightColor string
LowColor string
EmptyCells string
// SparklineOptions directly maps the settings of the sparkline.
type SparklineOptions struct {
Location []string `json:"location"`
Range []string `json:"range"`
Max int `json:"max"`
CustMax int `json:"cust_max"`
Min int `json:"min"`
CustMin int `json:"cust_min"`
Type string `json:"hype"`
Weight float64 `json:"weight"`
DateAxis bool `json:"date_axis"`
Markers bool `json:"markers"`
High bool `json:"high"`
Low bool `json:"low"`
First bool `json:"first"`
Last bool `json:"last"`
Negative bool `json:"negative"`
Axis bool `json:"axis"`
Hidden bool `json:"hidden"`
Reverse bool `json:"reverse"`
Style int `json:"style"`
SeriesColor string `json:"series_color"`
NegativeColor string `json:"negative_color"`
MarkersColor string `json:"markers_color"`
FirstColor string `json:"first_color"`
LastColor string `json:"last_color"`
HightColor string `json:"hight_color"`
LowColor string `json:"low_color"`
EmptyCells string `json:"empty_cells"`
}
// formatPanes directly maps the settings of the panes.
type formatPanes struct {
// panesOptions directly maps the settings of the panes.
type panesOptions struct {
Freeze bool `json:"freeze"`
Split bool `json:"split"`
XSplit int `json:"x_split"`
@ -823,8 +827,8 @@ type formatPanes struct {
} `json:"panes"`
}
// formatConditional directly maps the conditional format settings of the cells.
type formatConditional struct {
// conditionalOptions directly maps the conditional format settings of the cells.
type conditionalOptions struct {
Type string `json:"type"`
AboveAverage bool `json:"above_average,omitempty"`
Percent bool `json:"percent,omitempty"`
@ -848,47 +852,163 @@ type formatConditional struct {
BarColor string `json:"bar_color,omitempty"`
}
// FormatSheetProtection directly maps the settings of worksheet protection.
type FormatSheetProtection struct {
AlgorithmName string
AutoFilter bool
DeleteColumns bool
DeleteRows bool
EditObjects bool
EditScenarios bool
FormatCells bool
FormatColumns bool
FormatRows bool
InsertColumns bool
InsertHyperlinks bool
InsertRows bool
Password string
PivotTables bool
SelectLockedCells bool
SelectUnlockedCells bool
Sort bool
// SheetProtectionOptions directly maps the settings of worksheet protection.
type SheetProtectionOptions struct {
AlgorithmName string `json:"algorithm_name,omitempty"`
AutoFilter bool `json:"auto_filter,omitempty"`
DeleteColumns bool `json:"delete_columns,omitempty"`
DeleteRows bool `json:"delete_rows,omitempty"`
EditObjects bool `json:"edit_objects,omitempty"`
EditScenarios bool `json:"edit_scenarios,omitempty"`
FormatCells bool `json:"format_cells,omitempty"`
FormatColumns bool `json:"format_columns,omitempty"`
FormatRows bool `json:"format_rows,omitempty"`
InsertColumns bool `json:"insert_columns,omitempty"`
InsertHyperlinks bool `json:"insert_hyperlinks,omitempty"`
InsertRows bool `json:"insert_rows,omitempty"`
Password string `json:"password,omitempty"`
PivotTables bool `json:"pivot_tables,omitempty"`
SelectLockedCells bool `json:"select_locked_cells,omitempty"`
SelectUnlockedCells bool `json:"select_unlocked_cells,omitempty"`
Sort bool `json:"sort,omitempty"`
}
// FormatHeaderFooter directly maps the settings of header and footer.
type FormatHeaderFooter struct {
AlignWithMargins bool
DifferentFirst bool
DifferentOddEven bool
ScaleWithDoc bool
OddHeader string
OddFooter string
EvenHeader string
EvenFooter string
FirstHeader string
FirstFooter string
// HeaderFooterOptions directly maps the settings of header and footer.
type HeaderFooterOptions struct {
AlignWithMargins bool `json:"align_with_margins,omitempty"`
DifferentFirst bool `json:"different_first,omitempty"`
DifferentOddEven bool `json:"different_odd_even,omitempty"`
ScaleWithDoc bool `json:"scale_with_doc,omitempty"`
OddHeader string `json:"odd_header,omitempty"`
OddFooter string `json:"odd_footer,omitempty"`
EvenHeader string `json:"even_header,omitempty"`
EvenFooter string `json:"even_footer,omitempty"`
FirstHeader string `json:"first_header,omitempty"`
FirstFooter string `json:"first_footer,omitempty"`
}
// FormatPageMargins directly maps the settings of page margins
type FormatPageMargins struct {
Bottom string
Footer string
Header string
Left string
Right string
Top string
// PageLayoutMarginsOptions directly maps the settings of page layout margins.
type PageLayoutMarginsOptions struct {
Bottom *float64 `json:"bottom,omitempty"`
Footer *float64 `json:"footer,omitempty"`
Header *float64 `json:"header,omitempty"`
Left *float64 `json:"left,omitempty"`
Right *float64 `json:"right,omitempty"`
Top *float64 `json:"top,omitempty"`
Horizontally *bool `json:"horizontally,omitempty"`
Vertically *bool `json:"vertically,omitempty"`
}
// PageLayoutOptions directly maps the settings of page layout.
type PageLayoutOptions struct {
// Size defines the paper size of the worksheet.
Size *int `json:"size,omitempty"`
// Orientation defines the orientation of page layout for a worksheet.
Orientation *string `json:"orientation,omitempty"`
// FirstPageNumber specified the first printed page number. If no value is
// specified, then 'automatic' is assumed.
FirstPageNumber *uint `json:"first_page_number,omitempty"`
// AdjustTo defines the print scaling. This attribute is restricted to
// value ranging from 10 (10%) to 400 (400%). This setting is overridden
// when fitToWidth and/or fitToHeight are in use.
AdjustTo *uint `json:"adjust_to,omitempty"`
// FitToHeight specified the number of vertical pages to fit on.
FitToHeight *int `json:"fit_to_height,omitempty"`
// FitToWidth specified the number of horizontal pages to fit on.
FitToWidth *int `json:"fit_to_width,omitempty"`
// BlackAndWhite specified print black and white.
BlackAndWhite *bool `json:"black_and_white,omitempty"`
}
// ViewOptions directly maps the settings of sheet view.
type ViewOptions struct {
// DefaultGridColor indicating that the consuming application should use
// the default grid lines color(system dependent). Overrides any color
// specified in colorId.
DefaultGridColor *bool `json:"default_grid_color,omitempty"`
// RightToLeft indicating whether the sheet is in 'right to left' display
// mode. When in this mode, Column A is on the far right, Column B; is one
// column left of Column A, and so on. Also, information in cells is
// displayed in the Right to Left format.
RightToLeft *bool `json:"right_to_left,omitempty"`
// ShowFormulas indicating whether this sheet should display formulas.
ShowFormulas *bool `json:"show_formulas,omitempty"`
// ShowGridLines indicating whether this sheet should display grid lines.
ShowGridLines *bool `json:"show_grid_lines,omitempty"`
// ShowRowColHeaders indicating whether the sheet should display row and
// column headings.
ShowRowColHeaders *bool `json:"show_row_col_headers,omitempty"`
// ShowRuler indicating this sheet should display ruler.
ShowRuler *bool `json:"show_ruler,omitempty"`
// ShowZeros indicating whether to "show a zero in cells that have zero
// value". When using a formula to reference another cell which is empty,
// the referenced value becomes 0 when the flag is true. (Default setting
// is true.)
ShowZeros *bool `json:"show_zeros,omitempty"`
// TopLeftCell specifies a location of the top left visible cell Location
// of the top left visible cell in the bottom right pane (when in
// Left-to-Right mode).
TopLeftCell *string `json:"top_left_cell,omitempty"`
// View indicating how sheet is displayed, by default it uses empty string
// available options: normal, pageLayout, pageBreakPreview
View *string `json:"low_color,omitempty"`
// ZoomScale specifies a window zoom magnification for current view
// representing percent values. This attribute is restricted to values
// ranging from 10 to 400. Horizontal & Vertical scale together.
ZoomScale *float64 `json:"zoom_scale,omitempty"`
}
// SheetPropsOptions directly maps the settings of sheet view.
type SheetPropsOptions struct {
// Specifies a stable name of the sheet, which should not change over time,
// and does not change from user input. This name should be used by code
// to reference a particular sheet.
CodeName *string `json:"code_name,omitempty"`
// EnableFormatConditionsCalculation indicating whether the conditional
// formatting calculations shall be evaluated. If set to false, then the
// min/max values of color scales or data bars or threshold values in Top N
// rules shall not be updated. Essentially the conditional
// formatting "calc" is off.
EnableFormatConditionsCalculation *bool `json:"enable_format_conditions_calculation,omitempty"`
// Published indicating whether the worksheet is published.
Published *bool `json:"published,omitempty"`
// AutoPageBreaks indicating whether the sheet displays Automatic Page
// Breaks.
AutoPageBreaks *bool `json:"auto_page_breaks,omitempty"`
// FitToPage indicating whether the Fit to Page print option is enabled.
FitToPage *bool `json:"fit_to_page,omitempty"`
// TabColorIndexed represents the indexed color value.
TabColorIndexed *int `json:"tab_color_indexed,omitempty"`
// TabColorRGB represents the standard Alpha Red Green Blue color value.
TabColorRGB *string `json:"tab_color_rgb,omitempty"`
// TabColorTheme represents the zero-based index into the collection,
// referencing a particular value expressed in the Theme part.
TabColorTheme *int `json:"tab_color_theme,omitempty"`
// TabColorTint specifies the tint value applied to the color.
TabColorTint *float64 `json:"tab_color_tint,omitempty"`
// OutlineSummaryBelow indicating whether summary rows appear below detail
// in an outline, when applying an outline.
OutlineSummaryBelow *bool `json:"outline_summary_below,omitempty"`
// BaseColWidth specifies the number of characters of the maximum digit
// width of the normal style's font. This value does not include margin
// padding or extra padding for grid lines. It is only the number of
// characters.
BaseColWidth *uint8 `json:"base_col_width,omitempty"`
// DefaultColWidth specifies the default column width measured as the
// number of characters of the maximum digit width of the normal style's
// font.
DefaultColWidth *float64 `json:"default_col_width,omitempty"`
// DefaultRowHeight specifies the default row height measured in point
// size. Optimization so we don't have to write the height on all rows.
// This can be written out if most rows have custom height, to achieve the
// optimization.
DefaultRowHeight *float64 `json:"default_row_height,omitempty"`
// CustomHeight specifies the custom height.
CustomHeight *bool `json:"custom_height,omitempty"`
// ZeroHeight specifies if rows are hidden.
ZeroHeight *bool `json:"zero_height,omitempty"`
// ThickTop specifies if rows have a thick top border by default.
ThickTop *bool `json:"thick_top,omitempty"`
// ThickBottom specifies if rows have a thick bottom border by default.
ThickBottom *bool `json:"thick_bottom,omitempty"`
}