Skip to content

Commit e014a8b

Browse files
Support update conditional formatting on inserting/deleting columns/rows (qax-os#1717)
Return error for unsupported conditional formatting rule types
1 parent 134865d commit e014a8b

File tree

6 files changed

+86
-12
lines changed

6 files changed

+86
-12
lines changed

adjust.go

+39-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ const (
3030
)
3131

3232
// adjustHelperFunc defines functions to adjust helper.
33-
var adjustHelperFunc = [7]func(*File, *xlsxWorksheet, string, adjustDirection, int, int, int) error{
33+
var adjustHelperFunc = [8]func(*File, *xlsxWorksheet, string, adjustDirection, int, int, int) error{
34+
func(f *File, ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
35+
return f.adjustConditionalFormats(ws, sheet, dir, num, offset, sheetID)
36+
},
3437
func(f *File, ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
3538
return f.adjustDefinedNames(ws, sheet, dir, num, offset, sheetID)
3639
},
@@ -231,30 +234,38 @@ func (f *File) adjustSingleRowFormulas(sheet, sheetN string, r *xlsxRow, num, of
231234
}
232235

233236
// adjustCellRef provides a function to adjust cell reference.
234-
func (f *File) adjustCellRef(ref string, dir adjustDirection, num, offset int) (string, error) {
237+
func (f *File) adjustCellRef(ref string, dir adjustDirection, num, offset int) (string, bool, error) {
235238
if !strings.Contains(ref, ":") {
236239
ref += ":" + ref
237240
}
241+
var delete bool
238242
coordinates, err := rangeRefToCoordinates(ref)
239243
if err != nil {
240-
return ref, err
244+
return ref, delete, err
241245
}
242246
if dir == columns {
247+
if offset < 0 && coordinates[0] == coordinates[2] {
248+
delete = true
249+
}
243250
if coordinates[0] >= num {
244251
coordinates[0] += offset
245252
}
246253
if coordinates[2] >= num {
247254
coordinates[2] += offset
248255
}
249256
} else {
257+
if offset < 0 && coordinates[1] == coordinates[3] {
258+
delete = true
259+
}
250260
if coordinates[1] >= num {
251261
coordinates[1] += offset
252262
}
253263
if coordinates[3] >= num {
254264
coordinates[3] += offset
255265
}
256266
}
257-
return f.coordinatesToRangeRef(coordinates)
267+
ref, err = f.coordinatesToRangeRef(coordinates)
268+
return ref, delete, err
258269
}
259270

260271
// 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
265276
}
266277
var err error
267278
if formula.Ref != "" && sheet == sheetN {
268-
if formula.Ref, err = f.adjustCellRef(formula.Ref, dir, num, offset); err != nil {
279+
if formula.Ref, _, err = f.adjustCellRef(formula.Ref, dir, num, offset); err != nil {
269280
return err
270281
}
271282
if si && formula.Si != nil {
@@ -770,6 +781,29 @@ func (f *File) adjustVolatileDeps(ws *xlsxWorksheet, sheet string, dir adjustDir
770781
return nil
771782
}
772783

784+
// adjustConditionalFormats updates the cell reference of the worksheet
785+
// conditional formatting when inserting or deleting rows or columns.
786+
func (f *File) adjustConditionalFormats(ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
787+
for i := 0; i < len(ws.ConditionalFormatting); i++ {
788+
cf := ws.ConditionalFormatting[i]
789+
if cf == nil {
790+
continue
791+
}
792+
ref, del, err := f.adjustCellRef(cf.SQRef, dir, num, offset)
793+
if err != nil {
794+
return err
795+
}
796+
if del {
797+
ws.ConditionalFormatting = append(ws.ConditionalFormatting[:i],
798+
ws.ConditionalFormatting[i+1:]...)
799+
i--
800+
continue
801+
}
802+
ws.ConditionalFormatting[i].SQRef = ref
803+
}
804+
return nil
805+
}
806+
773807
// adjustDrawings updates the starting anchor of the two cell anchor pictures
774808
// and charts object when inserting or deleting rows or columns.
775809
func (from *xlsxFrom) adjustDrawings(dir adjustDirection, num, offset int, editAs string) (bool, error) {

adjust_test.go

+31
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,37 @@ func TestAdjustVolatileDeps(t *testing.T) {
962962
f.volatileDepsWriter()
963963
}
964964

965+
func TestAdjustConditionalFormats(t *testing.T) {
966+
f := NewFile()
967+
assert.NoError(t, f.SetSheetRow("Sheet1", "B1", &[]interface{}{1, nil, 1, 1}))
968+
formatID, err := f.NewConditionalStyle(&Style{Font: &Font{Color: "09600B"}, Fill: Fill{Type: "pattern", Color: []string{"C7EECF"}, Pattern: 1}})
969+
assert.NoError(t, err)
970+
format := []ConditionalFormatOptions{
971+
{
972+
Type: "cell",
973+
Criteria: "greater than",
974+
Format: formatID,
975+
Value: "0",
976+
},
977+
}
978+
for _, ref := range []string{"B1", "D1:E1"} {
979+
assert.NoError(t, f.SetConditionalFormat("Sheet1", ref, format))
980+
}
981+
assert.NoError(t, f.RemoveCol("Sheet1", "B"))
982+
opts, err := f.GetConditionalFormats("Sheet1")
983+
assert.NoError(t, err)
984+
assert.Len(t, format, 1)
985+
assert.Equal(t, format, opts["C1:D1"])
986+
987+
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
988+
assert.True(t, ok)
989+
ws.(*xlsxWorksheet).ConditionalFormatting[0].SQRef = "-"
990+
assert.Equal(t, newCellNameToCoordinatesError("-", newInvalidCellNameError("-")), f.RemoveCol("Sheet1", "B"))
991+
992+
ws.(*xlsxWorksheet).ConditionalFormatting[0] = nil
993+
assert.NoError(t, f.RemoveCol("Sheet1", "B"))
994+
}
995+
965996
func TestAdjustDrawings(t *testing.T) {
966997
f := NewFile()
967998
// Test add pictures to sheet with positioning

datavalidation_test.go

-6
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,6 @@ func TestDataValidation(t *testing.T) {
6767
assert.NoError(t, err)
6868
assert.Len(t, dataValidations, 1)
6969

70-
dv = NewDataValidation(true)
71-
dv.Sqref = "A4:A5"
72-
assert.NoError(t, dv.SetRange("Sheet2!$A$2:$A$3", "", DataValidationTypeList, DataValidationOperatorBetween))
73-
dv.SetError(DataValidationErrorStyleStop, "error title", "error body")
74-
assert.NoError(t, f.AddDataValidation("Sheet2", dv))
75-
7670
dv = NewDataValidation(true)
7771
dv.Sqref = "A5:B6"
7872
for _, listValid := range [][]string{

excelize_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1223,7 +1223,7 @@ func TestConditionalFormat(t *testing.T) {
12231223
},
12241224
))
12251225
// Set conditional format with illegal criteria type
1226-
assert.NoError(t, f.SetConditionalFormat(sheet1, "K1:K10",
1226+
assert.Equal(t, ErrParameterInvalid, f.SetConditionalFormat(sheet1, "K1:K10",
12271227
[]ConditionalFormatOptions{
12281228
{
12291229
Type: "data_bar",

styles.go

+2
Original file line numberDiff line numberDiff line change
@@ -2664,8 +2664,10 @@ func (f *File) SetConditionalFormat(sheet, rangeRef string, opts []ConditionalFo
26642664
f.addSheetNameSpace(sheet, NameSpaceSpreadSheetX14)
26652665
}
26662666
cfRule = append(cfRule, rule)
2667+
continue
26672668
}
26682669
}
2670+
return ErrParameterInvalid
26692671
}
26702672
}
26712673

styles_test.go

+13
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,19 @@ func TestSetConditionalFormat(t *testing.T) {
191191
assert.EqualError(t, f.SetConditionalFormat("Sheet1", "A1:A2", condFmts), "XML syntax error on line 1: element <conditionalFormattings> closed by </conditionalFormatting>")
192192
// Test creating a conditional format with invalid icon set style
193193
assert.EqualError(t, f.SetConditionalFormat("Sheet1", "A1:A2", []ConditionalFormatOptions{{Type: "icon_set", IconStyle: "unknown"}}), ErrParameterInvalid.Error())
194+
// Test unsupported conditional formatting rule types
195+
for _, val := range []string{
196+
"date",
197+
"time",
198+
"text",
199+
"time_period",
200+
"blanks",
201+
"no_blanks",
202+
"errors",
203+
"no_errors",
204+
} {
205+
assert.Equal(t, ErrParameterInvalid, f.SetConditionalFormat("Sheet1", "A1", []ConditionalFormatOptions{{Type: val}}))
206+
}
194207
}
195208

196209
func TestGetConditionalFormats(t *testing.T) {

0 commit comments

Comments
 (0)