spreadsheet: initial shared formula support

This commit is contained in:
Todd 2017-10-01 11:19:33 -05:00
parent d0820f1553
commit d7515808d8
3 changed files with 84 additions and 0 deletions

View File

@ -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")
}

View File

@ -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.

View File

@ -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)
}
}
}