diff --git a/_examples/spreadsheet/simple/simple.xlsx b/_examples/spreadsheet/simple/simple.xlsx index dffb6668..58c741e3 100644 Binary files a/_examples/spreadsheet/simple/simple.xlsx and b/_examples/spreadsheet/simple/simple.xlsx differ diff --git a/_examples/spreadsheet/wrapped-text/main.go b/_examples/spreadsheet/wrapped-text/main.go new file mode 100644 index 00000000..f7dd7967 --- /dev/null +++ b/_examples/spreadsheet/wrapped-text/main.go @@ -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") +} diff --git a/_examples/spreadsheet/wrapped-text/wrapped.xlsx b/_examples/spreadsheet/wrapped-text/wrapped.xlsx new file mode 100644 index 00000000..38be266d Binary files /dev/null and b/_examples/spreadsheet/wrapped-text/wrapped.xlsx differ diff --git a/spreadsheet/styles/borders.go b/spreadsheet/borders.go similarity index 97% rename from spreadsheet/styles/borders.go rename to spreadsheet/borders.go index 78ac39bb..55c7b9ab 100644 --- a/spreadsheet/styles/borders.go +++ b/spreadsheet/borders.go @@ -5,7 +5,7 @@ // appearing in the file LICENSE included in the packaging of this file. A // commercial license can be purchased by contacting sales@baliance.com. -package styles +package spreadsheet import sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" diff --git a/spreadsheet/cell.go b/spreadsheet/cell.go index 600e83b2..b4360099 100644 --- a/spreadsheet/cell.go +++ b/spreadsheet/cell.go @@ -12,7 +12,6 @@ import ( "baliance.com/gooxml" sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" - "baliance.com/gooxml/spreadsheet/styles" ) // 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 // via CellStyle.Index(). -func (c Cell) SetStyle(cs styles.CellStyle) { +func (c Cell) SetStyle(cs CellStyle) { c.x.SAttr = gooxml.Uint32(cs.Index()) } diff --git a/spreadsheet/cell_test.go b/spreadsheet/cell_test.go index 144e9578..33f5c28b 100644 --- a/spreadsheet/cell_test.go +++ b/spreadsheet/cell_test.go @@ -13,7 +13,7 @@ import sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" func TestCell(t *testing.T) { wb := spreadsheet.New() - sheet := wb.AddSheet("test") + sheet := wb.AddSheet() row := sheet.AddRow() cell := row.AddCell() diff --git a/spreadsheet/styles/cellstyle.go b/spreadsheet/cellstyle.go similarity index 72% rename from spreadsheet/styles/cellstyle.go rename to spreadsheet/cellstyle.go index 87819cf3..59a29247 100644 --- a/spreadsheet/styles/cellstyle.go +++ b/spreadsheet/cellstyle.go @@ -5,20 +5,42 @@ // appearing in the file LICENSE included in the packaging of this file. A // commercial license can be purchased by contacting sales@baliance.com. -package styles +package spreadsheet import ( "baliance.com/gooxml" 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 { xf *sml.CT_Xf xfs *sml.CT_CellXfs } -func NewCellStyle(xf *sml.CT_Xf, xfs *sml.CT_CellXfs) CellStyle { - return CellStyle{xf, xfs} +// Wrapped returns true if the cell will wrap text. +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. @@ -26,8 +48,8 @@ func (cs CellStyle) SetHorizontalAlignment(a sml.ST_HorizontalAlignment) { if cs.xf.Alignment == nil { cs.xf.Alignment = sml.NewCT_CellAlignment() } - cs.xf.ApplyAlignmentAttr = gooxml.Bool(true) cs.xf.Alignment.HorizontalAttr = a + cs.xf.ApplyAlignmentAttr = gooxml.Bool(true) } // SetVerticalAlignment sets the vertical alignment of a cell style. diff --git a/spreadsheet/styles/fills.go b/spreadsheet/fills.go similarity index 97% rename from spreadsheet/styles/fills.go rename to spreadsheet/fills.go index de1a671c..cfdeaf66 100644 --- a/spreadsheet/styles/fills.go +++ b/spreadsheet/fills.go @@ -5,7 +5,7 @@ // appearing in the file LICENSE included in the packaging of this file. A // commercial license can be purchased by contacting sales@baliance.com. -package styles +package spreadsheet import sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" diff --git a/spreadsheet/styles/font.go b/spreadsheet/font.go similarity index 91% rename from spreadsheet/styles/font.go rename to spreadsheet/font.go index 027a0984..0f60d3f3 100644 --- a/spreadsheet/styles/font.go +++ b/spreadsheet/font.go @@ -5,25 +5,24 @@ // appearing in the file LICENSE included in the packaging of this file. A // commercial license can be purchased by contacting sales@baliance.com. -package styles +package spreadsheet import ( "baliance.com/gooxml/color" sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" ) +// Font allows editing fonts within a spreadsheet stylesheet. type Font struct { font *sml.CT_Font styles *sml.StyleSheet } -func NewFont(font *sml.CT_Font, styles *sml.StyleSheet) Font { - return Font{font, styles} -} - +// X returns the inner wrapped XML type. func (f Font) X() *sml.CT_Font { return f.font } + func (f Font) Index() uint32 { for i, sf := range f.styles.Fonts.Font { if f.font == sf { diff --git a/spreadsheet/styles/patternfill.go b/spreadsheet/patternfill.go similarity index 98% rename from spreadsheet/styles/patternfill.go rename to spreadsheet/patternfill.go index 5f820cfe..32bce595 100644 --- a/spreadsheet/styles/patternfill.go +++ b/spreadsheet/patternfill.go @@ -5,7 +5,7 @@ // appearing in the file LICENSE included in the packaging of this file. A // commercial license can be purchased by contacting sales@baliance.com. -package styles +package spreadsheet import ( "baliance.com/gooxml/color" diff --git a/spreadsheet/styles/stylesheet.go b/spreadsheet/stylesheet.go similarity index 96% rename from spreadsheet/styles/stylesheet.go rename to spreadsheet/stylesheet.go index 2424e3fc..12aeba7a 100644 --- a/spreadsheet/styles/stylesheet.go +++ b/spreadsheet/stylesheet.go @@ -5,7 +5,7 @@ // appearing in the file LICENSE included in the packaging of this file. A // commercial license can be purchased by contacting sales@baliance.com. -package styles +package spreadsheet import ( "errors" @@ -76,7 +76,7 @@ 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 NewFont(font, s.x) + return Font{font, s.x} } // 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 { ret := []Font{} for _, f := range s.x.Fonts.Font { - ret = append(ret, NewFont(f, s.x)) + ret = append(ret, Font{f, s.x}) } return ret } @@ -106,7 +106,7 @@ 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 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. diff --git a/spreadsheet/styles/stylesheet_test.go b/spreadsheet/stylesheet_test.go similarity index 83% rename from spreadsheet/styles/stylesheet_test.go rename to spreadsheet/stylesheet_test.go index ee439ce6..36277b64 100644 --- a/spreadsheet/styles/stylesheet_test.go +++ b/spreadsheet/stylesheet_test.go @@ -5,7 +5,7 @@ // appearing in the file LICENSE included in the packaging of this file. A // commercial license can be purchased by contacting sales@baliance.com. -package styles_test +package spreadsheet_test import ( "bytes" @@ -14,7 +14,7 @@ import ( "os" "testing" - "baliance.com/gooxml/spreadsheet/styles" + "baliance.com/gooxml/spreadsheet" "baliance.com/gooxml/testhelper" "baliance.com/gooxml/zippkg" ) @@ -22,25 +22,25 @@ import ( func TestStyleSheetUnmarshal(t *testing.T) { f, err := os.Open("testdata/styles.xml") if err != nil { - t.Fatalf("error reading content types file") + t.Fatalf("error reading styles.xml") } dec := xml.NewDecoder(f) - r := styles.NewStyleSheet() + r := spreadsheet.NewStyleSheet() 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{} fmt.Fprintf(got, zippkg.XMLHeader) enc := xml.NewEncoder(zippkg.SelfClosingWriter{W: got}) 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()) } func TestStyleSheetFonts(t *testing.T) { - ss := styles.NewStyleSheet() + ss := spreadsheet.NewStyleSheet() fc := len(ss.Fonts()) ft := ss.AddFont() diff --git a/spreadsheet/styles/testdata/styles.xml b/spreadsheet/testdata/styles.xml similarity index 100% rename from spreadsheet/styles/testdata/styles.xml rename to spreadsheet/testdata/styles.xml diff --git a/spreadsheet/workbook.go b/spreadsheet/workbook.go index 1d418071..e8d4848c 100644 --- a/spreadsheet/workbook.go +++ b/spreadsheet/workbook.go @@ -19,7 +19,6 @@ import ( "baliance.com/gooxml/common" "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml" - "baliance.com/gooxml/spreadsheet/styles" "baliance.com/gooxml/zippkg" ) @@ -28,7 +27,7 @@ type Workbook struct { common.DocBase x *spreadsheetml.Workbook - StyleSheet styles.StyleSheet + StyleSheet StyleSheet Theme common.Theme SharedStrings SharedStrings xws []*spreadsheetml.Worksheet @@ -43,7 +42,7 @@ func New() *Workbook { wb.AppProperties = common.NewAppProperties() wb.CoreProperties = common.NewCoreProperties() - wb.StyleSheet = styles.NewStyleSheet() + wb.StyleSheet = NewStyleSheet() wb.Rels = common.NewRelationships() wb.wbRels = common.NewRelationships() @@ -148,7 +147,7 @@ func Read(r io.ReaderAt, size int64) (*Workbook, error) { basePaths[wksRel] = basePath wb.xwsRels = append(wb.xwsRels, wksRel) case common.StylesType: - wb.StyleSheet = styles.NewStyleSheet() + wb.StyleSheet = NewStyleSheet() decMap[basePaths[wb.wbRels]+r.Target()] = wb.StyleSheet.X() case common.ThemeType: wb.Theme = common.NewTheme() diff --git a/spreadsheet/workbook_test.go b/spreadsheet/workbook_test.go index acbbc9cd..47ef858a 100644 --- a/spreadsheet/workbook_test.go +++ b/spreadsheet/workbook_test.go @@ -67,7 +67,7 @@ func TestWorkbookUnmarshal(t *testing.T) { func TestSimpleSheet(t *testing.T) { wb := spreadsheet.New() - sheet := wb.AddSheet("foo") + sheet := wb.AddSheet() row := sheet.AddRow() cell := row.AddCell() cell.SetString("testing 123") @@ -114,14 +114,14 @@ func TestSheetCount(t *testing.T) { if wb.SheetCount() != 0 { t.Errorf("expected 0 sheets, got %d", wb.SheetCount()) } - wb.AddSheet("Sheet 1") + wb.AddSheet() if err := wb.Validate(); err != nil { t.Errorf("created an invalid spreadsheet: %s", err) } if wb.SheetCount() != 1 { t.Errorf("expected 1 sheets, got %d", wb.SheetCount()) } - wb.AddSheet("Sheet 2") + wb.AddSheet() if err := wb.Validate(); err != nil { t.Errorf("created an invalid spreadsheet: %s", err) } @@ -132,7 +132,7 @@ func TestSheetCount(t *testing.T) { func TestPreserveSpace(t *testing.T) { ss := spreadsheet.New() - sheet := ss.AddSheet("Sheet 1") + sheet := ss.AddSheet() row := sheet.AddRow() values := []string{" foo ", " bar \t", "foo\r\nbar", "\t\r\nfoo\t123\r\n"} for i, s := range values {