diff --git a/lib.go b/lib.go index b28b50f..2f3df35 100644 --- a/lib.go +++ b/lib.go @@ -121,3 +121,14 @@ func deepCopy(dst, src interface{}) error { } return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst) } + +// boolPtr returns a pointer to a bool with the given value. +func boolPtr(b bool) *bool { return &b } + +// defaultTrue returns true if b is nil, or the pointed value. +func defaultTrue(b *bool) bool { + if b == nil { + return true + } + return *b +} diff --git a/sheetview.go b/sheetview.go new file mode 100644 index 0000000..d26b8cb --- /dev/null +++ b/sheetview.go @@ -0,0 +1,138 @@ +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 { + getSheetViewOption(view *xlsxSheetView) +} + +type ( + // DefaultGridColor is a SheetViewOption. + DefaultGridColor bool + // RightToLeft is a SheetViewOption. + RightToLeft bool + // ShowFormulas is a SheetViewOption. + ShowFormulas bool + // ShowGridLines is a SheetViewOption. + ShowGridLines bool + // ShowRowColHeaders is a SheetViewOption. + ShowRowColHeaders bool + /* TODO + // ShowWhiteSpace is a SheetViewOption. + ShowWhiteSpace bool + // ShowZeros is a SheetViewOption. + ShowZeros bool + // WindowProtection is a SheetViewOption. + WindowProtection bool + */ +) + +// 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 RightToLeft) setSheetViewOption(view *xlsxSheetView) { + view.RightToLeft = bool(o) // Excel default: false +} + +func (o *RightToLeft) getSheetViewOption(view *xlsxSheetView) { + *o = RightToLeft(view.RightToLeft) +} + +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 +} + +// getSheetView returns the SheetView object +func (f *File) getSheetView(sheetName string, viewIndex int) (*xlsxSheetView, error) { + xlsx := f.workSheetReader(sheetName) + if viewIndex < 0 { + if viewIndex < -len(xlsx.SheetViews.SheetView) { + return nil, fmt.Errorf("view index %d out of range", viewIndex) + } + viewIndex = len(xlsx.SheetViews.SheetView) + viewIndex + } else if viewIndex >= len(xlsx.SheetViews.SheetView) { + return nil, fmt.Errorf("view index %d out of range", viewIndex) + } + + return &(xlsx.SheetViews.SheetView[viewIndex]), nil +} + +// 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) +// RightToLeft(bool) +// ShowFormulas(bool) +// ShowGridLines(bool) +// ShowRowColHeaders(bool) +// Example: +// err = f.SetSheetViewOptions("Sheet1", -1, ShowGridLines(false)) +func (f *File) SetSheetViewOptions(name string, viewIndex int, opts ...SheetViewOption) error { + view, err := f.getSheetView(name, 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) +// RightToLeft(bool) +// ShowFormulas(bool) +// ShowGridLines(bool) +// ShowRowColHeaders(bool) +// Example: +// var showGridLines excelize.ShowGridLines +// err = f.GetSheetViewOptions("Sheet1", -1, &showGridLines) +func (f *File) GetSheetViewOptions(name string, viewIndex int, opts ...SheetViewOptionPtr) error { + view, err := f.getSheetView(name, viewIndex) + if err != nil { + return err + } + + for _, opt := range opts { + opt.getSheetViewOption(view) + } + return nil +} diff --git a/sheetview_test.go b/sheetview_test.go new file mode 100644 index 0000000..348b9b7 --- /dev/null +++ b/sheetview_test.go @@ -0,0 +1,122 @@ +package excelize_test + +import ( + "fmt" + "testing" + + "github.com/360EntSecGroup-Skylar/excelize" +) + +var _ = []excelize.SheetViewOption{ + excelize.DefaultGridColor(true), + excelize.RightToLeft(false), + excelize.ShowFormulas(false), + excelize.ShowGridLines(true), + excelize.ShowRowColHeaders(true), +} + +var _ = []excelize.SheetViewOptionPtr{ + (*excelize.DefaultGridColor)(nil), + (*excelize.RightToLeft)(nil), + (*excelize.ShowFormulas)(nil), + (*excelize.ShowGridLines)(nil), + (*excelize.ShowRowColHeaders)(nil), +} + +func ExampleFile_SetSheetViewOptions() { + xl := excelize.NewFile() + const sheet = "Sheet1" + + if err := xl.SetSheetViewOptions(sheet, 0, + excelize.DefaultGridColor(false), + excelize.RightToLeft(false), + excelize.ShowFormulas(true), + excelize.ShowGridLines(true), + excelize.ShowRowColHeaders(true), + ); err != nil { + panic(err) + } + // Output: +} + +func ExampleFile_GetSheetViewOptions() { + xl := excelize.NewFile() + const sheet = "Sheet1" + + var ( + defaultGridColor excelize.DefaultGridColor + rightToLeft excelize.RightToLeft + showFormulas excelize.ShowFormulas + showGridLines excelize.ShowGridLines + showRowColHeaders excelize.ShowRowColHeaders + ) + + if err := xl.GetSheetViewOptions(sheet, 0, + &defaultGridColor, + &rightToLeft, + &showFormulas, + &showGridLines, + &showRowColHeaders, + ); err != nil { + panic(err) + } + + fmt.Println("Default:") + fmt.Println("- defaultGridColor:", defaultGridColor) + fmt.Println("- rightToLeft:", rightToLeft) + fmt.Println("- showFormulas:", showFormulas) + fmt.Println("- showGridLines:", showGridLines) + fmt.Println("- showRowColHeaders:", showRowColHeaders) + + if err := xl.SetSheetViewOptions(sheet, 0, excelize.ShowGridLines(false)); err != nil { + panic(err) + } + + if err := xl.GetSheetViewOptions(sheet, 0, &showGridLines); err != nil { + panic(err) + } + + fmt.Println("After change:") + fmt.Println("- showGridLines:", showGridLines) + + // Output: + // Default: + // - defaultGridColor: true + // - rightToLeft: false + // - showFormulas: false + // - showGridLines: true + // - showRowColHeaders: true + // After change: + // - showGridLines: false +} + +func TestSheetViewOptionsErrors(t *testing.T) { + xl := excelize.NewFile() + const sheet = "Sheet1" + + if err := xl.GetSheetViewOptions(sheet, 0); err != nil { + t.Errorf("Unexpected error: %s", err) + } + if err := xl.GetSheetViewOptions(sheet, -1); err != nil { + t.Errorf("Unexpected error: %s", err) + } + if err := xl.GetSheetViewOptions(sheet, 1); err == nil { + t.Error("Error expected but got nil") + } + if err := xl.GetSheetViewOptions(sheet, -2); err == nil { + t.Error("Error expected but got nil") + } + + if err := xl.SetSheetViewOptions(sheet, 0); err != nil { + t.Errorf("Unexpected error: %s", err) + } + if err := xl.SetSheetViewOptions(sheet, -1); err != nil { + t.Errorf("Unexpected error: %s", err) + } + if err := xl.SetSheetViewOptions(sheet, 1); err == nil { + t.Error("Error expected but got nil") + } + if err := xl.SetSheetViewOptions(sheet, -2); err == nil { + t.Error("Error expected but got nil") + } +} diff --git a/xmlWorksheet.go b/xmlWorksheet.go index de7ea93..22feca8 100644 --- a/xmlWorksheet.go +++ b/xmlWorksheet.go @@ -145,17 +145,18 @@ type xlsxSheetViews struct { // last sheetView definition is loaded, and the others are discarded. When // multiple windows are viewing the same sheet, multiple sheetView elements // (with corresponding workbookView entries) are saved. +// See https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.sheetview.aspx type xlsxSheetView struct { WindowProtection bool `xml:"windowProtection,attr,omitempty"` ShowFormulas bool `xml:"showFormulas,attr,omitempty"` - ShowGridLines string `xml:"showGridLines,attr,omitempty"` - ShowRowColHeaders bool `xml:"showRowColHeaders,attr,omitempty"` + ShowGridLines *bool `xml:"showGridLines,attr"` + ShowRowColHeaders *bool `xml:"showRowColHeaders,attr"` ShowZeros bool `xml:"showZeros,attr,omitempty"` RightToLeft bool `xml:"rightToLeft,attr,omitempty"` TabSelected bool `xml:"tabSelected,attr,omitempty"` ShowWhiteSpace *bool `xml:"showWhiteSpace,attr"` ShowOutlineSymbols bool `xml:"showOutlineSymbols,attr,omitempty"` - DefaultGridColor bool `xml:"defaultGridColor,attr"` + DefaultGridColor *bool `xml:"defaultGridColor,attr"` View string `xml:"view,attr,omitempty"` TopLeftCell string `xml:"topLeftCell,attr,omitempty"` ColorID int `xml:"colorId,attr,omitempty"`