mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-27 13:48:54 +08:00
Get all cells in a row with empty ones (#377)
* Get all cells in a row with empty ones * sheet.MaxColumnIdx() changed * goimports for all
This commit is contained in:
parent
5f9c94bf84
commit
72ad869a28
36
_examples/spreadsheet/cells-with-empty/main.go
Normal file
36
_examples/spreadsheet/cells-with-empty/main.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2017 FoxyUtils ehf. All rights reserved.
|
||||||
|
package main
|
||||||
|
|
||||||
|
// This example demonstrates outputing all cells in a row of an excel spreadsheet, including empty cells.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/unidoc/unioffice/spreadsheet"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ss, err := spreadsheet.Open("test.xlsx")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error opening document: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := ss.Sheets()[0]
|
||||||
|
|
||||||
|
maxColumnIdx := s.MaxColumnIdx()
|
||||||
|
for _, row := range s.Rows() {
|
||||||
|
for _, cell := range row.CellsWithEmpty(maxColumnIdx) {
|
||||||
|
fmt.Println(cell.Reference(), ":", cell.GetFormattedValue())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Print("\n\n\n")
|
||||||
|
|
||||||
|
s.Cell("F4").SetString("Hello world")
|
||||||
|
maxColumnIdx = s.MaxColumnIdx()
|
||||||
|
for _, row := range s.Rows() {
|
||||||
|
for _, cell := range row.CellsWithEmpty(maxColumnIdx) {
|
||||||
|
fmt.Println(cell.Reference(), ":", cell.GetFormattedValue())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
_examples/spreadsheet/cells-with-empty/test.xlsx
Normal file
BIN
_examples/spreadsheet/cells-with-empty/test.xlsx
Normal file
Binary file not shown.
@ -10,9 +10,9 @@ import (
|
|||||||
|
|
||||||
"github.com/unidoc/unioffice/common"
|
"github.com/unidoc/unioffice/common"
|
||||||
"github.com/unidoc/unioffice/document"
|
"github.com/unidoc/unioffice/document"
|
||||||
|
"github.com/unidoc/unioffice/schema/soo/ofc/docPropsVTypes"
|
||||||
"github.com/unidoc/unioffice/testhelper"
|
"github.com/unidoc/unioffice/testhelper"
|
||||||
"github.com/unidoc/unioffice/zippkg"
|
"github.com/unidoc/unioffice/zippkg"
|
||||||
"github.com/unidoc/unioffice/schema/soo/ofc/docPropsVTypes"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMarshalCustomProperties(t *testing.T) {
|
func TestMarshalCustomProperties(t *testing.T) {
|
||||||
|
@ -395,7 +395,6 @@ func (p *Presentation) Save(w io.Writer) error {
|
|||||||
r.Properties().SetSolidFill(color.Red)
|
r.Properties().SetSolidFill(color.Red)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dt := unioffice.DocTypePresentation
|
dt := unioffice.DocTypePresentation
|
||||||
|
|
||||||
z := zip.NewWriter(w)
|
z := zip.NewWriter(w)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
// commercial license can be purchased via https://unidoc.io website.
|
// commercial license can be purchased via https://unidoc.io website.
|
||||||
|
|
||||||
package custom_properties
|
package custom_properties
|
||||||
|
|
||||||
import "github.com/unidoc/unioffice"
|
import "github.com/unidoc/unioffice"
|
||||||
|
|
||||||
// init registers constructor functions for dynamically creating elements based off the XML namespace and name
|
// init registers constructor functions for dynamically creating elements based off the XML namespace and name
|
||||||
|
@ -27,7 +27,7 @@ const iso8601Format = "2006-01-02T15:04:05Z07:00"
|
|||||||
// Cell is a single cell within a sheet.
|
// Cell is a single cell within a sheet.
|
||||||
type Cell struct {
|
type Cell struct {
|
||||||
w *Workbook
|
w *Workbook
|
||||||
s *sml.Worksheet
|
sheet *Sheet
|
||||||
r *sml.CT_Row
|
r *sml.CT_Row
|
||||||
x *sml.CT_Cell
|
x *sml.CT_Cell
|
||||||
}
|
}
|
||||||
@ -110,8 +110,8 @@ func (c Cell) SetFormulaShared(formula string, rows, cols uint32) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sid := uint32(0)
|
sid := uint32(0)
|
||||||
for _, r := range c.s.SheetData.Row {
|
for _, r := range c.sheet.Rows() {
|
||||||
for _, c := range r.C {
|
for _, c := range r.x.C {
|
||||||
if c.F != nil && c.F.SiAttr != nil && *c.F.SiAttr >= sid {
|
if c.F != nil && c.F.SiAttr != nil && *c.F.SiAttr >= sid {
|
||||||
sid = *c.F.SiAttr
|
sid = *c.F.SiAttr
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ func (c Cell) SetFormulaShared(formula string, rows, cols uint32) error {
|
|||||||
ref := fmt.Sprintf("%s%d:%s%d", cref.Column, cref.RowIdx, reference.IndexToColumn(cref.ColumnIdx+cols), cref.RowIdx+rows)
|
ref := fmt.Sprintf("%s%d:%s%d", cref.Column, cref.RowIdx, reference.IndexToColumn(cref.ColumnIdx+cols), cref.RowIdx+rows)
|
||||||
c.x.F.RefAttr = unioffice.String(ref)
|
c.x.F.RefAttr = unioffice.String(ref)
|
||||||
c.x.F.SiAttr = unioffice.Uint32(sid)
|
c.x.F.SiAttr = unioffice.Uint32(sid)
|
||||||
sheet := Sheet{c.w, nil, c.s}
|
sheet := Sheet{c.w, c.sheet.cts, c.sheet.x}
|
||||||
for row := cref.RowIdx; row <= cref.RowIdx+rows; row++ {
|
for row := cref.RowIdx; row <= cref.RowIdx+rows; row++ {
|
||||||
for col := cref.ColumnIdx; col <= cref.ColumnIdx+cols; col++ {
|
for col := cref.ColumnIdx; col <= cref.ColumnIdx+cols; col++ {
|
||||||
if row == cref.RowIdx && col == cref.ColumnIdx {
|
if row == cref.RowIdx && col == cref.ColumnIdx {
|
||||||
@ -200,11 +200,16 @@ func (c Cell) getLabelPrefix() string {
|
|||||||
sid := *c.x.SAttr
|
sid := *c.x.SAttr
|
||||||
cs := c.w.StyleSheet.GetCellStyle(sid)
|
cs := c.w.StyleSheet.GetCellStyle(sid)
|
||||||
switch cs.xf.Alignment.HorizontalAttr {
|
switch cs.xf.Alignment.HorizontalAttr {
|
||||||
case sml.ST_HorizontalAlignmentLeft: return "'"
|
case sml.ST_HorizontalAlignmentLeft:
|
||||||
case sml.ST_HorizontalAlignmentRight: return "\""
|
return "'"
|
||||||
case sml.ST_HorizontalAlignmentCenter: return "^"
|
case sml.ST_HorizontalAlignmentRight:
|
||||||
case sml.ST_HorizontalAlignmentFill: return "\\"
|
return "\""
|
||||||
default: return ""
|
case sml.ST_HorizontalAlignmentCenter:
|
||||||
|
return "^"
|
||||||
|
case sml.ST_HorizontalAlignmentFill:
|
||||||
|
return "\\"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,22 +509,23 @@ func (c Cell) GetRawValue() (string, error) {
|
|||||||
|
|
||||||
// SetHyperlink sets a hyperlink on a cell.
|
// SetHyperlink sets a hyperlink on a cell.
|
||||||
func (c Cell) SetHyperlink(hl common.Hyperlink) {
|
func (c Cell) SetHyperlink(hl common.Hyperlink) {
|
||||||
if c.s.Hyperlinks == nil {
|
ws := c.sheet.x
|
||||||
c.s.Hyperlinks = sml.NewCT_Hyperlinks()
|
if ws.Hyperlinks == nil {
|
||||||
|
ws.Hyperlinks = sml.NewCT_Hyperlinks()
|
||||||
}
|
}
|
||||||
rel := common.Relationship(hl)
|
rel := common.Relationship(hl)
|
||||||
|
|
||||||
hle := sml.NewCT_Hyperlink()
|
hle := sml.NewCT_Hyperlink()
|
||||||
hle.RefAttr = c.Reference()
|
hle.RefAttr = c.Reference()
|
||||||
hle.IdAttr = unioffice.String(rel.ID())
|
hle.IdAttr = unioffice.String(rel.ID())
|
||||||
c.s.Hyperlinks.Hyperlink = append(c.s.Hyperlinks.Hyperlink, hle)
|
ws.Hyperlinks.Hyperlink = append(ws.Hyperlinks.Hyperlink, hle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddHyperlink creates and sets a hyperlink on a cell.
|
// AddHyperlink creates and sets a hyperlink on a cell.
|
||||||
func (c Cell) AddHyperlink(url string) {
|
func (c Cell) AddHyperlink(url string) {
|
||||||
// store the relationships so we don't need to do a lookup here?
|
// store the relationships so we don't need to do a lookup here?
|
||||||
for i, ws := range c.w.xws {
|
for i, ws := range c.w.xws {
|
||||||
if ws == c.s {
|
if ws == c.sheet.x {
|
||||||
// add a hyperlink relationship in the worksheet relationships file
|
// add a hyperlink relationship in the worksheet relationships file
|
||||||
c.SetHyperlink(c.w.xwsRels[i].AddHyperlink(url))
|
c.SetHyperlink(c.w.xwsRels[i].AddHyperlink(url))
|
||||||
return
|
return
|
||||||
|
@ -9,10 +9,10 @@ package spreadsheet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/unidoc/unioffice/spreadsheet/formula"
|
"github.com/unidoc/unioffice/spreadsheet/formula"
|
||||||
"github.com/unidoc/unioffice/spreadsheet/reference"
|
"github.com/unidoc/unioffice/spreadsheet/reference"
|
||||||
@ -220,7 +220,7 @@ func (e *evalContext) LastRow(col string) int {
|
|||||||
max := 1
|
max := 1
|
||||||
for _, r := range sheet.x.SheetData.Row {
|
for _, r := range sheet.x.SheetData.Row {
|
||||||
if r.RAttr != nil {
|
if r.RAttr != nil {
|
||||||
row := Row{sheet.w, sheet.x, r}
|
row := Row{sheet.w, sheet, r}
|
||||||
l := len(row.Cells())
|
l := len(row.Cells())
|
||||||
if l > colIdx {
|
if l > colIdx {
|
||||||
max = int(row.RowNumber())
|
max = int(row.RowNumber())
|
||||||
|
@ -904,7 +904,7 @@ func feb29Between(date1, date2 time.Time) bool {
|
|||||||
date2S := date2.Unix()
|
date2S := date2.Unix()
|
||||||
year1 := date1.Year()
|
year1 := date1.Year()
|
||||||
mar1year1 := makeDateS(year1, time.March, 1)
|
mar1year1 := makeDateS(year1, time.March, 1)
|
||||||
if (isLeapYear(year1) && date1S < mar1year1 && date2S >= mar1year1) {
|
if isLeapYear(year1) && date1S < mar1year1 && date2S >= mar1year1 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
var year2 = date2.Year()
|
var year2 = date2.Year()
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
package formula
|
package formula
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -11,9 +11,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/unidoc/unioffice/internal/mergesort"
|
||||||
"github.com/unidoc/unioffice/internal/wildcard"
|
"github.com/unidoc/unioffice/internal/wildcard"
|
||||||
"github.com/unidoc/unioffice/spreadsheet/reference"
|
"github.com/unidoc/unioffice/spreadsheet/reference"
|
||||||
"github.com/unidoc/unioffice/internal/mergesort"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -9,6 +9,7 @@ package formula
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
"github.com/unidoc/unioffice/spreadsheet/update"
|
"github.com/unidoc/unioffice/spreadsheet/update"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -366,7 +366,6 @@ func TestCountIfs(t *testing.T) {
|
|||||||
sheet.Cell("B9").SetNumber(2)
|
sheet.Cell("B9").SetNumber(2)
|
||||||
sheet.Cell("B10").SetNumber(1)
|
sheet.Cell("B10").SetNumber(1)
|
||||||
|
|
||||||
|
|
||||||
ctx := sheet.FormulaContext()
|
ctx := sheet.FormulaContext()
|
||||||
|
|
||||||
runTests(t, ctx, td)
|
runTests(t, ctx, td)
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
|
|
||||||
type MergedCell struct {
|
type MergedCell struct {
|
||||||
wb *Workbook
|
wb *Workbook
|
||||||
ws *sml.Worksheet
|
sheet *Sheet
|
||||||
x *sml.CT_MergeCell
|
x *sml.CT_MergeCell
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ func (s MergedCell) Cell() Cell {
|
|||||||
ref := s.Reference()
|
ref := s.Reference()
|
||||||
if idx := strings.Index(s.Reference(), ":"); idx != -1 {
|
if idx := strings.Index(s.Reference(), ":"); idx != -1 {
|
||||||
ref = ref[0:idx]
|
ref = ref[0:idx]
|
||||||
return Sheet{w: s.wb, x: s.ws}.Cell(ref)
|
return s.sheet.Cell(ref)
|
||||||
}
|
}
|
||||||
// couldn't find it, log an error?
|
// couldn't find it, log an error?
|
||||||
return Cell{}
|
return Cell{}
|
||||||
|
@ -12,8 +12,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path/filepath"
|
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/unidoc/unioffice"
|
"github.com/unidoc/unioffice"
|
||||||
"github.com/unidoc/unioffice/zippkg"
|
"github.com/unidoc/unioffice/zippkg"
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
// Row is a row within a spreadsheet.
|
// Row is a row within a spreadsheet.
|
||||||
type Row struct {
|
type Row struct {
|
||||||
w *Workbook
|
w *Workbook
|
||||||
s *sml.Worksheet
|
sheet *Sheet
|
||||||
x *sml.CT_Row
|
x *sml.CT_Row
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ func (r Row) AddCell() Cell {
|
|||||||
nextCellID = unioffice.Stringf("%s%d", reference.IndexToColumn(nextIdx), r.RowNumber())
|
nextCellID = unioffice.Stringf("%s%d", reference.IndexToColumn(nextIdx), r.RowNumber())
|
||||||
}
|
}
|
||||||
c.RAttr = nextCellID
|
c.RAttr = nextCellID
|
||||||
return Cell{r.w, r.s, r.x, c}
|
return Cell{r.w, r.sheet, r.x, c}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cells returns a slice of cells. The cells can be manipulated, but appending
|
// Cells returns a slice of cells. The cells can be manipulated, but appending
|
||||||
@ -116,7 +116,18 @@ func (r Row) Cells() []Cell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastIndex = currentIndex
|
lastIndex = currentIndex
|
||||||
ret = append(ret, Cell{r.w, r.s, r.x, c})
|
ret = append(ret, Cell{r.w, r.sheet, r.x, c})
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// CellsWithEmpty returns a slice of cells including empty ones from the first column to the last one used in the sheet.
|
||||||
|
// The cells can be manipulated, but appending to the slice will have no effect.
|
||||||
|
func (r Row) CellsWithEmpty(lastColIdx uint32) []Cell {
|
||||||
|
ret := []Cell{}
|
||||||
|
for columnIdx := uint32(0); columnIdx <= lastColIdx; columnIdx++ {
|
||||||
|
c := r.Cell(reference.IndexToColumn(columnIdx))
|
||||||
|
ret = append(ret, c)
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@ -147,7 +158,7 @@ func (r Row) AddNamedCell(col string) Cell {
|
|||||||
r.x.C = append(r.x.C[:indexToInsert], append([]*sml.CT_Cell{c}, r.x.C[indexToInsert:]...)...)
|
r.x.C = append(r.x.C[:indexToInsert], append([]*sml.CT_Cell{c}, r.x.C[indexToInsert:]...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Cell{r.w, r.s, r.x, c}
|
return Cell{r.w, r.sheet, r.x, c}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cell retrieves or adds a new cell to a row. Col is the column (e.g. 'A', 'B')
|
// Cell retrieves or adds a new cell to a row. Col is the column (e.g. 'A', 'B')
|
||||||
@ -155,7 +166,7 @@ func (r Row) Cell(col string) Cell {
|
|||||||
name := fmt.Sprintf("%s%d", col, r.RowNumber())
|
name := fmt.Sprintf("%s%d", col, r.RowNumber())
|
||||||
for _, c := range r.x.C {
|
for _, c := range r.x.C {
|
||||||
if c.RAttr != nil && *c.RAttr == name {
|
if c.RAttr != nil && *c.RAttr == name {
|
||||||
return Cell{r.w, r.s, r.x, c}
|
return Cell{r.w, r.sheet, r.x, c}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r.AddNamedCell(col)
|
return r.AddNamedCell(col)
|
||||||
|
@ -31,6 +31,22 @@ type Sheet struct {
|
|||||||
x *sml.Worksheet
|
x *sml.Worksheet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaxColumnIdx returns the max used column of the sheet.
|
||||||
|
func (s Sheet) MaxColumnIdx() uint32 {
|
||||||
|
maxColumnIdx := uint32(0)
|
||||||
|
for _, r := range s.Rows() {
|
||||||
|
cells := r.x.C
|
||||||
|
if len(cells) > 0 {
|
||||||
|
lastCell := cells[len(cells)-1]
|
||||||
|
ref, _ := reference.ParseCellReference(*lastCell.RAttr)
|
||||||
|
if maxColumnIdx < ref.ColumnIdx {
|
||||||
|
maxColumnIdx = ref.ColumnIdx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxColumnIdx
|
||||||
|
}
|
||||||
|
|
||||||
func (s Sheet) IsValid() bool {
|
func (s Sheet) IsValid() bool {
|
||||||
return s.x != nil
|
return s.x != nil
|
||||||
}
|
}
|
||||||
@ -42,11 +58,11 @@ func (s Sheet) X() *sml.Worksheet {
|
|||||||
|
|
||||||
// Row will return a row with a given row number, creating a new row if
|
// Row will return a row with a given row number, creating a new row if
|
||||||
// necessary.
|
// necessary.
|
||||||
func (s Sheet) Row(rowNum uint32) Row {
|
func (s *Sheet) Row(rowNum uint32) Row {
|
||||||
// see if the row exists
|
// see if the row exists
|
||||||
for _, r := range s.x.SheetData.Row {
|
for _, r := range s.x.SheetData.Row {
|
||||||
if r.RAttr != nil && *r.RAttr == rowNum {
|
if r.RAttr != nil && *r.RAttr == rowNum {
|
||||||
return Row{s.w, s.x, r}
|
return Row{s.w, s, r}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// create a new row
|
// create a new row
|
||||||
@ -54,7 +70,7 @@ func (s Sheet) Row(rowNum uint32) Row {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cell creates or returns a cell given a cell reference of the form 'A10'
|
// Cell creates or returns a cell given a cell reference of the form 'A10'
|
||||||
func (s Sheet) Cell(cellRef string) Cell {
|
func (s *Sheet) Cell(cellRef string) Cell {
|
||||||
cref, err := reference.ParseCellReference(cellRef)
|
cref, err := reference.ParseCellReference(cellRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
unioffice.Log("error parsing cell reference: %s", err)
|
unioffice.Log("error parsing cell reference: %s", err)
|
||||||
@ -66,7 +82,7 @@ func (s Sheet) Cell(cellRef string) Cell {
|
|||||||
// AddNumberedRow adds a row with a given row number. If you reuse a row number
|
// AddNumberedRow adds a row with a given row number. If you reuse a row number
|
||||||
// the resulting file will fail validation and fail to open in Office programs. Use
|
// the resulting file will fail validation and fail to open in Office programs. Use
|
||||||
// Row instead which creates a new row or returns an existing row.
|
// Row instead which creates a new row or returns an existing row.
|
||||||
func (s Sheet) AddNumberedRow(rowNum uint32) Row {
|
func (s *Sheet) AddNumberedRow(rowNum uint32) Row {
|
||||||
r := sml.NewCT_Row()
|
r := sml.NewCT_Row()
|
||||||
r.RAttr = unioffice.Uint32(rowNum)
|
r.RAttr = unioffice.Uint32(rowNum)
|
||||||
s.x.SheetData.Row = append(s.x.SheetData.Row, r)
|
s.x.SheetData.Row = append(s.x.SheetData.Row, r)
|
||||||
@ -84,22 +100,22 @@ func (s Sheet) AddNumberedRow(rowNum uint32) Row {
|
|||||||
return *l < *r
|
return *l < *r
|
||||||
})
|
})
|
||||||
|
|
||||||
return Row{s.w, s.x, r}
|
return Row{s.w, s, r}
|
||||||
}
|
}
|
||||||
|
|
||||||
// addNumberedRowFast is a fast path that can be used when adding consecutive
|
// addNumberedRowFast is a fast path that can be used when adding consecutive
|
||||||
// rows and not skipping any.
|
// rows and not skipping any.
|
||||||
func (s Sheet) addNumberedRowFast(rowNum uint32) Row {
|
func (s *Sheet) addNumberedRowFast(rowNum uint32) Row {
|
||||||
r := sml.NewCT_Row()
|
r := sml.NewCT_Row()
|
||||||
r.RAttr = unioffice.Uint32(rowNum)
|
r.RAttr = unioffice.Uint32(rowNum)
|
||||||
s.x.SheetData.Row = append(s.x.SheetData.Row, r)
|
s.x.SheetData.Row = append(s.x.SheetData.Row, r)
|
||||||
return Row{s.w, s.x, r}
|
return Row{s.w, s, r}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRow adds a new row to a sheet. You can mix this with numbered rows,
|
// AddRow adds a new row to a sheet. You can mix this with numbered rows,
|
||||||
// however it will get confusing. You should prefer to use either automatically
|
// however it will get confusing. You should prefer to use either automatically
|
||||||
// numbered rows with AddRow or manually numbered rows with Row/AddNumberedRow
|
// numbered rows with AddRow or manually numbered rows with Row/AddNumberedRow
|
||||||
func (s Sheet) AddRow() Row {
|
func (s *Sheet) AddRow() Row {
|
||||||
maxRowID := uint32(0)
|
maxRowID := uint32(0)
|
||||||
|
|
||||||
numRows := uint32(len(s.x.SheetData.Row))
|
numRows := uint32(len(s.x.SheetData.Row))
|
||||||
@ -120,7 +136,7 @@ func (s Sheet) AddRow() Row {
|
|||||||
|
|
||||||
// InsertRow inserts a new row into a spreadsheet at a particular row number. This
|
// InsertRow inserts a new row into a spreadsheet at a particular row number. This
|
||||||
// row will now be the row number specified, and any rows after it will be renumbed.
|
// row will now be the row number specified, and any rows after it will be renumbed.
|
||||||
func (s Sheet) InsertRow(rowNum int) Row {
|
func (s *Sheet) InsertRow(rowNum int) Row {
|
||||||
rIdx := uint32(rowNum)
|
rIdx := uint32(rowNum)
|
||||||
|
|
||||||
// Renumber every row after the row we're inserting
|
// Renumber every row after the row we're inserting
|
||||||
@ -166,7 +182,7 @@ func (s Sheet) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetName sets the sheet name.
|
// SetName sets the sheet name.
|
||||||
func (s Sheet) SetName(name string) {
|
func (s *Sheet) SetName(name string) {
|
||||||
s.cts.NameAttr = name
|
s.cts.NameAttr = name
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +198,7 @@ func (s Sheet) Validate() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := s.cts.Validate(); err != nil {
|
if err := s.x.Validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return s.x.Validate()
|
return s.x.Validate()
|
||||||
@ -249,21 +265,21 @@ func (s Sheet) validateMergedCells() error {
|
|||||||
// ValidateWithPath validates the sheet passing path informaton for a better
|
// ValidateWithPath validates the sheet passing path informaton for a better
|
||||||
// error message
|
// error message
|
||||||
func (s Sheet) ValidateWithPath(path string) error {
|
func (s Sheet) ValidateWithPath(path string) error {
|
||||||
return s.cts.ValidateWithPath(path)
|
return s.x.ValidateWithPath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rows returns all of the rows in a sheet.
|
// Rows returns all of the rows in a sheet.
|
||||||
func (s Sheet) Rows() []Row {
|
func (s *Sheet) Rows() []Row {
|
||||||
ret := []Row{}
|
ret := []Row{}
|
||||||
for _, r := range s.x.SheetData.Row {
|
for _, r := range s.x.SheetData.Row {
|
||||||
ret = append(ret, Row{s.w, s.x, r})
|
ret = append(ret, Row{s.w, s, r})
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDrawing sets the worksheet drawing. A worksheet can have a reference to a
|
// SetDrawing sets the worksheet drawing. A worksheet can have a reference to a
|
||||||
// single drawing, but the drawing can have many charts.
|
// single drawing, but the drawing can have many charts.
|
||||||
func (s Sheet) SetDrawing(d Drawing) {
|
func (s *Sheet) SetDrawing(d Drawing) {
|
||||||
var rel common.Relationships
|
var rel common.Relationships
|
||||||
for i, wks := range s.w.xws {
|
for i, wks := range s.w.xws {
|
||||||
if wks == s.x {
|
if wks == s.x {
|
||||||
@ -288,7 +304,7 @@ func (s Sheet) SetDrawing(d Drawing) {
|
|||||||
// AddHyperlink adds a hyperlink to a sheet. Adding the hyperlink to the sheet
|
// AddHyperlink adds a hyperlink to a sheet. Adding the hyperlink to the sheet
|
||||||
// and setting it on a cell is more efficient than setting hyperlinks directly
|
// and setting it on a cell is more efficient than setting hyperlinks directly
|
||||||
// on a cell.
|
// on a cell.
|
||||||
func (s Sheet) AddHyperlink(url string) common.Hyperlink {
|
func (s *Sheet) AddHyperlink(url string) common.Hyperlink {
|
||||||
// store the relationships so we don't need to do a lookup here?
|
// store the relationships so we don't need to do a lookup here?
|
||||||
for i, ws := range s.w.xws {
|
for i, ws := range s.w.xws {
|
||||||
if ws == s.x {
|
if ws == s.x {
|
||||||
@ -318,7 +334,7 @@ func (s Sheet) RangeReference(n string) string {
|
|||||||
const autoFilterName = "_xlnm._FilterDatabase"
|
const autoFilterName = "_xlnm._FilterDatabase"
|
||||||
|
|
||||||
// ClearAutoFilter removes the autofilters from the sheet.
|
// ClearAutoFilter removes the autofilters from the sheet.
|
||||||
func (s Sheet) ClearAutoFilter() {
|
func (s *Sheet) ClearAutoFilter() {
|
||||||
s.x.AutoFilter = nil
|
s.x.AutoFilter = nil
|
||||||
sn := "'" + s.Name() + "'!"
|
sn := "'" + s.Name() + "'!"
|
||||||
// see if we have a defined auto filter name for the sheet
|
// see if we have a defined auto filter name for the sheet
|
||||||
@ -336,7 +352,7 @@ func (s Sheet) ClearAutoFilter() {
|
|||||||
// filters that are common for a header row. The RangeRef should be of the form
|
// filters that are common for a header row. The RangeRef should be of the form
|
||||||
// "A1:C5" and cover the entire range of cells to be filtered, not just the
|
// "A1:C5" and cover the entire range of cells to be filtered, not just the
|
||||||
// header. SetAutoFilter replaces any existing auto filter on the sheet.
|
// header. SetAutoFilter replaces any existing auto filter on the sheet.
|
||||||
func (s Sheet) SetAutoFilter(rangeRef string) {
|
func (s *Sheet) SetAutoFilter(rangeRef string) {
|
||||||
// this should have no $ in it
|
// this should have no $ in it
|
||||||
rangeRef = strings.Replace(rangeRef, "$", "", -1)
|
rangeRef = strings.Replace(rangeRef, "$", "", -1)
|
||||||
|
|
||||||
@ -369,7 +385,7 @@ func (s Sheet) SetAutoFilter(rangeRef string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddMergedCells merges cells within a sheet.
|
// AddMergedCells merges cells within a sheet.
|
||||||
func (s Sheet) AddMergedCells(fromRef, toRef string) MergedCell {
|
func (s *Sheet) AddMergedCells(fromRef, toRef string) MergedCell {
|
||||||
// TODO: we might need to actually create the merged cells if they don't
|
// TODO: we might need to actually create the merged cells if they don't
|
||||||
// exist, but it appears to work fine on both Excel and LibreOffice just
|
// exist, but it appears to work fine on both Excel and LibreOffice just
|
||||||
// creating the merged region
|
// creating the merged region
|
||||||
@ -383,24 +399,24 @@ func (s Sheet) AddMergedCells(fromRef, toRef string) MergedCell {
|
|||||||
|
|
||||||
s.x.MergeCells.MergeCell = append(s.x.MergeCells.MergeCell, merge)
|
s.x.MergeCells.MergeCell = append(s.x.MergeCells.MergeCell, merge)
|
||||||
s.x.MergeCells.CountAttr = unioffice.Uint32(uint32(len(s.x.MergeCells.MergeCell)))
|
s.x.MergeCells.CountAttr = unioffice.Uint32(uint32(len(s.x.MergeCells.MergeCell)))
|
||||||
return MergedCell{s.w, s.x, merge}
|
return MergedCell{s.w, s, merge}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MergedCells returns the merged cell regions within the sheet.
|
// MergedCells returns the merged cell regions within the sheet.
|
||||||
func (s Sheet) MergedCells() []MergedCell {
|
func (s *Sheet) MergedCells() []MergedCell {
|
||||||
if s.x.MergeCells == nil {
|
if s.x.MergeCells == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ret := []MergedCell{}
|
ret := []MergedCell{}
|
||||||
for _, c := range s.x.MergeCells.MergeCell {
|
for _, c := range s.x.MergeCells.MergeCell {
|
||||||
ret = append(ret, MergedCell{s.w, s.x, c})
|
ret = append(ret, MergedCell{s.w, s, c})
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveMergedCell removes merging from a cell range within a sheet. The cells
|
// RemoveMergedCell removes merging from a cell range within a sheet. The cells
|
||||||
// that made up the merged cell remain, but are no lon merged.
|
// that made up the merged cell remain, but are no lon merged.
|
||||||
func (s Sheet) RemoveMergedCell(mc MergedCell) {
|
func (s *Sheet) RemoveMergedCell(mc MergedCell) {
|
||||||
for i, c := range s.x.MergeCells.MergeCell {
|
for i, c := range s.x.MergeCells.MergeCell {
|
||||||
if c == mc.X() {
|
if c == mc.X() {
|
||||||
copy(s.x.MergeCells.MergeCell[i:], s.x.MergeCells.MergeCell[i+1:])
|
copy(s.x.MergeCells.MergeCell[i:], s.x.MergeCells.MergeCell[i+1:])
|
||||||
@ -443,7 +459,7 @@ func (s Sheet) Extents() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddConditionalFormatting adds conditional formatting to the sheet.
|
// AddConditionalFormatting adds conditional formatting to the sheet.
|
||||||
func (s Sheet) AddConditionalFormatting(cellRanges []string) ConditionalFormatting {
|
func (s *Sheet) AddConditionalFormatting(cellRanges []string) ConditionalFormatting {
|
||||||
cfmt := sml.NewCT_ConditionalFormatting()
|
cfmt := sml.NewCT_ConditionalFormatting()
|
||||||
s.x.ConditionalFormatting = append(s.x.ConditionalFormatting, cfmt)
|
s.x.ConditionalFormatting = append(s.x.ConditionalFormatting, cfmt)
|
||||||
|
|
||||||
@ -460,7 +476,7 @@ func (s Sheet) AddConditionalFormatting(cellRanges []string) ConditionalFormatti
|
|||||||
// can span multiple column indices, this method will return the column that
|
// can span multiple column indices, this method will return the column that
|
||||||
// applies to a column index if it exists or create a new column that only
|
// applies to a column index if it exists or create a new column that only
|
||||||
// applies to the index passed in otherwise.
|
// applies to the index passed in otherwise.
|
||||||
func (s Sheet) Column(idx uint32) Column {
|
func (s *Sheet) Column(idx uint32) Column {
|
||||||
// scan for any existing column that covers this index
|
// scan for any existing column that covers this index
|
||||||
for _, colSet := range s.x.Cols {
|
for _, colSet := range s.x.Cols {
|
||||||
for _, col := range colSet.Col {
|
for _, col := range colSet.Col {
|
||||||
@ -487,7 +503,7 @@ func (s Sheet) Column(idx uint32) Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Comments returns the comments for a sheet.
|
// Comments returns the comments for a sheet.
|
||||||
func (s Sheet) Comments() Comments {
|
func (s *Sheet) Comments() Comments {
|
||||||
for i, wks := range s.w.xws {
|
for i, wks := range s.w.xws {
|
||||||
if wks == s.x {
|
if wks == s.x {
|
||||||
if s.w.comments[i] == nil {
|
if s.w.comments[i] == nil {
|
||||||
@ -518,7 +534,7 @@ func (s Sheet) Comments() Comments {
|
|||||||
// the cells on the top,left,right,bottom and four corners. This function
|
// the cells on the top,left,right,bottom and four corners. This function
|
||||||
// breaks apart a single border into its components and applies it to cells as
|
// breaks apart a single border into its components and applies it to cells as
|
||||||
// needed to give the effect of a border applying to multiple cells.
|
// needed to give the effect of a border applying to multiple cells.
|
||||||
func (s Sheet) SetBorder(cellRange string, border Border) error {
|
func (s *Sheet) SetBorder(cellRange string, border Border) error {
|
||||||
from, to, err := reference.ParseRangeReference(cellRange)
|
from, to, err := reference.ParseRangeReference(cellRange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -605,7 +621,7 @@ func (s Sheet) SetBorder(cellRange string, border Border) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddDataValidation adds a data validation rule to a sheet.
|
// AddDataValidation adds a data validation rule to a sheet.
|
||||||
func (s Sheet) AddDataValidation() DataValidation {
|
func (s *Sheet) AddDataValidation() DataValidation {
|
||||||
if s.x.DataValidations == nil {
|
if s.x.DataValidations == nil {
|
||||||
s.x.DataValidations = sml.NewCT_DataValidations()
|
s.x.DataValidations = sml.NewCT_DataValidations()
|
||||||
}
|
}
|
||||||
@ -860,8 +876,8 @@ func (s *Sheet) Sort(column string, firstRow uint32, order SortOrder) {
|
|||||||
cmp := Comparer{Order: order}
|
cmp := Comparer{Order: order}
|
||||||
sort.Slice(sheetData, func(i, j int) bool {
|
sort.Slice(sheetData, func(i, j int) bool {
|
||||||
return cmp.LessRows(column,
|
return cmp.LessRows(column,
|
||||||
Row{s.w, s.x, sheetData[i]},
|
Row{s.w, s, sheetData[i]},
|
||||||
Row{s.w, s.x, sheetData[j]})
|
Row{s.w, s, sheetData[j]})
|
||||||
})
|
})
|
||||||
|
|
||||||
// since we probably moved some rows, we need to go and fix up their row
|
// since we probably moved some rows, we need to go and fix up their row
|
||||||
|
@ -369,3 +369,16 @@ func TestRemoveColumn(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCellsWithEmpty(t *testing.T) {
|
||||||
|
wb := spreadsheet.New()
|
||||||
|
sheet := wb.AddSheet()
|
||||||
|
sheet.Cell("A1").SetNumber(1)
|
||||||
|
sheet.Cell("F2").SetNumber(1)
|
||||||
|
rows := sheet.Rows()
|
||||||
|
exp := 6
|
||||||
|
got := len(rows[0].CellsWithEmpty(sheet.MaxColumnIdx()))
|
||||||
|
if got != exp {
|
||||||
|
t.Errorf("expected %d cells in row, got %d", exp, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@ package update
|
|||||||
|
|
||||||
// UpdateAction is the type for update types constants.
|
// UpdateAction is the type for update types constants.
|
||||||
type UpdateAction byte
|
type UpdateAction byte
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// UpdateActionRemoveColumn means updating references after removing a column.
|
// UpdateActionRemoveColumn means updating references after removing a column.
|
||||||
UpdateActionRemoveColumn UpdateAction = iota
|
UpdateActionRemoveColumn UpdateAction = iota
|
||||||
|
@ -237,7 +237,8 @@ func (wb *Workbook) CopySheet(ind int, copiedSheetName string) (Sheet, error) {
|
|||||||
wb.comments = append(wb.comments, &copiedComments)
|
wb.comments = append(wb.comments, &copiedComments)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Sheet{wb, &copiedSheet, &copiedWs}, nil
|
sheet := Sheet{wb, &copiedSheet, &copiedWs}
|
||||||
|
return sheet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopySheetByName copies the existing sheet with the name `name` and puts its copy with the name `copiedSheetName`.
|
// CopySheetByName copies the existing sheet with the name `name` and puts its copy with the name `copiedSheetName`.
|
||||||
@ -438,7 +439,8 @@ func (wb *Workbook) Sheets() []Sheet {
|
|||||||
ret := []Sheet{}
|
ret := []Sheet{}
|
||||||
for i, wks := range wb.xws {
|
for i, wks := range wb.xws {
|
||||||
r := wb.x.Sheets.Sheet[i]
|
r := wb.x.Sheets.Sheet[i]
|
||||||
ret = append(ret, Sheet{wb, r, wks})
|
sheet := Sheet{wb, r, wks}
|
||||||
|
ret = append(ret, sheet)
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user