spreadsheet: merge spreadsheet/style package into spreadsheet

This commit is contained in:
Todd 2017-09-02 15:27:53 -05:00
parent 3e1bcdd646
commit d186678dbb
15 changed files with 83 additions and 34 deletions

View File

@ -0,0 +1,30 @@
// Copyright 2017 Baliance. All rights reserved.
package main
import (
"log"
"baliance.com/gooxml/spreadsheet"
)
var lorem = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin lobortis, lectus dictum feugiat tempus, sem neque finibus enim, sed eleifend sem nunc ac diam. Vestibulum tempus sagittis elementum`
func main() {
ss := spreadsheet.New()
// add a single sheet
sheet := ss.AddSheet()
row := sheet.AddRow()
cell := row.AddCell()
wrapped := ss.StyleSheet.AddCellStyle()
wrapped.SetWrapped(true)
cell.SetString(lorem)
cell.SetStyle(wrapped)
if err := ss.Validate(); err != nil {
log.Fatalf("error validating sheet: %s", err)
}
ss.SaveToFile("wrapped.xlsx")
}

Binary file not shown.

View File

@ -5,7 +5,7 @@
// appearing in the file LICENSE included in the packaging of this file. A // appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com. // commercial license can be purchased by contacting sales@baliance.com.
package styles package spreadsheet
import sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" import sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml"

View File

@ -12,7 +12,6 @@ import (
"baliance.com/gooxml" "baliance.com/gooxml"
sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml"
"baliance.com/gooxml/spreadsheet/styles"
) )
// Cell is a single cell within a sheet. // Cell is a single cell within a sheet.
@ -73,7 +72,7 @@ func (c Cell) SetBool(v bool) {
// SetStyle applies a style to the cell. This style is referenced in the generated XML // SetStyle applies a style to the cell. This style is referenced in the generated XML
// via CellStyle.Index(). // via CellStyle.Index().
func (c Cell) SetStyle(cs styles.CellStyle) { func (c Cell) SetStyle(cs CellStyle) {
c.x.SAttr = gooxml.Uint32(cs.Index()) c.x.SAttr = gooxml.Uint32(cs.Index())
} }

View File

@ -13,7 +13,7 @@ import sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml"
func TestCell(t *testing.T) { func TestCell(t *testing.T) {
wb := spreadsheet.New() wb := spreadsheet.New()
sheet := wb.AddSheet("test") sheet := wb.AddSheet()
row := sheet.AddRow() row := sheet.AddRow()
cell := row.AddCell() cell := row.AddCell()

View File

@ -5,20 +5,42 @@
// appearing in the file LICENSE included in the packaging of this file. A // appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com. // commercial license can be purchased by contacting sales@baliance.com.
package styles package spreadsheet
import ( import (
"baliance.com/gooxml" "baliance.com/gooxml"
sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml"
) )
// CellStyle is a formatting style for a cell. CellStyles are spreadsheet global
// and can be applied to cells across sheets.
type CellStyle struct { type CellStyle struct {
xf *sml.CT_Xf xf *sml.CT_Xf
xfs *sml.CT_CellXfs xfs *sml.CT_CellXfs
} }
func NewCellStyle(xf *sml.CT_Xf, xfs *sml.CT_CellXfs) CellStyle { // Wrapped returns true if the cell will wrap text.
return CellStyle{xf, xfs} func (cs CellStyle) Wrapped() bool {
if cs.xf.Alignment == nil {
return false
}
if cs.xf.Alignment.WrapTextAttr == nil {
return false
}
return *cs.xf.Alignment.WrapTextAttr
}
// SetWrapped configures the cell to wrap text.
func (cs CellStyle) SetWrapped(b bool) {
if cs.xf.Alignment == nil {
cs.xf.Alignment = sml.NewCT_CellAlignment()
}
if !b {
cs.xf.Alignment.WrapTextAttr = nil
} else {
cs.xf.Alignment.WrapTextAttr = gooxml.Bool(true)
cs.xf.ApplyAlignmentAttr = gooxml.Bool(true)
}
} }
// SetHorizontalAlignment sets the horizontal alignment of a cell style. // SetHorizontalAlignment sets the horizontal alignment of a cell style.
@ -26,8 +48,8 @@ func (cs CellStyle) SetHorizontalAlignment(a sml.ST_HorizontalAlignment) {
if cs.xf.Alignment == nil { if cs.xf.Alignment == nil {
cs.xf.Alignment = sml.NewCT_CellAlignment() cs.xf.Alignment = sml.NewCT_CellAlignment()
} }
cs.xf.ApplyAlignmentAttr = gooxml.Bool(true)
cs.xf.Alignment.HorizontalAttr = a cs.xf.Alignment.HorizontalAttr = a
cs.xf.ApplyAlignmentAttr = gooxml.Bool(true)
} }
// SetVerticalAlignment sets the vertical alignment of a cell style. // SetVerticalAlignment sets the vertical alignment of a cell style.

View File

@ -5,7 +5,7 @@
// appearing in the file LICENSE included in the packaging of this file. A // appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com. // commercial license can be purchased by contacting sales@baliance.com.
package styles package spreadsheet
import sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" import sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml"

View File

@ -5,25 +5,24 @@
// appearing in the file LICENSE included in the packaging of this file. A // appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com. // commercial license can be purchased by contacting sales@baliance.com.
package styles package spreadsheet
import ( import (
"baliance.com/gooxml/color" "baliance.com/gooxml/color"
sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml"
) )
// Font allows editing fonts within a spreadsheet stylesheet.
type Font struct { type Font struct {
font *sml.CT_Font font *sml.CT_Font
styles *sml.StyleSheet styles *sml.StyleSheet
} }
func NewFont(font *sml.CT_Font, styles *sml.StyleSheet) Font { // X returns the inner wrapped XML type.
return Font{font, styles}
}
func (f Font) X() *sml.CT_Font { func (f Font) X() *sml.CT_Font {
return f.font return f.font
} }
func (f Font) Index() uint32 { func (f Font) Index() uint32 {
for i, sf := range f.styles.Fonts.Font { for i, sf := range f.styles.Fonts.Font {
if f.font == sf { if f.font == sf {

View File

@ -5,7 +5,7 @@
// appearing in the file LICENSE included in the packaging of this file. A // appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com. // commercial license can be purchased by contacting sales@baliance.com.
package styles package spreadsheet
import ( import (
"baliance.com/gooxml/color" "baliance.com/gooxml/color"

View File

@ -5,7 +5,7 @@
// appearing in the file LICENSE included in the packaging of this file. A // appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com. // commercial license can be purchased by contacting sales@baliance.com.
package styles package spreadsheet
import ( import (
"errors" "errors"
@ -76,7 +76,7 @@ func (s StyleSheet) AddFont() Font {
font := sml.NewCT_Font() font := sml.NewCT_Font()
s.x.Fonts.Font = append(s.x.Fonts.Font, font) s.x.Fonts.Font = append(s.x.Fonts.Font, font)
s.x.Fonts.CountAttr = gooxml.Uint32(uint32(len(s.x.Fonts.Font))) s.x.Fonts.CountAttr = gooxml.Uint32(uint32(len(s.x.Fonts.Font)))
return NewFont(font, s.x) return Font{font, s.x}
} }
// RemoveFont removes a font from the style sheet. It *does not* update styles that refer // RemoveFont removes a font from the style sheet. It *does not* update styles that refer
@ -96,7 +96,7 @@ func (s StyleSheet) RemoveFont(f Font) error {
func (s StyleSheet) Fonts() []Font { func (s StyleSheet) Fonts() []Font {
ret := []Font{} ret := []Font{}
for _, f := range s.x.Fonts.Font { for _, f := range s.x.Fonts.Font {
ret = append(ret, NewFont(f, s.x)) ret = append(ret, Font{f, s.x})
} }
return ret return ret
} }
@ -106,7 +106,7 @@ func (s StyleSheet) AddCellStyle() CellStyle {
xf := sml.NewCT_Xf() xf := sml.NewCT_Xf()
s.x.CellXfs.Xf = append(s.x.CellXfs.Xf, xf) s.x.CellXfs.Xf = append(s.x.CellXfs.Xf, xf)
s.x.CellXfs.CountAttr = gooxml.Uint32(uint32(len(s.x.CellXfs.Xf))) s.x.CellXfs.CountAttr = gooxml.Uint32(uint32(len(s.x.CellXfs.Xf)))
return NewCellStyle(xf, s.x.CellXfs) return CellStyle{xf, s.x.CellXfs}
} }
// Fills returns a Fills object that can be used to add/create/edit fills. // Fills returns a Fills object that can be used to add/create/edit fills.

View File

@ -5,7 +5,7 @@
// appearing in the file LICENSE included in the packaging of this file. A // appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com. // commercial license can be purchased by contacting sales@baliance.com.
package styles_test package spreadsheet_test
import ( import (
"bytes" "bytes"
@ -14,7 +14,7 @@ import (
"os" "os"
"testing" "testing"
"baliance.com/gooxml/spreadsheet/styles" "baliance.com/gooxml/spreadsheet"
"baliance.com/gooxml/testhelper" "baliance.com/gooxml/testhelper"
"baliance.com/gooxml/zippkg" "baliance.com/gooxml/zippkg"
) )
@ -22,25 +22,25 @@ import (
func TestStyleSheetUnmarshal(t *testing.T) { func TestStyleSheetUnmarshal(t *testing.T) {
f, err := os.Open("testdata/styles.xml") f, err := os.Open("testdata/styles.xml")
if err != nil { if err != nil {
t.Fatalf("error reading content types file") t.Fatalf("error reading styles.xml")
} }
dec := xml.NewDecoder(f) dec := xml.NewDecoder(f)
r := styles.NewStyleSheet() r := spreadsheet.NewStyleSheet()
if err := dec.Decode(r.X()); err != nil { if err := dec.Decode(r.X()); err != nil {
t.Errorf("error decoding content types: %s", err) t.Errorf("error decoding styles.xml: %s", err)
} }
got := &bytes.Buffer{} got := &bytes.Buffer{}
fmt.Fprintf(got, zippkg.XMLHeader) fmt.Fprintf(got, zippkg.XMLHeader)
enc := xml.NewEncoder(zippkg.SelfClosingWriter{W: got}) enc := xml.NewEncoder(zippkg.SelfClosingWriter{W: got})
if err := enc.Encode(r.X()); err != nil { if err := enc.Encode(r.X()); err != nil {
t.Errorf("error encoding content types: %s", err) t.Errorf("error encoding styles.xml: %s", err)
} }
testhelper.CompareGoldenXML(t, "styles.xml", got.Bytes()) testhelper.CompareGoldenXML(t, "styles.xml", got.Bytes())
} }
func TestStyleSheetFonts(t *testing.T) { func TestStyleSheetFonts(t *testing.T) {
ss := styles.NewStyleSheet() ss := spreadsheet.NewStyleSheet()
fc := len(ss.Fonts()) fc := len(ss.Fonts())
ft := ss.AddFont() ft := ss.AddFont()

View File

@ -19,7 +19,6 @@ import (
"baliance.com/gooxml/common" "baliance.com/gooxml/common"
"baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml"
"baliance.com/gooxml/spreadsheet/styles"
"baliance.com/gooxml/zippkg" "baliance.com/gooxml/zippkg"
) )
@ -28,7 +27,7 @@ type Workbook struct {
common.DocBase common.DocBase
x *spreadsheetml.Workbook x *spreadsheetml.Workbook
StyleSheet styles.StyleSheet StyleSheet StyleSheet
Theme common.Theme Theme common.Theme
SharedStrings SharedStrings SharedStrings SharedStrings
xws []*spreadsheetml.Worksheet xws []*spreadsheetml.Worksheet
@ -43,7 +42,7 @@ func New() *Workbook {
wb.AppProperties = common.NewAppProperties() wb.AppProperties = common.NewAppProperties()
wb.CoreProperties = common.NewCoreProperties() wb.CoreProperties = common.NewCoreProperties()
wb.StyleSheet = styles.NewStyleSheet() wb.StyleSheet = NewStyleSheet()
wb.Rels = common.NewRelationships() wb.Rels = common.NewRelationships()
wb.wbRels = common.NewRelationships() wb.wbRels = common.NewRelationships()
@ -148,7 +147,7 @@ func Read(r io.ReaderAt, size int64) (*Workbook, error) {
basePaths[wksRel] = basePath basePaths[wksRel] = basePath
wb.xwsRels = append(wb.xwsRels, wksRel) wb.xwsRels = append(wb.xwsRels, wksRel)
case common.StylesType: case common.StylesType:
wb.StyleSheet = styles.NewStyleSheet() wb.StyleSheet = NewStyleSheet()
decMap[basePaths[wb.wbRels]+r.Target()] = wb.StyleSheet.X() decMap[basePaths[wb.wbRels]+r.Target()] = wb.StyleSheet.X()
case common.ThemeType: case common.ThemeType:
wb.Theme = common.NewTheme() wb.Theme = common.NewTheme()

View File

@ -67,7 +67,7 @@ func TestWorkbookUnmarshal(t *testing.T) {
func TestSimpleSheet(t *testing.T) { func TestSimpleSheet(t *testing.T) {
wb := spreadsheet.New() wb := spreadsheet.New()
sheet := wb.AddSheet("foo") sheet := wb.AddSheet()
row := sheet.AddRow() row := sheet.AddRow()
cell := row.AddCell() cell := row.AddCell()
cell.SetString("testing 123") cell.SetString("testing 123")
@ -114,14 +114,14 @@ func TestSheetCount(t *testing.T) {
if wb.SheetCount() != 0 { if wb.SheetCount() != 0 {
t.Errorf("expected 0 sheets, got %d", wb.SheetCount()) t.Errorf("expected 0 sheets, got %d", wb.SheetCount())
} }
wb.AddSheet("Sheet 1") wb.AddSheet()
if err := wb.Validate(); err != nil { if err := wb.Validate(); err != nil {
t.Errorf("created an invalid spreadsheet: %s", err) t.Errorf("created an invalid spreadsheet: %s", err)
} }
if wb.SheetCount() != 1 { if wb.SheetCount() != 1 {
t.Errorf("expected 1 sheets, got %d", wb.SheetCount()) t.Errorf("expected 1 sheets, got %d", wb.SheetCount())
} }
wb.AddSheet("Sheet 2") wb.AddSheet()
if err := wb.Validate(); err != nil { if err := wb.Validate(); err != nil {
t.Errorf("created an invalid spreadsheet: %s", err) t.Errorf("created an invalid spreadsheet: %s", err)
} }
@ -132,7 +132,7 @@ func TestSheetCount(t *testing.T) {
func TestPreserveSpace(t *testing.T) { func TestPreserveSpace(t *testing.T) {
ss := spreadsheet.New() ss := spreadsheet.New()
sheet := ss.AddSheet("Sheet 1") sheet := ss.AddSheet()
row := sheet.AddRow() row := sheet.AddRow()
values := []string{" foo ", " bar \t", "foo\r\nbar", "\t\r\nfoo\t123\r\n"} values := []string{" foo ", " bar \t", "foo\r\nbar", "\t\r\nfoo\t123\r\n"}
for i, s := range values { for i, s := range values {