summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarrison <harrison3000@users.noreply.github.com>2022-10-10 13:05:02 -0300
committerGitHub <noreply@github.com>2022-10-11 00:05:02 +0800
commitc02346bafc6e098406f32ee0a183d45f3038c619 (patch)
tree7c04d06c12b9850b1940cf4a476036b5df974850
parent2f5704b114d033e81725f18459f9293a9adfee1e (diff)
This closes #1047, stream writer support set panes (#1123)
- New exported error `ErrStreamSetPanes` has been added
-rw-r--r--errors.go3
-rw-r--r--sheet.go68
-rw-r--r--sheet_test.go2
-rw-r--r--stream.go35
-rw-r--r--stream_test.go12
5 files changed, 78 insertions, 42 deletions
diff --git a/errors.go b/errors.go
index 48476bc..fd896a6 100644
--- a/errors.go
+++ b/errors.go
@@ -91,6 +91,9 @@ var (
// ErrStreamSetColWidth defined the error message on set column width in
// stream writing mode.
ErrStreamSetColWidth = errors.New("must call the SetColWidth function before the SetRow function")
+ // ErrStreamSetPanes defined the error message on set panes in stream
+ // writing mode.
+ ErrStreamSetPanes = errors.New("must call the SetPanes function before the SetRow function")
// ErrColumnNumber defined the error message on receive an invalid column
// number.
ErrColumnNumber = fmt.Errorf(`the column number must be greater than or equal to %d and less than or equal to %d`, MinColumns, MaxColumns)
diff --git a/sheet.go b/sheet.go
index a737a9a..71123d7 100644
--- a/sheet.go
+++ b/sheet.go
@@ -683,8 +683,44 @@ func parsePanesOptions(opts string) (*panesOptions, error) {
return &format, err
}
+// setPanes set create freeze panes and split panes by given options.
+func (ws *xlsxWorksheet) setPanes(panes string) error {
+ opts, err := parsePanesOptions(panes)
+ if err != nil {
+ return err
+ }
+ p := &xlsxPane{
+ ActivePane: opts.ActivePane,
+ TopLeftCell: opts.TopLeftCell,
+ XSplit: float64(opts.XSplit),
+ YSplit: float64(opts.YSplit),
+ }
+ if opts.Freeze {
+ p.State = "frozen"
+ }
+ if ws.SheetViews == nil {
+ ws.SheetViews = &xlsxSheetViews{SheetView: []xlsxSheetView{{}}}
+ }
+ ws.SheetViews.SheetView[len(ws.SheetViews.SheetView)-1].Pane = p
+ if !(opts.Freeze) && !(opts.Split) {
+ if len(ws.SheetViews.SheetView) > 0 {
+ ws.SheetViews.SheetView[len(ws.SheetViews.SheetView)-1].Pane = nil
+ }
+ }
+ var s []*xlsxSelection
+ for _, p := range opts.Panes {
+ s = append(s, &xlsxSelection{
+ ActiveCell: p.ActiveCell,
+ Pane: p.Pane,
+ SQRef: p.SQRef,
+ })
+ }
+ ws.SheetViews.SheetView[len(ws.SheetViews.SheetView)-1].Selection = s
+ return err
+}
+
// SetPanes provides a function to create and remove freeze panes and split panes
-// by given worksheet name and panes format set.
+// by given worksheet name and panes options.
//
// activePane defines the pane that is active. The possible values for this
// attribute are defined in the following table:
@@ -768,39 +804,11 @@ func parsePanesOptions(opts string) (*panesOptions, error) {
//
// f.SetPanes("Sheet1", `{"freeze":false,"split":false}`)
func (f *File) SetPanes(sheet, panes string) error {
- fs, _ := parsePanesOptions(panes)
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
- p := &xlsxPane{
- ActivePane: fs.ActivePane,
- TopLeftCell: fs.TopLeftCell,
- XSplit: float64(fs.XSplit),
- YSplit: float64(fs.YSplit),
- }
- if fs.Freeze {
- p.State = "frozen"
- }
- if ws.SheetViews == nil {
- ws.SheetViews = &xlsxSheetViews{SheetView: []xlsxSheetView{{}}}
- }
- ws.SheetViews.SheetView[len(ws.SheetViews.SheetView)-1].Pane = p
- if !(fs.Freeze) && !(fs.Split) {
- if len(ws.SheetViews.SheetView) > 0 {
- ws.SheetViews.SheetView[len(ws.SheetViews.SheetView)-1].Pane = nil
- }
- }
- var s []*xlsxSelection
- for _, p := range fs.Panes {
- s = append(s, &xlsxSelection{
- ActiveCell: p.ActiveCell,
- Pane: p.Pane,
- SQRef: p.SQRef,
- })
- }
- ws.SheetViews.SheetView[len(ws.SheetViews.SheetView)-1].Selection = s
- return err
+ return ws.setPanes(panes)
}
// GetSheetVisible provides a function to get worksheet visible by given worksheet
diff --git a/sheet_test.go b/sheet_test.go
index 74ca02c..6e87de9 100644
--- a/sheet_test.go
+++ b/sheet_test.go
@@ -34,7 +34,7 @@ func TestSetPane(t *testing.T) {
assert.NoError(t, f.SetPanes("Panes 3", `{"freeze":false,"split":true,"x_split":3270,"y_split":1800,"top_left_cell":"N57","active_pane":"bottomLeft","panes":[{"sqref":"I36","active_cell":"I36"},{"sqref":"G33","active_cell":"G33","pane":"topRight"},{"sqref":"J60","active_cell":"J60","pane":"bottomLeft"},{"sqref":"O60","active_cell":"O60","pane":"bottomRight"}]}`))
f.NewSheet("Panes 4")
assert.NoError(t, f.SetPanes("Panes 4", `{"freeze":true,"split":false,"x_split":0,"y_split":9,"top_left_cell":"A34","active_pane":"bottomLeft","panes":[{"sqref":"A11:XFD11","active_cell":"A11","pane":"bottomLeft"}]}`))
- assert.NoError(t, f.SetPanes("Panes 4", ""))
+ assert.EqualError(t, f.SetPanes("Panes 4", ""), "unexpected end of JSON input")
assert.EqualError(t, f.SetPanes("SheetN", ""), "sheet SheetN does not exist")
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetPane.xlsx")))
// Test add pane on empty sheet views worksheet
diff --git a/stream.go b/stream.go
index 66c0fda..9f47762 100644
--- a/stream.go
+++ b/stream.go
@@ -119,7 +119,7 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
f.streams[sheetXMLPath] = sw
_, _ = sw.rawData.WriteString(xml.Header + `<worksheet` + templateNamespaceIDMap)
- bulkAppendFields(&sw.rawData, sw.worksheet, 2, 5)
+ bulkAppendFields(&sw.rawData, sw.worksheet, 2, 3)
return sw, err
}
@@ -351,13 +351,7 @@ func (sw *StreamWriter) SetRow(cell string, values []interface{}, opts ...RowOpt
if err != nil {
return err
}
- if !sw.sheetWritten {
- if len(sw.cols) > 0 {
- _, _ = sw.rawData.WriteString("<cols>" + sw.cols + "</cols>")
- }
- _, _ = sw.rawData.WriteString(`<sheetData>`)
- sw.sheetWritten = true
- }
+ sw.writeSheetData()
options := parseRowOpts(opts...)
attrs, err := options.marshalAttrs()
if err != nil {
@@ -415,6 +409,16 @@ func (sw *StreamWriter) SetColWidth(min, max int, width float64) error {
return nil
}
+// SetPanes provides a function to create and remove freeze panes and split
+// panes by given worksheet name and panes options for the StreamWriter. Note
+// that you must call the 'SetPanes' function before the 'SetRow' function.
+func (sw *StreamWriter) SetPanes(panes string) error {
+ if sw.sheetWritten {
+ return ErrStreamSetPanes
+ }
+ return sw.worksheet.setPanes(panes)
+}
+
// MergeCell provides a function to merge cells by a given range reference for
// the StreamWriter. Don't create a merged cell that overlaps with another
// existing merged cell.
@@ -507,6 +511,7 @@ func setCellIntFunc(c *xlsxC, val interface{}) (err error) {
return
}
+// writeCell constructs a cell XML and writes it to the buffer.
func writeCell(buf *bufferedWriter, c xlsxC) {
_, _ = buf.WriteString(`<c`)
if c.XMLSpace.Value != "" {
@@ -539,12 +544,22 @@ func writeCell(buf *bufferedWriter, c xlsxC) {
_, _ = buf.WriteString(`</c>`)
}
-// Flush ending the streaming writing process.
-func (sw *StreamWriter) Flush() error {
+// writeSheetData prepares the element preceding sheetData and writes the
+// sheetData XML start element to the buffer.
+func (sw *StreamWriter) writeSheetData() {
if !sw.sheetWritten {
+ bulkAppendFields(&sw.rawData, sw.worksheet, 4, 5)
+ if len(sw.cols) > 0 {
+ _, _ = sw.rawData.WriteString("<cols>" + sw.cols + "</cols>")
+ }
_, _ = sw.rawData.WriteString(`<sheetData>`)
sw.sheetWritten = true
}
+}
+
+// Flush ending the streaming writing process.
+func (sw *StreamWriter) Flush() error {
+ sw.writeSheetData()
_, _ = sw.rawData.WriteString(`</sheetData>`)
bulkAppendFields(&sw.rawData, sw.worksheet, 8, 15)
mergeCells := strings.Builder{}
diff --git a/stream_test.go b/stream_test.go
index 3c2cc69..91aa580 100644
--- a/stream_test.go
+++ b/stream_test.go
@@ -146,7 +146,17 @@ func TestStreamSetColWidth(t *testing.T) {
assert.ErrorIs(t, streamWriter.SetColWidth(MaxColumns+1, 3, 20), ErrColumnNumber)
assert.EqualError(t, streamWriter.SetColWidth(1, 3, MaxColumnWidth+1), ErrColumnWidth.Error())
assert.NoError(t, streamWriter.SetRow("A1", []interface{}{"A", "B", "C"}))
- assert.EqualError(t, streamWriter.SetColWidth(2, 3, 20), ErrStreamSetColWidth.Error())
+ assert.ErrorIs(t, streamWriter.SetColWidth(2, 3, 20), ErrStreamSetColWidth)
+}
+
+func TestStreamSetPanes(t *testing.T) {
+ file, paneOpts := NewFile(), `{"freeze":true,"split":false,"x_split":1,"y_split":0,"top_left_cell":"B1","active_pane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}`
+ streamWriter, err := file.NewStreamWriter("Sheet1")
+ assert.NoError(t, err)
+ assert.NoError(t, streamWriter.SetPanes(paneOpts))
+ assert.EqualError(t, streamWriter.SetPanes(""), "unexpected end of JSON input")
+ assert.NoError(t, streamWriter.SetRow("A1", []interface{}{"A", "B", "C"}))
+ assert.ErrorIs(t, streamWriter.SetPanes(paneOpts), ErrStreamSetPanes)
}
func TestStreamTable(t *testing.T) {