forked from p30928647/excelize
New function `GetPanes` for get sheet panes and view selection (#1556)
- Breaking changes: rename exported type `PaneOptions` to `Selection` - Update unit tests - Upgrade dependencies package - Add internal error variables - Simplify variable declarations
This commit is contained in:
parent
661c0eade9
commit
78c974d855
|
@ -100,6 +100,12 @@ func newViewIdxError(viewIndex int) error {
|
||||||
return fmt.Errorf("view index %d out of range", viewIndex)
|
return fmt.Errorf("view index %d out of range", viewIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newUnknownFilterTokenError defined the error message on receiving a unknown
|
||||||
|
// filter operator token.
|
||||||
|
func newUnknownFilterTokenError(token string) error {
|
||||||
|
return fmt.Errorf("unknown operator: %s", token)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrStreamSetColWidth defined the error message on set column width in
|
// ErrStreamSetColWidth defined the error message on set column width in
|
||||||
// stream writing mode.
|
// stream writing mode.
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -8,9 +8,9 @@ require (
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9
|
github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9
|
||||||
github.com/xuri/nfp v0.0.0-20230503010013-3f38cdbb0b83
|
github.com/xuri/nfp v0.0.0-20230503010013-3f38cdbb0b83
|
||||||
golang.org/x/crypto v0.8.0
|
golang.org/x/crypto v0.9.0
|
||||||
golang.org/x/image v0.5.0
|
golang.org/x/image v0.5.0
|
||||||
golang.org/x/net v0.9.0
|
golang.org/x/net v0.10.0
|
||||||
golang.org/x/text v0.9.0
|
golang.org/x/text v0.9.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -22,8 +22,8 @@ github.com/xuri/nfp v0.0.0-20230503010013-3f38cdbb0b83/go.mod h1:WwHg+CVyzlv/TX9
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
|
golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
|
||||||
golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
|
golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
@ -32,8 +32,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -43,11 +43,11 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
|
12
numfmt.go
12
numfmt.go
|
@ -1018,8 +1018,13 @@ var (
|
||||||
// applyBuiltInNumFmt provides a function to returns a value after formatted
|
// applyBuiltInNumFmt provides a function to returns a value after formatted
|
||||||
// with built-in number format code, or specified sort date format code.
|
// with built-in number format code, or specified sort date format code.
|
||||||
func (f *File) applyBuiltInNumFmt(c *xlsxC, fmtCode string, numFmtID int, date1904 bool, cellType CellType) string {
|
func (f *File) applyBuiltInNumFmt(c *xlsxC, fmtCode string, numFmtID int, date1904 bool, cellType CellType) string {
|
||||||
if numFmtID == 14 && f.options != nil && f.options.ShortDatePattern != "" {
|
if f.options != nil && f.options.ShortDatePattern != "" {
|
||||||
fmtCode = f.options.ShortDatePattern
|
if numFmtID == 14 {
|
||||||
|
fmtCode = f.options.ShortDatePattern
|
||||||
|
}
|
||||||
|
if numFmtID == 22 {
|
||||||
|
fmtCode = fmt.Sprintf("%s hh:mm", f.options.ShortDatePattern)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return format(c.V, fmtCode, date1904, cellType, f.options)
|
return format(c.V, fmtCode, date1904, cellType, f.options)
|
||||||
}
|
}
|
||||||
|
@ -1073,9 +1078,6 @@ func (f *File) langNumFmtFuncZhCN(numFmtID int) string {
|
||||||
// getBuiltInNumFmtCode convert number format index to number format code with
|
// getBuiltInNumFmtCode convert number format index to number format code with
|
||||||
// specified locale and language.
|
// specified locale and language.
|
||||||
func (f *File) getBuiltInNumFmtCode(numFmtID int) (string, bool) {
|
func (f *File) getBuiltInNumFmtCode(numFmtID int) (string, bool) {
|
||||||
if numFmtID == 22 && f.options.ShortDatePattern != "" {
|
|
||||||
return fmt.Sprintf("%s hh:mm", f.options.ShortDatePattern), true
|
|
||||||
}
|
|
||||||
if fmtCode, ok := builtInNumFmt[numFmtID]; ok {
|
if fmtCode, ok := builtInNumFmt[numFmtID]; ok {
|
||||||
return fmtCode, true
|
return fmtCode, true
|
||||||
}
|
}
|
||||||
|
|
52
sheet.go
52
sheet.go
|
@ -772,7 +772,7 @@ func (ws *xlsxWorksheet) setPanes(panes *Panes) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var s []*xlsxSelection
|
var s []*xlsxSelection
|
||||||
for _, p := range panes.Panes {
|
for _, p := range panes.Selection {
|
||||||
s = append(s, &xlsxSelection{
|
s = append(s, &xlsxSelection{
|
||||||
ActiveCell: p.ActiveCell,
|
ActiveCell: p.ActiveCell,
|
||||||
Pane: p.Pane,
|
Pane: p.Pane,
|
||||||
|
@ -859,7 +859,7 @@ func (ws *xlsxWorksheet) setPanes(panes *Panes) error {
|
||||||
// YSplit: 0,
|
// YSplit: 0,
|
||||||
// TopLeftCell: "B1",
|
// TopLeftCell: "B1",
|
||||||
// ActivePane: "topRight",
|
// ActivePane: "topRight",
|
||||||
// Panes: []excelize.PaneOptions{
|
// Selection: []excelize.Selection{
|
||||||
// {SQRef: "K16", ActiveCell: "K16", Pane: "topRight"},
|
// {SQRef: "K16", ActiveCell: "K16", Pane: "topRight"},
|
||||||
// },
|
// },
|
||||||
// })
|
// })
|
||||||
|
@ -874,7 +874,7 @@ func (ws *xlsxWorksheet) setPanes(panes *Panes) error {
|
||||||
// YSplit: 9,
|
// YSplit: 9,
|
||||||
// TopLeftCell: "A34",
|
// TopLeftCell: "A34",
|
||||||
// ActivePane: "bottomLeft",
|
// ActivePane: "bottomLeft",
|
||||||
// Panes: []excelize.PaneOptions{
|
// Selection: []excelize.Selection{
|
||||||
// {SQRef: "A11:XFD11", ActiveCell: "A11", Pane: "bottomLeft"},
|
// {SQRef: "A11:XFD11", ActiveCell: "A11", Pane: "bottomLeft"},
|
||||||
// },
|
// },
|
||||||
// })
|
// })
|
||||||
|
@ -889,7 +889,7 @@ func (ws *xlsxWorksheet) setPanes(panes *Panes) error {
|
||||||
// YSplit: 1800,
|
// YSplit: 1800,
|
||||||
// TopLeftCell: "N57",
|
// TopLeftCell: "N57",
|
||||||
// ActivePane: "bottomLeft",
|
// ActivePane: "bottomLeft",
|
||||||
// Panes: []excelize.PaneOptions{
|
// Selection: []excelize.Selection{
|
||||||
// {SQRef: "I36", ActiveCell: "I36"},
|
// {SQRef: "I36", ActiveCell: "I36"},
|
||||||
// {SQRef: "G33", ActiveCell: "G33", Pane: "topRight"},
|
// {SQRef: "G33", ActiveCell: "G33", Pane: "topRight"},
|
||||||
// {SQRef: "J60", ActiveCell: "J60", Pane: "bottomLeft"},
|
// {SQRef: "J60", ActiveCell: "J60", Pane: "bottomLeft"},
|
||||||
|
@ -908,6 +908,50 @@ func (f *File) SetPanes(sheet string, panes *Panes) error {
|
||||||
return ws.setPanes(panes)
|
return ws.setPanes(panes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getPanes returns freeze panes, split panes, and views of the worksheet.
|
||||||
|
func (ws *xlsxWorksheet) getPanes() Panes {
|
||||||
|
var (
|
||||||
|
panes Panes
|
||||||
|
section []Selection
|
||||||
|
)
|
||||||
|
if ws.SheetViews == nil || len(ws.SheetViews.SheetView) < 1 {
|
||||||
|
return panes
|
||||||
|
}
|
||||||
|
sw := ws.SheetViews.SheetView[len(ws.SheetViews.SheetView)-1]
|
||||||
|
for _, s := range sw.Selection {
|
||||||
|
if s != nil {
|
||||||
|
section = append(section, Selection{
|
||||||
|
SQRef: s.SQRef,
|
||||||
|
ActiveCell: s.ActiveCell,
|
||||||
|
Pane: s.Pane,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panes.Selection = section
|
||||||
|
if sw.Pane == nil {
|
||||||
|
return panes
|
||||||
|
}
|
||||||
|
panes.ActivePane = sw.Pane.ActivePane
|
||||||
|
if sw.Pane.State == "frozen" {
|
||||||
|
panes.Freeze = true
|
||||||
|
}
|
||||||
|
panes.TopLeftCell = sw.Pane.TopLeftCell
|
||||||
|
panes.XSplit = int(sw.Pane.XSplit)
|
||||||
|
panes.YSplit = int(sw.Pane.YSplit)
|
||||||
|
return panes
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPanes provides a function to get freeze panes, split panes, and worksheet
|
||||||
|
// views by given worksheet name.
|
||||||
|
func (f *File) GetPanes(sheet string) (Panes, error) {
|
||||||
|
var panes Panes
|
||||||
|
ws, err := f.workSheetReader(sheet)
|
||||||
|
if err != nil {
|
||||||
|
return panes, err
|
||||||
|
}
|
||||||
|
return ws.getPanes(), err
|
||||||
|
}
|
||||||
|
|
||||||
// GetSheetVisible provides a function to get worksheet visible by given worksheet
|
// GetSheetVisible provides a function to get worksheet visible by given worksheet
|
||||||
// name. For example, get visible state of Sheet1:
|
// name. For example, get visible state of Sheet1:
|
||||||
//
|
//
|
||||||
|
|
|
@ -37,25 +37,29 @@ func TestNewSheet(t *testing.T) {
|
||||||
assert.Equal(t, -1, sheetID)
|
assert.Equal(t, -1, sheetID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetPanes(t *testing.T) {
|
func TestPanes(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
|
|
||||||
assert.NoError(t, f.SetPanes("Sheet1", &Panes{Freeze: false, Split: false}))
|
assert.NoError(t, f.SetPanes("Sheet1", &Panes{Freeze: false, Split: false}))
|
||||||
_, err := f.NewSheet("Panes 2")
|
_, err := f.NewSheet("Panes 2")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, f.SetPanes("Panes 2",
|
|
||||||
&Panes{
|
expected := Panes{
|
||||||
Freeze: true,
|
Freeze: true,
|
||||||
Split: false,
|
Split: false,
|
||||||
XSplit: 1,
|
XSplit: 1,
|
||||||
YSplit: 0,
|
YSplit: 0,
|
||||||
TopLeftCell: "B1",
|
TopLeftCell: "B1",
|
||||||
ActivePane: "topRight",
|
ActivePane: "topRight",
|
||||||
Panes: []PaneOptions{
|
Selection: []Selection{
|
||||||
{SQRef: "K16", ActiveCell: "K16", Pane: "topRight"},
|
{SQRef: "K16", ActiveCell: "K16", Pane: "topRight"},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
))
|
}
|
||||||
|
assert.NoError(t, f.SetPanes("Panes 2", &expected))
|
||||||
|
panes, err := f.GetPanes("Panes 2")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expected, panes)
|
||||||
|
|
||||||
_, err = f.NewSheet("Panes 3")
|
_, err = f.NewSheet("Panes 3")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, f.SetPanes("Panes 3",
|
assert.NoError(t, f.SetPanes("Panes 3",
|
||||||
|
@ -66,7 +70,7 @@ func TestSetPanes(t *testing.T) {
|
||||||
YSplit: 1800,
|
YSplit: 1800,
|
||||||
TopLeftCell: "N57",
|
TopLeftCell: "N57",
|
||||||
ActivePane: "bottomLeft",
|
ActivePane: "bottomLeft",
|
||||||
Panes: []PaneOptions{
|
Selection: []Selection{
|
||||||
{SQRef: "I36", ActiveCell: "I36"},
|
{SQRef: "I36", ActiveCell: "I36"},
|
||||||
{SQRef: "G33", ActiveCell: "G33", Pane: "topRight"},
|
{SQRef: "G33", ActiveCell: "G33", Pane: "topRight"},
|
||||||
{SQRef: "J60", ActiveCell: "J60", Pane: "bottomLeft"},
|
{SQRef: "J60", ActiveCell: "J60", Pane: "bottomLeft"},
|
||||||
|
@ -84,7 +88,7 @@ func TestSetPanes(t *testing.T) {
|
||||||
YSplit: 9,
|
YSplit: 9,
|
||||||
TopLeftCell: "A34",
|
TopLeftCell: "A34",
|
||||||
ActivePane: "bottomLeft",
|
ActivePane: "bottomLeft",
|
||||||
Panes: []PaneOptions{
|
Selection: []Selection{
|
||||||
{SQRef: "A11:XFD11", ActiveCell: "A11", Pane: "bottomLeft"},
|
{SQRef: "A11:XFD11", ActiveCell: "A11", Pane: "bottomLeft"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -94,6 +98,26 @@ func TestSetPanes(t *testing.T) {
|
||||||
// Test set panes with invalid sheet name
|
// Test set panes with invalid sheet name
|
||||||
assert.EqualError(t, f.SetPanes("Sheet:1", &Panes{Freeze: false, Split: false}), ErrSheetNameInvalid.Error())
|
assert.EqualError(t, f.SetPanes("Sheet:1", &Panes{Freeze: false, Split: false}), ErrSheetNameInvalid.Error())
|
||||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetPane.xlsx")))
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetPane.xlsx")))
|
||||||
|
|
||||||
|
// Test get panes with empty sheet views
|
||||||
|
f = NewFile()
|
||||||
|
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
|
||||||
|
assert.True(t, ok)
|
||||||
|
ws.(*xlsxWorksheet).SheetViews = &xlsxSheetViews{}
|
||||||
|
_, err = f.GetPanes("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// Test get panes without panes
|
||||||
|
ws.(*xlsxWorksheet).SheetViews = &xlsxSheetViews{SheetView: []xlsxSheetView{{}}}
|
||||||
|
_, err = f.GetPanes("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// Test get panes without sheet views
|
||||||
|
ws.(*xlsxWorksheet).SheetViews = nil
|
||||||
|
_, err = f.GetPanes("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// Test get panes on not exists worksheet
|
||||||
|
_, err = f.GetPanes("SheetN")
|
||||||
|
assert.EqualError(t, err, "sheet SheetN does not exist")
|
||||||
|
|
||||||
// Test add pane on empty sheet views worksheet
|
// Test add pane on empty sheet views worksheet
|
||||||
f = NewFile()
|
f = NewFile()
|
||||||
f.checked = nil
|
f.checked = nil
|
||||||
|
@ -107,7 +131,7 @@ func TestSetPanes(t *testing.T) {
|
||||||
YSplit: 0,
|
YSplit: 0,
|
||||||
TopLeftCell: "B1",
|
TopLeftCell: "B1",
|
||||||
ActivePane: "topRight",
|
ActivePane: "topRight",
|
||||||
Panes: []PaneOptions{
|
Selection: []Selection{
|
||||||
{SQRef: "K16", ActiveCell: "K16", Pane: "topRight"},
|
{SQRef: "K16", ActiveCell: "K16", Pane: "topRight"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -61,11 +61,7 @@ func (view *xlsxSheetView) setSheetView(opts *ViewOptions) {
|
||||||
view.TopLeftCell = *opts.TopLeftCell
|
view.TopLeftCell = *opts.TopLeftCell
|
||||||
}
|
}
|
||||||
if opts.View != nil {
|
if opts.View != nil {
|
||||||
if _, ok := map[string]interface{}{
|
if inStrSlice([]string{"normal", "pageLayout", "pageBreakPreview"}, *opts.View, true) != -1 {
|
||||||
"normal": nil,
|
|
||||||
"pageLayout": nil,
|
|
||||||
"pageBreakPreview": nil,
|
|
||||||
}[*opts.View]; ok {
|
|
||||||
view.View = *opts.View
|
view.View = *opts.View
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ func TestStreamSetPanes(t *testing.T) {
|
||||||
YSplit: 0,
|
YSplit: 0,
|
||||||
TopLeftCell: "B1",
|
TopLeftCell: "B1",
|
||||||
ActivePane: "topRight",
|
ActivePane: "topRight",
|
||||||
Panes: []PaneOptions{
|
Selection: []Selection{
|
||||||
{SQRef: "K16", ActiveCell: "K16", Pane: "topRight"},
|
{SQRef: "K16", ActiveCell: "K16", Pane: "topRight"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
53
table.go
53
table.go
|
@ -430,22 +430,23 @@ func (f *File) writeAutoFilter(fc *xlsxFilterColumn, exp []int, tokens []string)
|
||||||
var filters []*xlsxFilter
|
var filters []*xlsxFilter
|
||||||
filters = append(filters, &xlsxFilter{Val: tokens[0]})
|
filters = append(filters, &xlsxFilter{Val: tokens[0]})
|
||||||
fc.Filters = &xlsxFilters{Filter: filters}
|
fc.Filters = &xlsxFilters{Filter: filters}
|
||||||
} else if len(exp) == 3 && exp[0] == 2 && exp[1] == 1 && exp[2] == 2 {
|
return
|
||||||
|
}
|
||||||
|
if len(exp) == 3 && exp[0] == 2 && exp[1] == 1 && exp[2] == 2 {
|
||||||
// Double equality with "or" operator.
|
// Double equality with "or" operator.
|
||||||
var filters []*xlsxFilter
|
var filters []*xlsxFilter
|
||||||
for _, v := range tokens {
|
for _, v := range tokens {
|
||||||
filters = append(filters, &xlsxFilter{Val: v})
|
filters = append(filters, &xlsxFilter{Val: v})
|
||||||
}
|
}
|
||||||
fc.Filters = &xlsxFilters{Filter: filters}
|
fc.Filters = &xlsxFilters{Filter: filters}
|
||||||
} else {
|
return
|
||||||
// Non default custom filter.
|
}
|
||||||
expRel := map[int]int{0: 0, 1: 2}
|
// Non default custom filter.
|
||||||
andRel := map[int]bool{0: true, 1: false}
|
expRel, andRel := map[int]int{0: 0, 1: 2}, map[int]bool{0: true, 1: false}
|
||||||
for k, v := range tokens {
|
for k, v := range tokens {
|
||||||
f.writeCustomFilter(fc, exp[expRel[k]], v)
|
f.writeCustomFilter(fc, exp[expRel[k]], v)
|
||||||
if k == 1 {
|
if k == 1 {
|
||||||
fc.CustomFilters.And = andRel[exp[k]]
|
fc.CustomFilters.And = andRel[exp[k]]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,11 +468,11 @@ func (f *File) writeCustomFilter(fc *xlsxFilterColumn, operator int, val string)
|
||||||
}
|
}
|
||||||
if fc.CustomFilters != nil {
|
if fc.CustomFilters != nil {
|
||||||
fc.CustomFilters.CustomFilter = append(fc.CustomFilters.CustomFilter, &customFilter)
|
fc.CustomFilters.CustomFilter = append(fc.CustomFilters.CustomFilter, &customFilter)
|
||||||
} else {
|
return
|
||||||
var customFilters []*xlsxCustomFilter
|
|
||||||
customFilters = append(customFilters, &customFilter)
|
|
||||||
fc.CustomFilters = &xlsxCustomFilters{CustomFilter: customFilters}
|
|
||||||
}
|
}
|
||||||
|
var customFilters []*xlsxCustomFilter
|
||||||
|
customFilters = append(customFilters, &customFilter)
|
||||||
|
fc.CustomFilters = &xlsxCustomFilters{CustomFilter: customFilters}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseFilterExpression provides a function to converts the tokens of a
|
// parseFilterExpression provides a function to converts the tokens of a
|
||||||
|
@ -488,8 +489,7 @@ func (f *File) parseFilterExpression(expression string, tokens []string) ([]int,
|
||||||
if len(tokens) == 7 {
|
if len(tokens) == 7 {
|
||||||
// The number of tokens will be either 3 (for 1 expression) or 7 (for 2
|
// The number of tokens will be either 3 (for 1 expression) or 7 (for 2
|
||||||
// expressions).
|
// expressions).
|
||||||
conditional := 0
|
conditional, c := 0, tokens[3]
|
||||||
c := tokens[3]
|
|
||||||
if conditionFormat.MatchString(c) {
|
if conditionFormat.MatchString(c) {
|
||||||
conditional = 1
|
conditional = 1
|
||||||
}
|
}
|
||||||
|
@ -501,17 +501,13 @@ func (f *File) parseFilterExpression(expression string, tokens []string) ([]int,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return expressions, t, err
|
return expressions, t, err
|
||||||
}
|
}
|
||||||
expressions = []int{expression1[0], conditional, expression2[0]}
|
return []int{expression1[0], conditional, expression2[0]}, []string{token1, token2}, nil
|
||||||
t = []string{token1, token2}
|
|
||||||
} else {
|
|
||||||
exp, token, err := f.parseFilterTokens(expression, tokens)
|
|
||||||
if err != nil {
|
|
||||||
return expressions, t, err
|
|
||||||
}
|
|
||||||
expressions = exp
|
|
||||||
t = []string{token}
|
|
||||||
}
|
}
|
||||||
return expressions, t, nil
|
exp, token, err := f.parseFilterTokens(expression, tokens)
|
||||||
|
if err != nil {
|
||||||
|
return expressions, t, err
|
||||||
|
}
|
||||||
|
return exp, []string{token}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseFilterTokens provides a function to parse the 3 tokens of a filter
|
// parseFilterTokens provides a function to parse the 3 tokens of a filter
|
||||||
|
@ -534,7 +530,7 @@ func (f *File) parseFilterTokens(expression string, tokens []string) ([]int, str
|
||||||
operator, ok := operators[strings.ToLower(tokens[1])]
|
operator, ok := operators[strings.ToLower(tokens[1])]
|
||||||
if !ok {
|
if !ok {
|
||||||
// Convert the operator from a number to a descriptive string.
|
// Convert the operator from a number to a descriptive string.
|
||||||
return []int{}, "", fmt.Errorf("unknown operator: %s", tokens[1])
|
return []int{}, "", newUnknownFilterTokenError(tokens[1])
|
||||||
}
|
}
|
||||||
token := tokens[2]
|
token := tokens[2]
|
||||||
// Special handling for Blanks/NonBlanks.
|
// Special handling for Blanks/NonBlanks.
|
||||||
|
@ -563,8 +559,7 @@ func (f *File) parseFilterTokens(expression string, tokens []string) ([]int, str
|
||||||
}
|
}
|
||||||
// If the string token contains an Excel match character then change the
|
// If the string token contains an Excel match character then change the
|
||||||
// operator type to indicate a non "simple" equality.
|
// operator type to indicate a non "simple" equality.
|
||||||
re = matchFormat.MatchString(token)
|
if re = matchFormat.MatchString(token); operator == 2 && re {
|
||||||
if operator == 2 && re {
|
|
||||||
operator = 22
|
operator = 22
|
||||||
}
|
}
|
||||||
return []int{operator}, token, nil
|
return []int{operator}, token, nil
|
||||||
|
|
|
@ -894,8 +894,8 @@ type SparklineOptions struct {
|
||||||
EmptyCells string
|
EmptyCells string
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaneOptions directly maps the settings of the pane.
|
// Selection directly maps the settings of the worksheet selection.
|
||||||
type PaneOptions struct {
|
type Selection struct {
|
||||||
SQRef string
|
SQRef string
|
||||||
ActiveCell string
|
ActiveCell string
|
||||||
Pane string
|
Pane string
|
||||||
|
@ -909,7 +909,7 @@ type Panes struct {
|
||||||
YSplit int
|
YSplit int
|
||||||
TopLeftCell string
|
TopLeftCell string
|
||||||
ActivePane string
|
ActivePane string
|
||||||
Panes []PaneOptions
|
Selection []Selection
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConditionalFormatOptions directly maps the conditional format settings of the cells.
|
// ConditionalFormatOptions directly maps the conditional format settings of the cells.
|
||||||
|
|
Loading…
Reference in New Issue