diff options
author | Harrison <harrison3000@users.noreply.github.com> | 2022-10-10 13:05:02 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-11 00:05:02 +0800 |
commit | c02346bafc6e098406f32ee0a183d45f3038c619 (patch) | |
tree | 7c04d06c12b9850b1940cf4a476036b5df974850 | |
parent | 2f5704b114d033e81725f18459f9293a9adfee1e (diff) |
This closes #1047, stream writer support set panes (#1123)
- New exported error `ErrStreamSetPanes` has been added
-rw-r--r-- | errors.go | 3 | ||||
-rw-r--r-- | sheet.go | 68 | ||||
-rw-r--r-- | sheet_test.go | 2 | ||||
-rw-r--r-- | stream.go | 35 | ||||
-rw-r--r-- | stream_test.go | 12 |
5 files changed, 78 insertions, 42 deletions
@@ -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) @@ -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 @@ -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) { |