This closes #1129, make cell support inheritance columns/rows style

Correct cells style in merge range
Fix incorrect style ID returned on getting cell style in some cases
Unit test updated and simplified code
This commit is contained in:
xuri 2022-01-27 22:37:32 +08:00
parent 3ee3c38f9c
commit 156bf6d16e
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
7 changed files with 58 additions and 40 deletions

52
cell.go
View File

@ -200,12 +200,12 @@ func (f *File) setCellTimeFunc(sheet, axis string, value time.Time) error {
if err != nil {
return err
}
cellData, col, _, err := f.prepareCell(ws, sheet, axis)
cellData, col, row, err := f.prepareCell(ws, sheet, axis)
if err != nil {
return err
}
ws.Lock()
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
ws.Unlock()
var isNum bool
@ -214,10 +214,7 @@ func (f *File) setCellTimeFunc(sheet, axis string, value time.Time) error {
return err
}
if isNum {
err = f.setDefaultTimeStyle(sheet, axis, 22)
if err != nil {
return err
}
_ = f.setDefaultTimeStyle(sheet, axis, 22)
}
return err
}
@ -254,13 +251,13 @@ func (f *File) SetCellInt(sheet, axis string, value int) error {
if err != nil {
return err
}
cellData, col, _, err := f.prepareCell(ws, sheet, axis)
cellData, col, row, err := f.prepareCell(ws, sheet, axis)
if err != nil {
return err
}
ws.Lock()
defer ws.Unlock()
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
cellData.T, cellData.V = setCellInt(value)
return err
}
@ -279,13 +276,13 @@ func (f *File) SetCellBool(sheet, axis string, value bool) error {
if err != nil {
return err
}
cellData, col, _, err := f.prepareCell(ws, sheet, axis)
cellData, col, row, err := f.prepareCell(ws, sheet, axis)
if err != nil {
return err
}
ws.Lock()
defer ws.Unlock()
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
cellData.T, cellData.V = setCellBool(value)
return err
}
@ -316,13 +313,13 @@ func (f *File) SetCellFloat(sheet, axis string, value float64, prec, bitSize int
if err != nil {
return err
}
cellData, col, _, err := f.prepareCell(ws, sheet, axis)
cellData, col, row, err := f.prepareCell(ws, sheet, axis)
if err != nil {
return err
}
ws.Lock()
defer ws.Unlock()
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
cellData.T, cellData.V = setCellFloat(value, prec, bitSize)
return err
}
@ -341,13 +338,13 @@ func (f *File) SetCellStr(sheet, axis, value string) error {
if err != nil {
return err
}
cellData, col, _, err := f.prepareCell(ws, sheet, axis)
cellData, col, row, err := f.prepareCell(ws, sheet, axis)
if err != nil {
return err
}
ws.Lock()
defer ws.Unlock()
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
cellData.T, cellData.V, err = f.setCellString(value)
return err
}
@ -439,13 +436,13 @@ func (f *File) SetCellDefault(sheet, axis, value string) error {
if err != nil {
return err
}
cellData, col, _, err := f.prepareCell(ws, sheet, axis)
cellData, col, row, err := f.prepareCell(ws, sheet, axis)
if err != nil {
return err
}
ws.Lock()
defer ws.Unlock()
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
cellData.T, cellData.V = setCellDefault(value)
return err
}
@ -937,14 +934,14 @@ func (f *File) SetCellRichText(sheet, cell string, runs []RichTextRun) error {
if err != nil {
return err
}
cellData, col, _, err := f.prepareCell(ws, sheet, cell)
cellData, col, row, err := f.prepareCell(ws, sheet, cell)
if err != nil {
return err
}
if err := f.sharedStringsLoader(); err != nil {
return err
}
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
si := xlsxSI{}
sst := f.sharedStringsReader()
textRuns := []xlsxR{}
@ -1133,14 +1130,19 @@ func isTimeNumFmt(format string) bool {
// prepareCellStyle provides a function to prepare style index of cell in
// worksheet by given column index and style index.
func (f *File) prepareCellStyle(ws *xlsxWorksheet, col, style int) int {
func (f *File) prepareCellStyle(ws *xlsxWorksheet, col, row, style int) int {
if ws.Cols != nil && style == 0 {
for _, c := range ws.Cols.Col {
if c.Min <= col && col <= c.Max {
style = c.Style
if c.Min <= col && col <= c.Max && c.Style != 0 {
return c.Style
}
}
}
for rowIdx := range ws.SheetData.Row {
if styleID := ws.SheetData.Row[rowIdx].S; style == 0 && styleID != 0 {
return styleID
}
}
return style
}
@ -1150,6 +1152,11 @@ func (f *File) mergeCellsParser(ws *xlsxWorksheet, axis string) (string, error)
axis = strings.ToUpper(axis)
if ws.MergeCells != nil {
for i := 0; i < len(ws.MergeCells.Cells); i++ {
if ws.MergeCells.Cells[i] == nil {
ws.MergeCells.Cells = append(ws.MergeCells.Cells[:i], ws.MergeCells.Cells[i+1:]...)
i--
continue
}
ok, err := f.checkCellInArea(axis, ws.MergeCells.Cells[i].Ref)
if err != nil {
return axis, err
@ -1170,8 +1177,7 @@ func (f *File) checkCellInArea(cell, area string) (bool, error) {
return false, err
}
rng := strings.Split(area, ":")
if len(rng) != 2 {
if rng := strings.Split(area, ":"); len(rng) != 2 {
return false, err
}
coordinates, err := areaRefToCoordinates(area)

11
col.go
View File

@ -592,9 +592,8 @@ func (f *File) positionObjectPixels(sheet string, col, row, x1, y1, width, heigh
row++
}
// Initialise end cell to the same as the start cell.
colEnd := col
rowEnd := row
// Initialized end cell to the same as the start cell.
colEnd, rowEnd := col, row
width += x1
height += y1
@ -632,7 +631,7 @@ func (f *File) getColWidth(sheet string, col int) int {
return int(convertColWidthToPixels(width))
}
}
// Optimisation for when the column widths haven't changed.
// Optimization for when the column widths haven't changed.
return int(defaultColWidthPixels)
}
@ -658,7 +657,7 @@ func (f *File) GetColWidth(sheet, col string) (float64, error) {
return width, err
}
}
// Optimisation for when the column widths haven't changed.
// Optimization for when the column widths haven't changed.
return defaultColWidth, err
}
@ -707,7 +706,7 @@ func (f *File) RemoveCol(sheet, col string) error {
return f.adjustHelper(sheet, columns, num, -1)
}
// convertColWidthToPixels provieds function to convert the width of a cell
// convertColWidthToPixels provides function to convert the width of a cell
// from user's units to pixels. Excel rounds the column width to the nearest
// pixel. If the width hasn't been set by the user we use the default value.
// If the column is hidden it has a value of zero.

View File

@ -289,18 +289,24 @@ func TestOutlineLevel(t *testing.T) {
func TestSetColStyle(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetCellValue("Sheet1", "B2", "Hello"))
style, err := f.NewStyle(`{"fill":{"type":"pattern","color":["#94d3a2"],"pattern":1}}`)
styleID, err := f.NewStyle(`{"fill":{"type":"pattern","color":["#94d3a2"],"pattern":1}}`)
assert.NoError(t, err)
// Test set column style on not exists worksheet.
assert.EqualError(t, f.SetColStyle("SheetN", "E", style), "sheet SheetN is not exist")
assert.EqualError(t, f.SetColStyle("SheetN", "E", styleID), "sheet SheetN is not exist")
// Test set column style with illegal cell coordinates.
assert.EqualError(t, f.SetColStyle("Sheet1", "*", style), newInvalidColumnNameError("*").Error())
assert.EqualError(t, f.SetColStyle("Sheet1", "A:*", style), newInvalidColumnNameError("*").Error())
assert.EqualError(t, f.SetColStyle("Sheet1", "*", styleID), newInvalidColumnNameError("*").Error())
assert.EqualError(t, f.SetColStyle("Sheet1", "A:*", styleID), newInvalidColumnNameError("*").Error())
assert.NoError(t, f.SetColStyle("Sheet1", "B", style))
assert.NoError(t, f.SetColStyle("Sheet1", "B", styleID))
// Test set column style with already exists column with style.
assert.NoError(t, f.SetColStyle("Sheet1", "B", style))
assert.NoError(t, f.SetColStyle("Sheet1", "D:C", style))
assert.NoError(t, f.SetColStyle("Sheet1", "B", styleID))
assert.NoError(t, f.SetColStyle("Sheet1", "D:C", styleID))
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).SheetData.Row[1].C[2].S = 0
cellStyleID, err := f.GetCellStyle("Sheet1", "C2")
assert.NoError(t, err)
assert.Equal(t, styleID, cellStyleID)
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetColStyle.xlsx")))
}

View File

@ -147,6 +147,7 @@ func TestOpenFile(t *testing.T) {
assert.NoError(t, f.SetCellValue("Sheet2", "G4", time.Now()))
assert.NoError(t, f.SetCellValue("Sheet2", "G4", time.Now().UTC()))
assert.EqualError(t, f.SetCellValue("SheetN", "A1", time.Now()), "sheet SheetN is not exist")
// 02:46:40
assert.NoError(t, f.SetCellValue("Sheet2", "G5", time.Duration(1e13)))
// Test completion column.

View File

@ -11,7 +11,9 @@
package excelize
import "strings"
import (
"strings"
)
// Rect gets merged cell rectangle coordinates sequence.
func (mc *xlsxMergeCell) Rect() ([]int, error) {
@ -68,7 +70,8 @@ func (f *File) MergeCell(sheet, hCell, vCell string) error {
ws.MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: ref, rect: rect}}}
}
ws.MergeCells.Count = len(ws.MergeCells.Cells)
return err
styleID, _ := f.GetCellStyle(sheet, hCell)
return f.SetCellStyle(sheet, hCell, vCell, styleID)
}
// UnmergeCell provides a function to unmerge a given coordinate area.

View File

@ -921,6 +921,9 @@ func TestSetRowStyle(t *testing.T) {
assert.EqualError(t, f.SetRowStyle("Sheet1", 1, 1, -1), newInvalidStyleID(-1).Error())
assert.EqualError(t, f.SetRowStyle("SheetN", 1, 1, styleID), "sheet SheetN is not exist")
assert.NoError(t, f.SetRowStyle("Sheet1", 10, 1, styleID))
cellStyleID, err := f.GetCellStyle("Sheet1", "B2")
assert.NoError(t, err)
assert.Equal(t, styleID, cellStyleID)
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetRowStyle.xlsx")))
}

View File

@ -2613,11 +2613,11 @@ func (f *File) GetCellStyle(sheet, axis string) (int, error) {
if err != nil {
return 0, err
}
cellData, col, _, err := f.prepareCell(ws, sheet, axis)
cellData, col, row, err := f.prepareCell(ws, sheet, axis)
if err != nil {
return 0, err
}
return f.prepareCellStyle(ws, col, cellData.S), err
return f.prepareCellStyle(ws, col, row, cellData.S), err
}
// SetCellStyle provides a function to add style attribute for cells by given