Skip to content

Commit

Permalink
This closes #1129, make cell support inheritance columns/rows style
Browse files Browse the repository at this point in the history
Correct cells style in merge range
Fix incorrect style ID returned on getting cell style in some cases
Unit test updated and simplified code
  • Loading branch information
xuri committed Jan 27, 2022
1 parent 3ee3c38 commit 156bf6d
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 40 deletions.
52 changes: 29 additions & 23 deletions cell.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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{}
Expand Down Expand Up @@ -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
}

Expand All @@ -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
Expand All @@ -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)
Expand Down
11 changes: 5 additions & 6 deletions col.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}

Expand All @@ -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
}

Expand Down Expand Up @@ -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.
Expand Down
20 changes: 13 additions & 7 deletions col_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")))
}

Expand Down
1 change: 1 addition & 0 deletions excelize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 5 additions & 2 deletions merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

package excelize

import "strings"
import (
"strings"
)

// Rect gets merged cell rectangle coordinates sequence.
func (mc *xlsxMergeCell) Rect() ([]int, error) {
Expand Down Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions rows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")))
}

Expand Down
4 changes: 2 additions & 2 deletions styles.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 156bf6d

Please sign in to comment.