unioffice/spreadsheet/stylesheet.go
2017-09-23 10:01:17 -04:00

201 lines
5.7 KiB
Go

// Copyright 2017 Baliance. All rights reserved.
//
// Use of this source code is governed by the terms of the Affero GNU General
// Public License version 3.0 as published by the Free Software Foundation and
// appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com.
package spreadsheet
import (
"errors"
"baliance.com/gooxml"
"baliance.com/gooxml/schema/soo/sml"
)
// StyleSheet is a document style sheet.
type StyleSheet struct {
wb *Workbook
x *sml.StyleSheet
}
// NewStyleSheet constructs a new default stylesheet.
func NewStyleSheet(wb *Workbook) StyleSheet {
ss := sml.NewStyleSheet()
ss.CellStyleXfs = sml.NewCT_CellStyleXfs()
ss.CellXfs = sml.NewCT_CellXfs()
ss.CellStyles = sml.NewCT_CellStyles()
cs := sml.NewCT_CellStyle()
cs.NameAttr = gooxml.String("Normal")
cs.XfIdAttr = 0
cs.BuiltinIdAttr = gooxml.Uint32(0)
ss.CellStyles.CellStyle = append(ss.CellStyles.CellStyle, cs)
ss.CellStyles.CountAttr = gooxml.Uint32(uint32(len(ss.CellStyles.CellStyle)))
xf := sml.NewCT_Xf()
xf.NumFmtIdAttr = gooxml.Uint32(0)
xf.FontIdAttr = gooxml.Uint32(0)
xf.FillIdAttr = gooxml.Uint32(0)
xf.BorderIdAttr = gooxml.Uint32(0)
ss.CellStyleXfs.Xf = append(ss.CellStyleXfs.Xf, xf)
ss.CellStyleXfs.CountAttr = gooxml.Uint32(uint32(len(ss.CellStyleXfs.Xf)))
fills := NewFills()
ss.Fills = fills.X()
fill := fills.AddFill().SetPatternFill()
fill.SetPattern(sml.ST_PatternTypeNone)
fill = fills.AddFill().SetPatternFill()
fill.SetPattern(sml.ST_PatternTypeGray125)
ss.Fonts = sml.NewCT_Fonts()
ss.Borders = sml.NewCT_Borders()
s := StyleSheet{wb, ss}
// default empty border
s.AddBorder().InitializeDefaults()
fnt := s.AddFont()
fnt.SetName("Calibri")
fnt.SetSize(11)
xf2 := sml.NewCT_Xf()
*xf2 = *xf
xf2.XfIdAttr = gooxml.Uint32(0)
ss.CellXfs.Xf = append(ss.CellXfs.Xf, xf2)
ss.CellXfs.CountAttr = gooxml.Uint32(uint32(len(ss.CellXfs.Xf)))
return s
}
// X returns the inner XML entity for a stylesheet.
func (s StyleSheet) X() *sml.StyleSheet {
return s.x
}
// AddFont adds a new empty font to the stylesheet.
func (s StyleSheet) AddFont() Font {
font := sml.NewCT_Font()
s.x.Fonts.Font = append(s.x.Fonts.Font, font)
s.x.Fonts.CountAttr = gooxml.Uint32(uint32(len(s.x.Fonts.Font)))
return Font{font, s.x}
}
// AddBorder creates a new empty border that can be applied to a cell style.
func (s StyleSheet) AddBorder() Border {
b := sml.NewCT_Border()
s.x.Borders.Border = append(s.x.Borders.Border, b)
s.x.Borders.CountAttr = gooxml.Uint32(uint32(len(s.x.Borders.Border)))
return Border{b, s.x.Borders}
}
// RemoveFont removes a font from the style sheet. It *does not* update styles that refer
// to this font.
func (s StyleSheet) RemoveFont(f Font) error {
for i, sf := range s.x.Fonts.Font {
if sf == f.X() {
s.x.Fonts.Font = append(s.x.Fonts.Font[:i],
s.x.Fonts.Font[i+1:]...)
return nil
}
}
return errors.New("font not found")
}
// Fonts returns the list of fonts defined in the stylesheet.
func (s StyleSheet) Fonts() []Font {
ret := []Font{}
for _, f := range s.x.Fonts.Font {
ret = append(ret, Font{f, s.x})
}
return ret
}
// AddCellStyle adds a new empty cell style to the stylesheet.
func (s StyleSheet) AddCellStyle() CellStyle {
xf := sml.NewCT_Xf()
s.x.CellXfs.Xf = append(s.x.CellXfs.Xf, xf)
s.x.CellXfs.CountAttr = gooxml.Uint32(uint32(len(s.x.CellXfs.Xf)))
return CellStyle{s.wb, xf, s.x.CellXfs}
}
// CellStyles returns the list of defined cell styles
func (s StyleSheet) CellStyles() []CellStyle {
ret := []CellStyle{}
for _, xf := range s.x.CellXfs.Xf {
ret = append(ret, CellStyle{s.wb, xf, s.x.CellXfs})
}
return ret
}
// AddDifferentialStyle adds a new empty differential cell style to the stylesheet.
func (s StyleSheet) AddDifferentialStyle() DifferentialStyle {
if s.x.Dxfs == nil {
s.x.Dxfs = sml.NewCT_Dxfs()
}
dxf := sml.NewCT_Dxf()
s.x.Dxfs.Dxf = append(s.x.Dxfs.Dxf, dxf)
s.x.Dxfs.CountAttr = gooxml.Uint32(uint32(len(s.x.Dxfs.Dxf)))
return DifferentialStyle{dxf, s.wb, s.x.Dxfs}
}
// GetOrCreateStandardNumberFormat gets or creates a cell style with a given
// standard format. This should only be used when you want to perform
// number/date/time formatting only. Manipulating the style returned will cause
// all cells using style returned from this for a given format to be formatted.
func (s StyleSheet) GetOrCreateStandardNumberFormat(f StandardFormat) CellStyle {
for _, cs := range s.CellStyles() {
// found an existing number format
if cs.HasNumberFormat() && cs.NumberFormat() == uint32(f) {
return cs
}
}
// need to create a new format
cs := s.AddCellStyle()
cs.SetNumberFormatStandard(f)
return cs
}
// AddNumberFormat adds a new blank number format to the stylesheet.
func (s StyleSheet) AddNumberFormat() NumberFormat {
if s.x.NumFmts == nil {
s.x.NumFmts = sml.NewCT_NumFmts()
}
nf := sml.NewCT_NumFmt()
// start our IDs at 200 so we can ensure we don't conflict with any
// pre-defined formats
nf.NumFmtIdAttr = uint32(200 + len(s.x.NumFmts.NumFmt))
s.x.NumFmts.NumFmt = append(s.x.NumFmts.NumFmt, nf)
s.x.NumFmts.CountAttr = gooxml.Uint32(uint32(len(s.x.NumFmts.NumFmt)))
return NumberFormat{s.wb, nf}
}
// Fills returns a Fills object that can be used to add/create/edit fills.
func (s StyleSheet) Fills() Fills {
return Fills{s.x.Fills}
}
func (s StyleSheet) GetCellStyle(id uint32) CellStyle {
for i, f := range s.x.CellXfs.Xf {
if uint32(i) == id {
return CellStyle{s.wb, f, s.x.CellXfs}
}
}
return CellStyle{}
}
func (s StyleSheet) GetNumberFormat(id uint32) NumberFormat {
if id >= 0 && id < 50 {
return CreateDefaultNumberFormat(StandardFormat(id))
}
for _, nf := range s.x.NumFmts.NumFmt {
if nf.NumFmtIdAttr == id {
return NumberFormat{s.wb, nf}
}
}
return NumberFormat{}
}