diff --git a/_examples/spreadsheet/shared-formula/main.go b/_examples/spreadsheet/shared-formula/main.go new file mode 100644 index 00000000..01062977 --- /dev/null +++ b/_examples/spreadsheet/shared-formula/main.go @@ -0,0 +1,36 @@ +// Copyright 2017 Baliance. All rights reserved. +package main + +import ( + "log" + + "baliance.com/gooxml/spreadsheet" +) + +func main() { + ss := spreadsheet.New() + sheet := ss.AddSheet() + + sheet.Cell("A1").SetNumber(1) + sheet.Cell("B1").SetNumber(2) + sheet.Cell("C1").SetNumber(3) + sheet.Cell("D1").SetNumber(4) + sheet.Cell("A2").SetNumber(5) + sheet.Cell("B2").SetNumber(6) + sheet.Cell("C2").SetNumber(7) + sheet.Cell("D2").SetNumber(8) + sheet.Cell("A3").SetNumber(9) + sheet.Cell("B3").SetNumber(10) + sheet.Cell("C3").SetNumber(11) + sheet.Cell("D3").SetNumber(12) + + sheet.Cell("A5").SetFormulaShared("=A1+1", 2, 3) + sheet.Cell("A9").SetFormulaShared("=$A1+1", 2, 3) + sheet.Cell("A13").SetFormulaShared("=$A$1+1", 2, 3) + + ss.RecalculateFormulas() + if err := ss.Validate(); err != nil { + log.Fatalf("error validating: %s", err) + } + ss.SaveToFile("shared-formula.xlsx") +} diff --git a/spreadsheet/cell.go b/spreadsheet/cell.go index c00d2a55..98e55644 100644 --- a/spreadsheet/cell.go +++ b/spreadsheet/cell.go @@ -9,6 +9,7 @@ package spreadsheet import ( "errors" + "fmt" "math" "math/big" "strconv" @@ -93,6 +94,50 @@ func (c Cell) SetFormulaArray(s string) { c.x.F.Content = s } +// SetFormulaShared sets the cell type to formula shared, and the raw formula to +// the given string. The range is the range of cells that the formula applies +// to, and is used to conserve disk space. +func (c Cell) SetFormulaShared(formula string, rows, cols uint32) error { + c.clearValue() + c.x.TAttr = sml.ST_CellTypeStr + c.x.F = sml.NewCT_CellFormula() + c.x.F.TAttr = sml.ST_CellFormulaTypeShared + c.x.F.Content = formula + col, rowIdx, err := ParseCellReference(c.Reference()) + if err != nil { + return err + } + colIdx := ColumnToIndex(col) + + sid := uint32(0) + for _, r := range c.s.SheetData.Row { + for _, c := range r.C { + if c.F != nil && c.F.SiAttr != nil && *c.F.SiAttr >= sid { + sid = *c.F.SiAttr + } + } + } + + ref := fmt.Sprintf("%s%d:%s%d", col, rowIdx, IndexToColumn(colIdx+cols), rowIdx+rows) + fmt.Println("REF IS", ref) + c.x.F.RefAttr = gooxml.String(ref) + c.x.F.SiAttr = gooxml.Uint32(sid) + sheet := Sheet{c.w, nil, c.s} + for row := rowIdx; row <= rowIdx+rows; row++ { + for col := colIdx; col <= colIdx+cols; col++ { + if row == rowIdx && col == colIdx { + continue + } + ref := fmt.Sprintf("%s%d", IndexToColumn(col), row) + sheet.Cell(ref).Clear() + sheet.Cell(ref).X().F = sml.NewCT_CellFormula() + sheet.Cell(ref).X().F.TAttr = sml.ST_CellFormulaTypeShared + sheet.Cell(ref).X().F.SiAttr = gooxml.Uint32(sid) + } + } + return nil +} + // SetString sets the cell type to string, and the value to the given string, // returning an ID from the shared strings table. To reuse a string, call // SetStringByID with the ID returned. diff --git a/spreadsheet/sheet.go b/spreadsheet/sheet.go index 3fb0a2d4..272f63a6 100644 --- a/spreadsheet/sheet.go +++ b/spreadsheet/sheet.go @@ -628,6 +628,9 @@ func (s *Sheet) RecalculateFormulas() { // array we need to expand the array out into cells if c.X().F.TAttr == sml.ST_CellFormulaTypeArray && res.Type == formula.ResultTypeArray { s.setArray(c.Reference(), res) + } else if c.X().F.TAttr == sml.ST_CellFormulaTypeShared { + // shared formula + // s.setShared(c.X().F.RefAttr) } } }