Support update conditional formatting on inserting/deleting columns/rows (#1717)
Return error for unsupported conditional formatting rule types
This commit is contained in:
parent
134865d9d2
commit
e014a8bb23
44
adjust.go
44
adjust.go
|
@ -30,7 +30,10 @@ const (
|
|||
)
|
||||
|
||||
// adjustHelperFunc defines functions to adjust helper.
|
||||
var adjustHelperFunc = [7]func(*File, *xlsxWorksheet, string, adjustDirection, int, int, int) error{
|
||||
var adjustHelperFunc = [8]func(*File, *xlsxWorksheet, string, adjustDirection, int, int, int) error{
|
||||
func(f *File, ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
|
||||
return f.adjustConditionalFormats(ws, sheet, dir, num, offset, sheetID)
|
||||
},
|
||||
func(f *File, ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
|
||||
return f.adjustDefinedNames(ws, sheet, dir, num, offset, sheetID)
|
||||
},
|
||||
|
@ -231,15 +234,19 @@ func (f *File) adjustSingleRowFormulas(sheet, sheetN string, r *xlsxRow, num, of
|
|||
}
|
||||
|
||||
// adjustCellRef provides a function to adjust cell reference.
|
||||
func (f *File) adjustCellRef(ref string, dir adjustDirection, num, offset int) (string, error) {
|
||||
func (f *File) adjustCellRef(ref string, dir adjustDirection, num, offset int) (string, bool, error) {
|
||||
if !strings.Contains(ref, ":") {
|
||||
ref += ":" + ref
|
||||
}
|
||||
var delete bool
|
||||
coordinates, err := rangeRefToCoordinates(ref)
|
||||
if err != nil {
|
||||
return ref, err
|
||||
return ref, delete, err
|
||||
}
|
||||
if dir == columns {
|
||||
if offset < 0 && coordinates[0] == coordinates[2] {
|
||||
delete = true
|
||||
}
|
||||
if coordinates[0] >= num {
|
||||
coordinates[0] += offset
|
||||
}
|
||||
|
@ -247,6 +254,9 @@ func (f *File) adjustCellRef(ref string, dir adjustDirection, num, offset int) (
|
|||
coordinates[2] += offset
|
||||
}
|
||||
} else {
|
||||
if offset < 0 && coordinates[1] == coordinates[3] {
|
||||
delete = true
|
||||
}
|
||||
if coordinates[1] >= num {
|
||||
coordinates[1] += offset
|
||||
}
|
||||
|
@ -254,7 +264,8 @@ func (f *File) adjustCellRef(ref string, dir adjustDirection, num, offset int) (
|
|||
coordinates[3] += offset
|
||||
}
|
||||
}
|
||||
return f.coordinatesToRangeRef(coordinates)
|
||||
ref, err = f.coordinatesToRangeRef(coordinates)
|
||||
return ref, delete, err
|
||||
}
|
||||
|
||||
// adjustFormula provides a function to adjust formula reference and shared
|
||||
|
@ -265,7 +276,7 @@ func (f *File) adjustFormula(sheet, sheetN string, formula *xlsxF, dir adjustDir
|
|||
}
|
||||
var err error
|
||||
if formula.Ref != "" && sheet == sheetN {
|
||||
if formula.Ref, err = f.adjustCellRef(formula.Ref, dir, num, offset); err != nil {
|
||||
if formula.Ref, _, err = f.adjustCellRef(formula.Ref, dir, num, offset); err != nil {
|
||||
return err
|
||||
}
|
||||
if si && formula.Si != nil {
|
||||
|
@ -770,6 +781,29 @@ func (f *File) adjustVolatileDeps(ws *xlsxWorksheet, sheet string, dir adjustDir
|
|||
return nil
|
||||
}
|
||||
|
||||
// adjustConditionalFormats updates the cell reference of the worksheet
|
||||
// conditional formatting when inserting or deleting rows or columns.
|
||||
func (f *File) adjustConditionalFormats(ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
|
||||
for i := 0; i < len(ws.ConditionalFormatting); i++ {
|
||||
cf := ws.ConditionalFormatting[i]
|
||||
if cf == nil {
|
||||
continue
|
||||
}
|
||||
ref, del, err := f.adjustCellRef(cf.SQRef, dir, num, offset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if del {
|
||||
ws.ConditionalFormatting = append(ws.ConditionalFormatting[:i],
|
||||
ws.ConditionalFormatting[i+1:]...)
|
||||
i--
|
||||
continue
|
||||
}
|
||||
ws.ConditionalFormatting[i].SQRef = ref
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// adjustDrawings updates the starting anchor of the two cell anchor pictures
|
||||
// and charts object when inserting or deleting rows or columns.
|
||||
func (from *xlsxFrom) adjustDrawings(dir adjustDirection, num, offset int, editAs string) (bool, error) {
|
||||
|
|
|
@ -962,6 +962,37 @@ func TestAdjustVolatileDeps(t *testing.T) {
|
|||
f.volatileDepsWriter()
|
||||
}
|
||||
|
||||
func TestAdjustConditionalFormats(t *testing.T) {
|
||||
f := NewFile()
|
||||
assert.NoError(t, f.SetSheetRow("Sheet1", "B1", &[]interface{}{1, nil, 1, 1}))
|
||||
formatID, err := f.NewConditionalStyle(&Style{Font: &Font{Color: "09600B"}, Fill: Fill{Type: "pattern", Color: []string{"C7EECF"}, Pattern: 1}})
|
||||
assert.NoError(t, err)
|
||||
format := []ConditionalFormatOptions{
|
||||
{
|
||||
Type: "cell",
|
||||
Criteria: "greater than",
|
||||
Format: formatID,
|
||||
Value: "0",
|
||||
},
|
||||
}
|
||||
for _, ref := range []string{"B1", "D1:E1"} {
|
||||
assert.NoError(t, f.SetConditionalFormat("Sheet1", ref, format))
|
||||
}
|
||||
assert.NoError(t, f.RemoveCol("Sheet1", "B"))
|
||||
opts, err := f.GetConditionalFormats("Sheet1")
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, format, 1)
|
||||
assert.Equal(t, format, opts["C1:D1"])
|
||||
|
||||
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
|
||||
assert.True(t, ok)
|
||||
ws.(*xlsxWorksheet).ConditionalFormatting[0].SQRef = "-"
|
||||
assert.Equal(t, newCellNameToCoordinatesError("-", newInvalidCellNameError("-")), f.RemoveCol("Sheet1", "B"))
|
||||
|
||||
ws.(*xlsxWorksheet).ConditionalFormatting[0] = nil
|
||||
assert.NoError(t, f.RemoveCol("Sheet1", "B"))
|
||||
}
|
||||
|
||||
func TestAdjustDrawings(t *testing.T) {
|
||||
f := NewFile()
|
||||
// Test add pictures to sheet with positioning
|
||||
|
|
|
@ -67,12 +67,6 @@ func TestDataValidation(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Len(t, dataValidations, 1)
|
||||
|
||||
dv = NewDataValidation(true)
|
||||
dv.Sqref = "A4:A5"
|
||||
assert.NoError(t, dv.SetRange("Sheet2!$A$2:$A$3", "", DataValidationTypeList, DataValidationOperatorBetween))
|
||||
dv.SetError(DataValidationErrorStyleStop, "error title", "error body")
|
||||
assert.NoError(t, f.AddDataValidation("Sheet2", dv))
|
||||
|
||||
dv = NewDataValidation(true)
|
||||
dv.Sqref = "A5:B6"
|
||||
for _, listValid := range [][]string{
|
||||
|
|
|
@ -1223,7 +1223,7 @@ func TestConditionalFormat(t *testing.T) {
|
|||
},
|
||||
))
|
||||
// Set conditional format with illegal criteria type
|
||||
assert.NoError(t, f.SetConditionalFormat(sheet1, "K1:K10",
|
||||
assert.Equal(t, ErrParameterInvalid, f.SetConditionalFormat(sheet1, "K1:K10",
|
||||
[]ConditionalFormatOptions{
|
||||
{
|
||||
Type: "data_bar",
|
||||
|
|
|
@ -2664,8 +2664,10 @@ func (f *File) SetConditionalFormat(sheet, rangeRef string, opts []ConditionalFo
|
|||
f.addSheetNameSpace(sheet, NameSpaceSpreadSheetX14)
|
||||
}
|
||||
cfRule = append(cfRule, rule)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return ErrParameterInvalid
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -191,6 +191,19 @@ func TestSetConditionalFormat(t *testing.T) {
|
|||
assert.EqualError(t, f.SetConditionalFormat("Sheet1", "A1:A2", condFmts), "XML syntax error on line 1: element <conditionalFormattings> closed by </conditionalFormatting>")
|
||||
// Test creating a conditional format with invalid icon set style
|
||||
assert.EqualError(t, f.SetConditionalFormat("Sheet1", "A1:A2", []ConditionalFormatOptions{{Type: "icon_set", IconStyle: "unknown"}}), ErrParameterInvalid.Error())
|
||||
// Test unsupported conditional formatting rule types
|
||||
for _, val := range []string{
|
||||
"date",
|
||||
"time",
|
||||
"text",
|
||||
"time_period",
|
||||
"blanks",
|
||||
"no_blanks",
|
||||
"errors",
|
||||
"no_errors",
|
||||
} {
|
||||
assert.Equal(t, ErrParameterInvalid, f.SetConditionalFormat("Sheet1", "A1", []ConditionalFormatOptions{{Type: val}}))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConditionalFormats(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue