forked from p30928647/excelize
This fixes #1461, supports 0 row height and column width
- Increase max cell styles to 65430 - Add new exported error variable `ErrCellStyles` - Update unit tests, support test under Go 1.20.x
This commit is contained in:
parent
85e0b6c56e
commit
12645e7116
|
@ -5,7 +5,7 @@ jobs:
|
|||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.16.x, 1.17.x, 1.18.x, 1.19.x]
|
||||
go-version: [1.16.x, 1.17.x, 1.18.x, 1.19.x, 1.20.x]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
targetplatform: [x86, x64]
|
||||
|
||||
|
|
14
col.go
14
col.go
|
@ -300,7 +300,7 @@ func (f *File) SetColVisible(sheet, columns string, visible bool) error {
|
|||
colData := xlsxCol{
|
||||
Min: min,
|
||||
Max: max,
|
||||
Width: defaultColWidth, // default width
|
||||
Width: float64Ptr(defaultColWidth),
|
||||
Hidden: !visible,
|
||||
CustomWidth: true,
|
||||
}
|
||||
|
@ -449,7 +449,7 @@ func (f *File) SetColStyle(sheet, columns string, styleID int) error {
|
|||
ws.Cols.Col = flatCols(xlsxCol{
|
||||
Min: min,
|
||||
Max: max,
|
||||
Width: defaultColWidth,
|
||||
Width: float64Ptr(defaultColWidth),
|
||||
Style: styleID,
|
||||
}, ws.Cols.Col, func(fc, c xlsxCol) xlsxCol {
|
||||
fc.BestFit = c.BestFit
|
||||
|
@ -493,7 +493,7 @@ func (f *File) SetColWidth(sheet, startCol, endCol string, width float64) error
|
|||
col := xlsxCol{
|
||||
Min: min,
|
||||
Max: max,
|
||||
Width: width,
|
||||
Width: float64Ptr(width),
|
||||
CustomWidth: true,
|
||||
}
|
||||
if ws.Cols == nil {
|
||||
|
@ -639,8 +639,8 @@ func (f *File) getColWidth(sheet string, col int) int {
|
|||
if ws.Cols != nil {
|
||||
var width float64
|
||||
for _, v := range ws.Cols.Col {
|
||||
if v.Min <= col && col <= v.Max {
|
||||
width = v.Width
|
||||
if v.Min <= col && col <= v.Max && v.Width != nil {
|
||||
width = *v.Width
|
||||
}
|
||||
}
|
||||
if width != 0 {
|
||||
|
@ -691,8 +691,8 @@ func (f *File) GetColWidth(sheet, col string) (float64, error) {
|
|||
if ws.Cols != nil {
|
||||
var width float64
|
||||
for _, v := range ws.Cols.Col {
|
||||
if v.Min <= colNum && colNum <= v.Max {
|
||||
width = v.Width
|
||||
if v.Min <= colNum && colNum <= v.Max && v.Width != nil {
|
||||
width = *v.Width
|
||||
}
|
||||
}
|
||||
if width != 0 {
|
||||
|
|
|
@ -230,6 +230,8 @@ var (
|
|||
// ErrSheetNameLength defined the error message on receiving the sheet
|
||||
// name length exceeds the limit.
|
||||
ErrSheetNameLength = fmt.Errorf("the sheet name length exceeds the %d characters limit", MaxSheetNameLength)
|
||||
// ErrCellStyles defined the error message on cell styles exceeds the limit.
|
||||
ErrCellStyles = fmt.Errorf("the cell styles exceeds the %d limit", MaxCellStyles)
|
||||
// ErrUnprotectWorkbook defined the error message on workbook has set no
|
||||
// protection.
|
||||
ErrUnprotectWorkbook = errors.New("workbook has set no protect")
|
||||
|
|
|
@ -342,8 +342,10 @@ func TestReadBytes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnzipToTemp(t *testing.T) {
|
||||
if strings.HasPrefix(runtime.Version(), "go1.19") {
|
||||
t.Skip()
|
||||
for _, v := range []string{"go1.19", "go1.20"} {
|
||||
if strings.HasPrefix(runtime.Version(), v) {
|
||||
t.Skip()
|
||||
}
|
||||
}
|
||||
os.Setenv("TMPDIR", "test")
|
||||
defer os.Unsetenv("TMPDIR")
|
||||
|
|
12
rows.go
12
rows.go
|
@ -363,7 +363,7 @@ func (f *File) SetRowHeight(sheet string, row int, height float64) error {
|
|||
prepareSheetXML(ws, 0, row)
|
||||
|
||||
rowIdx := row - 1
|
||||
ws.SheetData.Row[rowIdx].Ht = height
|
||||
ws.SheetData.Row[rowIdx].Ht = float64Ptr(height)
|
||||
ws.SheetData.Row[rowIdx].CustomHeight = true
|
||||
return nil
|
||||
}
|
||||
|
@ -376,8 +376,8 @@ func (f *File) getRowHeight(sheet string, row int) int {
|
|||
defer ws.Unlock()
|
||||
for i := range ws.SheetData.Row {
|
||||
v := &ws.SheetData.Row[i]
|
||||
if v.R == row && v.Ht != 0 {
|
||||
return int(convertRowHeightToPixels(v.Ht))
|
||||
if v.R == row && v.Ht != nil {
|
||||
return int(convertRowHeightToPixels(*v.Ht))
|
||||
}
|
||||
}
|
||||
// Optimization for when the row heights haven't changed.
|
||||
|
@ -404,8 +404,8 @@ func (f *File) GetRowHeight(sheet string, row int) (float64, error) {
|
|||
return ht, nil // it will be better to use 0, but we take care with BC
|
||||
}
|
||||
for _, v := range ws.SheetData.Row {
|
||||
if v.R == row && v.Ht != 0 {
|
||||
return v.Ht, nil
|
||||
if v.R == row && v.Ht != nil {
|
||||
return *v.Ht, nil
|
||||
}
|
||||
}
|
||||
// Optimization for when the row heights haven't changed.
|
||||
|
@ -784,7 +784,7 @@ func checkRow(ws *xlsxWorksheet) error {
|
|||
|
||||
// hasAttr determine if row non-default attributes.
|
||||
func (r *xlsxRow) hasAttr() bool {
|
||||
return r.Spans != "" || r.S != 0 || r.CustomFormat || r.Ht != 0 ||
|
||||
return r.Spans != "" || r.S != 0 || r.CustomFormat || r.Ht != nil ||
|
||||
r.Hidden || r.CustomHeight || r.OutlineLevel != 0 || r.Collapsed ||
|
||||
r.ThickTop || r.ThickBot || r.Ph
|
||||
}
|
||||
|
|
4
sheet.go
4
sheet.go
|
@ -1844,10 +1844,10 @@ func prepareSheetXML(ws *xlsxWorksheet, col int, row int) {
|
|||
defer ws.Unlock()
|
||||
rowCount := len(ws.SheetData.Row)
|
||||
sizeHint := 0
|
||||
var ht float64
|
||||
var ht *float64
|
||||
var customHeight bool
|
||||
if ws.SheetFormatPr != nil && ws.SheetFormatPr.CustomHeight {
|
||||
ht = ws.SheetFormatPr.DefaultRowHeight
|
||||
ht = float64Ptr(ws.SheetFormatPr.DefaultRowHeight)
|
||||
customHeight = true
|
||||
}
|
||||
if rowCount > 0 {
|
||||
|
|
11
styles.go
11
styles.go
|
@ -1193,6 +1193,7 @@ func parseFormatStyleSet(style *Style) (*Style, error) {
|
|||
//
|
||||
// Style
|
||||
// ------------------
|
||||
// none
|
||||
// single
|
||||
// double
|
||||
//
|
||||
|
@ -2047,8 +2048,7 @@ func (f *File) NewStyle(style *Style) (int, error) {
|
|||
|
||||
applyAlignment, alignment := fs.Alignment != nil, newAlignment(fs)
|
||||
applyProtection, protection := fs.Protection != nil, newProtection(fs)
|
||||
cellXfsID = setCellXfs(s, fontID, numFmtID, fillID, borderID, applyAlignment, applyProtection, alignment, protection)
|
||||
return cellXfsID, nil
|
||||
return setCellXfs(s, fontID, numFmtID, fillID, borderID, applyAlignment, applyProtection, alignment, protection)
|
||||
}
|
||||
|
||||
var getXfIDFuncs = map[string]func(int, xlsxXf, *Style) bool{
|
||||
|
@ -2620,7 +2620,7 @@ func newBorders(style *Style) *xlsxBorder {
|
|||
|
||||
// setCellXfs provides a function to set describes all of the formatting for a
|
||||
// cell.
|
||||
func setCellXfs(style *xlsxStyleSheet, fontID, numFmtID, fillID, borderID int, applyAlignment, applyProtection bool, alignment *xlsxAlignment, protection *xlsxProtection) int {
|
||||
func setCellXfs(style *xlsxStyleSheet, fontID, numFmtID, fillID, borderID int, applyAlignment, applyProtection bool, alignment *xlsxAlignment, protection *xlsxProtection) (int, error) {
|
||||
var xf xlsxXf
|
||||
xf.FontID = intPtr(fontID)
|
||||
if fontID != 0 {
|
||||
|
@ -2638,6 +2638,9 @@ func setCellXfs(style *xlsxStyleSheet, fontID, numFmtID, fillID, borderID int, a
|
|||
if borderID != 0 {
|
||||
xf.ApplyBorder = boolPtr(true)
|
||||
}
|
||||
if len(style.CellXfs.Xf) == MaxCellStyles {
|
||||
return 0, ErrCellStyles
|
||||
}
|
||||
style.CellXfs.Count = len(style.CellXfs.Xf) + 1
|
||||
xf.Alignment = alignment
|
||||
if alignment != nil {
|
||||
|
@ -2650,7 +2653,7 @@ func setCellXfs(style *xlsxStyleSheet, fontID, numFmtID, fillID, borderID int, a
|
|||
xfID := 0
|
||||
xf.XfID = &xfID
|
||||
style.CellXfs.Xf = append(style.CellXfs.Xf, xf)
|
||||
return style.CellXfs.Count - 1
|
||||
return style.CellXfs.Count - 1, nil
|
||||
}
|
||||
|
||||
// GetCellStyle provides a function to get cell style index by given worksheet
|
||||
|
|
|
@ -325,6 +325,13 @@ func TestNewStyle(t *testing.T) {
|
|||
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
||||
_, err = f.NewStyle(&Style{NumFmt: 165})
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
|
||||
// Test create cell styles reach maximum
|
||||
f = NewFile()
|
||||
f.Styles.CellXfs.Xf = make([]xlsxXf, MaxCellStyles)
|
||||
f.Styles.CellXfs.Count = MaxCellStyles
|
||||
_, err = f.NewStyle(&Style{NumFmt: 0})
|
||||
assert.Equal(t, ErrCellStyles, err)
|
||||
}
|
||||
|
||||
func TestNewConditionalStyle(t *testing.T) {
|
||||
|
|
|
@ -108,7 +108,7 @@ const (
|
|||
|
||||
// Excel specifications and limits
|
||||
const (
|
||||
MaxCellStyles = 64000
|
||||
MaxCellStyles = 65430
|
||||
MaxColumns = 16384
|
||||
MaxColumnWidth = 255
|
||||
MaxFieldLength = 255
|
||||
|
|
|
@ -280,16 +280,16 @@ type xlsxCols struct {
|
|||
// xlsxCol directly maps the col (Column Width & Formatting). Defines column
|
||||
// width and column formatting for one or more columns of the worksheet.
|
||||
type xlsxCol struct {
|
||||
BestFit bool `xml:"bestFit,attr,omitempty"`
|
||||
Collapsed bool `xml:"collapsed,attr,omitempty"`
|
||||
CustomWidth bool `xml:"customWidth,attr,omitempty"`
|
||||
Hidden bool `xml:"hidden,attr,omitempty"`
|
||||
Max int `xml:"max,attr"`
|
||||
Min int `xml:"min,attr"`
|
||||
OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"`
|
||||
Phonetic bool `xml:"phonetic,attr,omitempty"`
|
||||
Style int `xml:"style,attr,omitempty"`
|
||||
Width float64 `xml:"width,attr,omitempty"`
|
||||
BestFit bool `xml:"bestFit,attr,omitempty"`
|
||||
Collapsed bool `xml:"collapsed,attr,omitempty"`
|
||||
CustomWidth bool `xml:"customWidth,attr,omitempty"`
|
||||
Hidden bool `xml:"hidden,attr,omitempty"`
|
||||
Max int `xml:"max,attr"`
|
||||
Min int `xml:"min,attr"`
|
||||
OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"`
|
||||
Phonetic bool `xml:"phonetic,attr,omitempty"`
|
||||
Style int `xml:"style,attr,omitempty"`
|
||||
Width *float64 `xml:"width,attr"`
|
||||
}
|
||||
|
||||
// xlsxDimension directly maps the dimension element in the namespace
|
||||
|
@ -316,19 +316,19 @@ type xlsxSheetData struct {
|
|||
// about an entire row of a worksheet, and contains all cell definitions for a
|
||||
// particular row in the worksheet.
|
||||
type xlsxRow struct {
|
||||
C []xlsxC `xml:"c"`
|
||||
R int `xml:"r,attr,omitempty"`
|
||||
Spans string `xml:"spans,attr,omitempty"`
|
||||
S int `xml:"s,attr,omitempty"`
|
||||
CustomFormat bool `xml:"customFormat,attr,omitempty"`
|
||||
Ht float64 `xml:"ht,attr,omitempty"`
|
||||
Hidden bool `xml:"hidden,attr,omitempty"`
|
||||
CustomHeight bool `xml:"customHeight,attr,omitempty"`
|
||||
OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"`
|
||||
Collapsed bool `xml:"collapsed,attr,omitempty"`
|
||||
ThickTop bool `xml:"thickTop,attr,omitempty"`
|
||||
ThickBot bool `xml:"thickBot,attr,omitempty"`
|
||||
Ph bool `xml:"ph,attr,omitempty"`
|
||||
C []xlsxC `xml:"c"`
|
||||
R int `xml:"r,attr,omitempty"`
|
||||
Spans string `xml:"spans,attr,omitempty"`
|
||||
S int `xml:"s,attr,omitempty"`
|
||||
CustomFormat bool `xml:"customFormat,attr,omitempty"`
|
||||
Ht *float64 `xml:"ht,attr"`
|
||||
Hidden bool `xml:"hidden,attr,omitempty"`
|
||||
CustomHeight bool `xml:"customHeight,attr,omitempty"`
|
||||
OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"`
|
||||
Collapsed bool `xml:"collapsed,attr,omitempty"`
|
||||
ThickTop bool `xml:"thickTop,attr,omitempty"`
|
||||
ThickBot bool `xml:"thickBot,attr,omitempty"`
|
||||
Ph bool `xml:"ph,attr,omitempty"`
|
||||
}
|
||||
|
||||
// xlsxSortState directly maps the sortState element. This collection
|
||||
|
|
Loading…
Reference in New Issue