Mercurial > gemma
changeset 5344:7df6062a1371 extented-report
XLSX: Implemented correct handling of merged cells.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Fri, 18 Jun 2021 21:27:41 +0200 |
parents | bb6761abd81d |
children | 95dafb72a288 |
files | pkg/xlsx/templater.go |
diffstat | 1 files changed, 127 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/pkg/xlsx/templater.go Fri Jun 18 13:43:21 2021 +0200 +++ b/pkg/xlsx/templater.go Fri Jun 18 21:27:41 2021 +0200 @@ -57,6 +57,38 @@ frames []frame } +type area struct { + x1 int + y1 int + x2 int + y2 int + mc excelize.MergeCell +} + +func mergeCellToArea(mc excelize.MergeCell) (area, error) { + sa := mc.GetStartAxis() + x1, y1, err := excelize.CellNameToCoordinates(sa) + if err != nil { + return area{}, err + } + ea := mc.GetEndAxis() + x2, y2, err := excelize.CellNameToCoordinates(ea) + if err != nil { + return area{}, err + } + return area{ + x1: x1, + y1: y1, + x2: x2, + y2: y2, + mc: mc, + }, nil +} + +func (a *area) contains(x, y int) bool { + return x >= a.x1 && x <= a.x2 && y >= a.y1 && y <= a.y2 +} + func ActionFromFile(filename string) (*Action, error) { f, err := os.Open(filename) if err != nil { @@ -161,6 +193,13 @@ return e.actions(action) } +func order(a, b int) (int, int) { + if a < b { + return a, b + } + return b, a +} + func (e *executor) copy(action *Action) error { if n := len(action.Location); !(n == 1 || n == 2) { return fmt.Errorf("length location = %d (expect 1 or 2)", @@ -179,22 +218,12 @@ split := func(s string) (int, int) { var x, y int if err == nil { - var cell string - if cell, y, err = excelize.SplitCellName(s); err == nil { - x, err = excelize.ColumnNameToNumber(cell) - } + x, y, err = excelize.CellNameToCoordinates(s) } return x, y } - order := func(a, b int) (int, int) { - if a > b { - return b, a - } - return a, b - } var location []string - if len(action.Location) == 1 { location = []string{action.Location[0], action.Location[0]} } else { @@ -202,7 +231,6 @@ } var destination string - if action.Destination == "" { destination = location[0] } else { @@ -221,26 +249,101 @@ return err } sx1, sx2 = order(sx1, sx2) - sy1, sy1 = order(sy1, sy2) + sy1, sy2 = order(sy1, sy2) + + var areas []area - //log.Printf("%s/%s -> %s\n", sFrom, sTo, dTo) + //log.Println("merged cells") + if mcs, err := e.template.GetMergeCells(e.sourceSheet); err == nil { + areas = make([]area, 0, len(mcs)) + for _, mc := range mcs { + if a, err := mergeCellToArea(mc); err == nil { + areas = append(areas, a) + } + } + } for y, i := sy1, 0; y <= sy2; y, i = y+1, i+1 { + nextX: for x, j := sx1, 0; x <= sx2; x, j = x+1, j+1 { - src, err1 := excelize.CoordinatesToCellName(x, y) - dst, err2 := excelize.CoordinatesToCellName(dx1+j, dy1+i) - if err1 != nil || err2 != nil { + + // check if cell is part of a merged cell + for k := range areas { + area := &areas[k] + + if area.contains(x, y) { + ofsX := x - area.x1 + ofsY := y - area.y1 + + sx := dx1 + j - ofsX + sy := dy1 + i - ofsY + ex := sx + (area.x2 - area.x1) + ey := sy + (area.y2 - area.y1) + + // Copy over attributes + for l := 0; l <= area.x2-area.x1; l++ { + for m := 0; m <= area.y2-area.y1; m++ { + src, err1 := excelize.CoordinatesToCellName(area.x1+l, area.y1+m) + dst, err2 := excelize.CoordinatesToCellName(sx+l, sy+m) + if err1 != nil || err2 != nil { + continue + } + if s, err := e.template.GetCellStyle(e.sourceSheet, src); err == nil { + e.template.SetCellStyle(e.destinationSheet, dst, dst, s) + } + if s, err := e.template.GetCellFormula(e.sourceSheet, src); err == nil { + e.template.SetCellFormula(e.destinationSheet, dst, s) + } + } + } + + dst, err := excelize.CoordinatesToCellName(sx, sy) + if err != nil { + continue nextX + } + + // Copy over expanded text + if s, err := e.expand(area.mc.GetCellValue(), vars); err == nil { + e.template.SetCellStr(e.destinationSheet, dst, s) + } + + // Finally merge the cells + if end, err := excelize.CoordinatesToCellName(ex, ey); err == nil { + e.template.MergeCell(e.destinationSheet, dst, end) + } + + continue nextX + } + } + + // Regular cell + + src, err := excelize.CoordinatesToCellName(x, y) + if err != nil { + continue + } + dst, err := excelize.CoordinatesToCellName(dx1+j, dy1+i) + if err != nil { continue } - sc, sr, err1 := excelize.SplitCellName(src) - dc, dr, err2 := excelize.SplitCellName(dst) - if err1 != nil || err2 != nil { + cn, err := excelize.ColumnNumberToName(x) + if err != nil { + continue + } + + cw, err := e.template.GetColWidth(e.sourceSheet, cn) + if err != nil { continue } - cw, err1 := e.template.GetColWidth(e.sourceSheet, sc) - rh, err1 := e.template.GetRowHeight(e.sourceSheet, sr) - if err1 != nil || err2 != nil { + + rh, err := e.template.GetRowHeight(e.sourceSheet, y) + if err != nil { + continue + } + + dc, err := excelize.ColumnNumberToName(dx1 + j) + if err != nil { continue } @@ -248,7 +351,7 @@ continue } - if e.template.SetRowHeight(e.destinationSheet, dr, rh) != nil { + if e.template.SetRowHeight(e.destinationSheet, dy1+i, rh) != nil { continue }