OSDN Git Service

Support to adjust formula cross worksheet on inserting/deleting columns/rows (#1705)
authorrjtee <62975067+TeeRenJing@users.noreply.github.com>
Tue, 31 Oct 2023 16:52:18 +0000 (00:52 +0800)
committerGitHub <noreply@github.com>
Tue, 31 Oct 2023 16:52:18 +0000 (00:52 +0800)
adjust.go
adjust_test.go
rows.go

index d8defce..608e249 100644 (file)
--- a/adjust.go
+++ b/adjust.go
@@ -17,6 +17,7 @@ import (
        "io"
        "strconv"
        "strings"
+       "unicode"
 
        "github.com/xuri/efp"
 )
@@ -128,15 +129,24 @@ func (f *File) adjustColDimensions(sheet string, ws *xlsxWorksheet, col, offset
                        }
                }
        }
-       for rowIdx := range ws.SheetData.Row {
-               for colIdx, v := range ws.SheetData.Row[rowIdx].C {
-                       if cellCol, cellRow, _ := CellNameToCoordinates(v.R); col <= cellCol {
-                               if newCol := cellCol + offset; newCol > 0 {
-                                       ws.SheetData.Row[rowIdx].C[colIdx].R, _ = CoordinatesToCellName(newCol, cellRow)
-                               }
+       for _, sheetN := range f.GetSheetList() {
+               worksheet, err := f.workSheetReader(sheetN)
+               if err != nil {
+                       if err.Error() == newNotWorksheetError(sheetN).Error() {
+                               continue
                        }
-                       if err := f.adjustFormula(sheet, ws.SheetData.Row[rowIdx].C[colIdx].F, columns, col, offset, false); err != nil {
-                               return err
+                       return err
+               }
+               for rowIdx := range worksheet.SheetData.Row {
+                       for colIdx, v := range worksheet.SheetData.Row[rowIdx].C {
+                               if cellCol, cellRow, _ := CellNameToCoordinates(v.R); sheetN == sheet && col <= cellCol {
+                                       if newCol := cellCol + offset; newCol > 0 {
+                                               worksheet.SheetData.Row[rowIdx].C[colIdx].R, _ = CoordinatesToCellName(newCol, cellRow)
+                                       }
+                               }
+                               if err := f.adjustFormula(sheet, sheetN, worksheet.SheetData.Row[rowIdx].C[colIdx].F, columns, col, offset, false); err != nil {
+                                       return err
+                               }
                        }
                }
        }
@@ -146,6 +156,25 @@ func (f *File) adjustColDimensions(sheet string, ws *xlsxWorksheet, col, offset
 // adjustRowDimensions provides a function to update row dimensions when
 // inserting or deleting rows or columns.
 func (f *File) adjustRowDimensions(sheet string, ws *xlsxWorksheet, row, offset int) error {
+       for _, sheetN := range f.GetSheetList() {
+               if sheetN == sheet {
+                       continue
+               }
+               worksheet, err := f.workSheetReader(sheetN)
+               if err != nil {
+                       if err.Error() == newNotWorksheetError(sheetN).Error() {
+                               continue
+                       }
+                       return err
+               }
+               numOfRows := len(worksheet.SheetData.Row)
+               for i := 0; i < numOfRows; i++ {
+                       r := &worksheet.SheetData.Row[i]
+                       if err = f.adjustSingleRowFormulas(sheet, sheetN, r, row, offset, false); err != nil {
+                               return err
+                       }
+               }
+       }
        totalRows := len(ws.SheetData.Row)
        if totalRows == 0 {
                return nil
@@ -160,7 +189,7 @@ func (f *File) adjustRowDimensions(sheet string, ws *xlsxWorksheet, row, offset
                if newRow := r.R + offset; r.R >= row && newRow > 0 {
                        r.adjustSingleRowDimensions(offset)
                }
-               if err := f.adjustSingleRowFormulas(sheet, r, row, offset, false); err != nil {
+               if err := f.adjustSingleRowFormulas(sheet, sheet, r, row, offset, false); err != nil {
                        return err
                }
        }
@@ -177,9 +206,9 @@ func (r *xlsxRow) adjustSingleRowDimensions(offset int) {
 }
 
 // adjustSingleRowFormulas provides a function to adjust single row formulas.
-func (f *File) adjustSingleRowFormulas(sheet string, r *xlsxRow, num, offset int, si bool) error {
+func (f *File) adjustSingleRowFormulas(sheet, sheetN string, r *xlsxRow, num, offset int, si bool) error {
        for _, col := range r.C {
-               if err := f.adjustFormula(sheet, col.F, rows, num, offset, si); err != nil {
+               if err := f.adjustFormula(sheet, sheetN, col.F, rows, num, offset, si); err != nil {
                        return err
                }
        }
@@ -215,12 +244,12 @@ func (f *File) adjustCellRef(ref string, dir adjustDirection, num, offset int) (
 
 // adjustFormula provides a function to adjust formula reference and shared
 // formula reference.
-func (f *File) adjustFormula(sheet string, formula *xlsxF, dir adjustDirection, num, offset int, si bool) error {
+func (f *File) adjustFormula(sheet, sheetN string, formula *xlsxF, dir adjustDirection, num, offset int, si bool) error {
        if formula == nil {
                return nil
        }
        var err error
-       if formula.Ref != "" {
+       if formula.Ref != "" && sheet == sheetN {
                if formula.Ref, err = f.adjustCellRef(formula.Ref, dir, num, offset); err != nil {
                        return err
                }
@@ -229,7 +258,7 @@ func (f *File) adjustFormula(sheet string, formula *xlsxF, dir adjustDirection,
                }
        }
        if formula.Content != "" {
-               if formula.Content, err = f.adjustFormulaRef(sheet, formula.Content, dir, num, offset); err != nil {
+               if formula.Content, err = f.adjustFormulaRef(sheet, sheetN, formula.Content, dir, num, offset); err != nil {
                        return err
                }
        }
@@ -246,11 +275,19 @@ func isFunctionStart(token efp.Token) bool {
        return token.TType == efp.TokenTypeFunction && token.TSubType == efp.TokenSubTypeStart
 }
 
+// escapeSheetName enclose sheet name in single quotation marks if the giving
+// worksheet name includes spaces or non-alphabetical characters.
+func escapeSheetName(name string) string {
+       if strings.IndexFunc(name, func(r rune) bool {
+               return !unicode.IsLetter(r) && !unicode.IsNumber(r)
+       }) != -1 {
+               return string(efp.QuoteSingle) + name + string(efp.QuoteSingle)
+       }
+       return name
+}
+
 // adjustFormulaColumnName adjust column name in the formula reference.
 func adjustFormulaColumnName(name string, dir adjustDirection, num, offset int) (string, error) {
-       if name == "" {
-               return name, nil
-       }
        col, err := ColumnNameToNumber(name)
        if err != nil {
                return name, err
@@ -264,9 +301,6 @@ func adjustFormulaColumnName(name string, dir adjustDirection, num, offset int)
 
 // adjustFormulaRowNumber adjust row number in the formula reference.
 func adjustFormulaRowNumber(name string, dir adjustDirection, num, offset int) (string, error) {
-       if name == "" {
-               return name, nil
-       }
        row, _ := strconv.Atoi(name)
        if dir == rows && row >= num {
                row += offset
@@ -300,16 +334,19 @@ func adjustFormulaOperandRef(row, col, operand string, dir adjustDirection, num
 }
 
 // adjustFormulaOperand adjust range operand tokens for the formula.
-func (f *File) adjustFormulaOperand(token efp.Token, dir adjustDirection, num int, offset int) (string, error) {
+func (f *File) adjustFormulaOperand(sheet, sheetN string, token efp.Token, dir adjustDirection, num int, offset int) (string, error) {
        var (
-               err                      error
-               sheet, col, row, operand string
-               cell                     = token.TValue
-               tokens                   = strings.Split(token.TValue, "!")
+               err                          error
+               sheetName, col, row, operand string
+               cell                         = token.TValue
+               tokens                       = strings.Split(token.TValue, "!")
        )
        if len(tokens) == 2 { // have a worksheet
-               sheet, cell = tokens[0], tokens[1]
-               operand = string(efp.QuoteSingle) + sheet + string(efp.QuoteSingle) + "!"
+               sheetName, cell = tokens[0], tokens[1]
+               operand = escapeSheetName(sheetName) + "!"
+       }
+       if sheet != sheetN && sheet != sheetName {
+               return operand + cell, err
        }
        for _, r := range cell {
                if ('A' <= r && r <= 'Z') || ('a' <= r && r <= 'z') {
@@ -333,19 +370,13 @@ func (f *File) adjustFormulaOperand(token efp.Token, dir adjustDirection, num in
                }
                operand += string(r)
        }
-       name, err := adjustFormulaColumnName(col, dir, num, offset)
-       if err != nil {
-               return operand, err
-       }
-       operand += name
-       name, err = adjustFormulaRowNumber(row, dir, num, offset)
-       operand += name
+       _, _, operand, err = adjustFormulaOperandRef(row, col, operand, dir, num, offset)
        return operand, err
 }
 
 // adjustFormulaRef returns adjusted formula by giving adjusting direction and
 // the base number of column or row, and offset.
-func (f *File) adjustFormulaRef(sheet, formula string, dir adjustDirection, num, offset int) (string, error) {
+func (f *File) adjustFormulaRef(sheet, sheetN, formula string, dir adjustDirection, num, offset int) (string, error) {
        var (
                val          string
                definedNames []string
@@ -366,7 +397,7 @@ func (f *File) adjustFormulaRef(sheet, formula string, dir adjustDirection, num,
                                val += token.TValue
                                continue
                        }
-                       operand, err := f.adjustFormulaOperand(token, dir, num, offset)
+                       operand, err := f.adjustFormulaOperand(sheet, sheetN, token, dir, num, offset)
                        if err != nil {
                                return val, err
                        }
@@ -382,7 +413,7 @@ func (f *File) adjustFormulaRef(sheet, formula string, dir adjustDirection, num,
                        continue
                }
                if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeText {
-                       val += string(efp.QuoteDouble) + token.TValue + string(efp.QuoteDouble)
+                       val += string(efp.QuoteDouble) + strings.ReplaceAll(token.TValue, "\"", "\"\"") + string(efp.QuoteDouble)
                        continue
                }
                val += token.TValue
@@ -420,7 +451,7 @@ func (f *File) adjustHyperlinks(ws *xlsxWorksheet, sheet string, dir adjustDirec
        }
        for i := range ws.Hyperlinks.Hyperlink {
                link := &ws.Hyperlinks.Hyperlink[i] // get reference
-               link.Ref, _ = f.adjustFormulaRef(sheet, link.Ref, dir, num, offset)
+               link.Ref, _ = f.adjustFormulaRef(sheet, sheet, link.Ref, dir, num, offset)
        }
 }
 
index 2356b82..985d759 100644 (file)
@@ -457,6 +457,12 @@ func TestAdjustColDimensions(t *testing.T) {
        assert.NoError(t, err)
        assert.NoError(t, f.SetCellFormula("Sheet1", "C3", "A1+B1"))
        assert.Equal(t, ErrColumnNumber, f.adjustColDimensions("Sheet1", ws, 1, MaxColumns))
+
+       _, err = f.NewSheet("Sheet2")
+       assert.NoError(t, err)
+       f.Sheet.Delete("xl/worksheets/sheet2.xml")
+       f.Pkg.Store("xl/worksheets/sheet2.xml", MacintoshCyrillicCharset)
+       assert.EqualError(t, f.adjustColDimensions("Sheet2", ws, 2, 1), "XML syntax error on line 1: invalid UTF-8")
 }
 
 func TestAdjustRowDimensions(t *testing.T) {
@@ -465,6 +471,20 @@ func TestAdjustRowDimensions(t *testing.T) {
        assert.NoError(t, err)
        assert.NoError(t, f.SetCellFormula("Sheet1", "C3", "A1+B1"))
        assert.Equal(t, ErrMaxRows, f.adjustRowDimensions("Sheet1", ws, 1, TotalRows))
+
+       _, err = f.NewSheet("Sheet2")
+       assert.NoError(t, err)
+       f.Sheet.Delete("xl/worksheets/sheet2.xml")
+       f.Pkg.Store("xl/worksheets/sheet2.xml", MacintoshCyrillicCharset)
+       assert.EqualError(t, f.adjustRowDimensions("Sheet1", ws, 2, 1), "XML syntax error on line 1: invalid UTF-8")
+
+       f = NewFile()
+       _, err = f.NewSheet("Sheet2")
+       assert.NoError(t, err)
+       ws, err = f.workSheetReader("Sheet1")
+       assert.NoError(t, err)
+       assert.NoError(t, f.SetCellFormula("Sheet1", "B2", fmt.Sprintf("Sheet2!A%d", TotalRows)))
+       assert.Equal(t, ErrMaxRows, f.adjustRowDimensions("Sheet2", ws, 1, TotalRows))
 }
 
 func TestAdjustHyperlinks(t *testing.T) {
@@ -523,13 +543,13 @@ func TestAdjustFormula(t *testing.T) {
        assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAdjustFormula.xlsx")))
        assert.NoError(t, f.Close())
 
-       assert.NoError(t, f.adjustFormula("Sheet1", nil, rows, 0, 0, false))
-       assert.Equal(t, newCellNameToCoordinatesError("-", newInvalidCellNameError("-")), f.adjustFormula("Sheet1", &xlsxF{Ref: "-"}, rows, 0, 0, false))
-       assert.Equal(t, ErrColumnNumber, f.adjustFormula("Sheet1", &xlsxF{Ref: "XFD1:XFD1"}, columns, 0, 1, false))
+       assert.NoError(t, f.adjustFormula("Sheet1", "Sheet1", nil, rows, 0, 0, false))
+       assert.Equal(t, newCellNameToCoordinatesError("-", newInvalidCellNameError("-")), f.adjustFormula("Sheet1", "Sheet1", &xlsxF{Ref: "-"}, rows, 0, 0, false))
+       assert.Equal(t, ErrColumnNumber, f.adjustFormula("Sheet1", "Sheet1", &xlsxF{Ref: "XFD1:XFD1"}, columns, 0, 1, false))
 
-       _, err := f.adjustFormulaRef("Sheet1", "XFE1", columns, 0, 1)
+       _, err := f.adjustFormulaRef("Sheet1", "Sheet1", "XFE1", columns, 0, 1)
        assert.Equal(t, ErrColumnNumber, err)
-       _, err = f.adjustFormulaRef("Sheet1", "XFD1", columns, 0, 1)
+       _, err = f.adjustFormulaRef("Sheet1", "Sheet1", "XFD1", columns, 0, 1)
        assert.Equal(t, ErrColumnNumber, err)
 
        f = NewFile()
@@ -699,17 +719,17 @@ func TestAdjustFormula(t *testing.T) {
 
                f = NewFile()
                // Test adjust formula on insert row in the middle of the range
-               assert.NoError(t, f.SetCellFormula("Sheet1", "B1", "SUM('Sheet1'!A2,A3)"))
+               assert.NoError(t, f.SetCellFormula("Sheet1", "B1", "SUM('Sheet 1'!A2,A3)"))
                assert.NoError(t, f.InsertRows("Sheet1", 3, 1))
                formula, err = f.GetCellFormula("Sheet1", "B1")
                assert.NoError(t, err)
-               assert.Equal(t, "SUM('Sheet1'!A2,A4)", formula)
+               assert.Equal(t, "SUM('Sheet 1'!A2,A4)", formula)
 
                // Test adjust formula on insert row at the top of the range
                assert.NoError(t, f.InsertRows("Sheet1", 2, 1))
                formula, err = f.GetCellFormula("Sheet1", "B1")
                assert.NoError(t, err)
-               assert.Equal(t, "SUM('Sheet1'!A3,A5)", formula)
+               assert.Equal(t, "SUM('Sheet 1'!A3,A5)", formula)
 
                f = NewFile()
                // Test adjust formula on insert col in the middle of the range
@@ -767,4 +787,143 @@ func TestAdjustFormula(t *testing.T) {
                assert.NoError(t, err)
                assert.Equal(t, "SUM(D:F)", formula)
        })
+       t.Run("for_all_worksheet_cells_with_rows_insert", func(t *testing.T) {
+               f := NewFile()
+               _, err := f.NewSheet("Sheet2")
+               assert.NoError(t, err)
+               // Tests formulas referencing Sheet2 should update but those referencing the original sheet should not
+               tbl := [][]string{
+                       {"B1", "Sheet2!A1+Sheet2!A2", "Sheet2!A1+Sheet2!A3", "Sheet2!A2+Sheet2!A4"},
+                       {"C1", "A1+A2", "A1+A2", "A1+A2"},
+                       {"D1", "Sheet2!B1:B2", "Sheet2!B1:B3", "Sheet2!B2:B4"},
+                       {"E1", "B1:B2", "B1:B2", "B1:B2"},
+                       {"F1", "SUM(Sheet2!C1:C2)", "SUM(Sheet2!C1:C3)", "SUM(Sheet2!C2:C4)"},
+                       {"G1", "SUM(C1:C2)", "SUM(C1:C2)", "SUM(C1:C2)"},
+                       {"H1", "SUM(Sheet2!D1,Sheet2!D2)", "SUM(Sheet2!D1,Sheet2!D3)", "SUM(Sheet2!D2,Sheet2!D4)"},
+                       {"I1", "SUM(D1,D2)", "SUM(D1,D2)", "SUM(D1,D2)"},
+               }
+               for _, preset := range tbl {
+                       assert.NoError(t, f.SetCellFormula("Sheet1", preset[0], preset[1]))
+               }
+               // Test adjust formula on insert row in the middle of the range
+               assert.NoError(t, f.InsertRows("Sheet2", 2, 1))
+               for _, preset := range tbl {
+                       formula, err := f.GetCellFormula("Sheet1", preset[0])
+                       assert.NoError(t, err)
+                       assert.Equal(t, preset[2], formula)
+               }
+
+               // Test adjust formula on insert row in the top of the range
+               assert.NoError(t, f.InsertRows("Sheet2", 1, 1))
+               for _, preset := range tbl {
+                       formula, err := f.GetCellFormula("Sheet1", preset[0])
+                       assert.NoError(t, err)
+                       assert.Equal(t, preset[3], formula)
+               }
+       })
+       t.Run("for_all_worksheet_cells_with_cols_insert", func(t *testing.T) {
+               f := NewFile()
+               _, err := f.NewSheet("Sheet2")
+               assert.NoError(t, err)
+               tbl := [][]string{
+                       {"A1", "Sheet2!A1+Sheet2!B1", "Sheet2!A1+Sheet2!C1", "Sheet2!B1+Sheet2!D1"},
+                       {"A2", "A1+B1", "A1+B1", "A1+B1"},
+                       {"A3", "Sheet2!A2:B2", "Sheet2!A2:C2", "Sheet2!B2:D2"},
+                       {"A4", "A2:B2", "A2:B2", "A2:B2"},
+                       {"A5", "SUM(Sheet2!A3:B3)", "SUM(Sheet2!A3:C3)", "SUM(Sheet2!B3:D3)"},
+                       {"A6", "SUM(A3:B3)", "SUM(A3:B3)", "SUM(A3:B3)"},
+                       {"A7", "SUM(Sheet2!A4,Sheet2!B4)", "SUM(Sheet2!A4,Sheet2!C4)", "SUM(Sheet2!B4,Sheet2!D4)"},
+                       {"A8", "SUM(A4,B4)", "SUM(A4,B4)", "SUM(A4,B4)"},
+               }
+               for _, preset := range tbl {
+                       assert.NoError(t, f.SetCellFormula("Sheet1", preset[0], preset[1]))
+               }
+               // Test adjust formula on insert column in the middle of the range
+               assert.NoError(t, f.InsertCols("Sheet2", "B", 1))
+               for _, preset := range tbl {
+                       formula, err := f.GetCellFormula("Sheet1", preset[0])
+                       assert.NoError(t, err)
+                       assert.Equal(t, preset[2], formula)
+               }
+               // Test adjust formula on insert column in the top of the range
+               assert.NoError(t, f.InsertCols("Sheet2", "A", 1))
+               for _, preset := range tbl {
+                       formula, err := f.GetCellFormula("Sheet1", preset[0])
+                       assert.NoError(t, err)
+                       assert.Equal(t, preset[3], formula)
+               }
+       })
+       t.Run("for_cross_sheet_ref_with_rows_insert)", func(t *testing.T) {
+               f := NewFile()
+               _, err := f.NewSheet("Sheet2")
+               assert.NoError(t, err)
+               _, err = f.NewSheet("Sheet3")
+               assert.NoError(t, err)
+               // Tests formulas referencing Sheet2 should update but those referencing
+               // the original sheet or Sheet 3 should not update
+               tbl := [][]string{
+                       {"B1", "Sheet2!A1+Sheet2!A2+Sheet1!A3+Sheet1!A4", "Sheet2!A1+Sheet2!A3+Sheet1!A3+Sheet1!A4", "Sheet2!A2+Sheet2!A4+Sheet1!A3+Sheet1!A4"},
+                       {"C1", "Sheet2!B1+Sheet2!B2+B3+B4", "Sheet2!B1+Sheet2!B3+B3+B4", "Sheet2!B2+Sheet2!B4+B3+B4"},
+                       {"D1", "Sheet2!C1+Sheet2!C2+Sheet3!A3+Sheet3!A4", "Sheet2!C1+Sheet2!C3+Sheet3!A3+Sheet3!A4", "Sheet2!C2+Sheet2!C4+Sheet3!A3+Sheet3!A4"},
+                       {"E1", "SUM(Sheet2!D1:D2,Sheet1!A3:A4)", "SUM(Sheet2!D1:D3,Sheet1!A3:A4)", "SUM(Sheet2!D2:D4,Sheet1!A3:A4)"},
+                       {"F1", "SUM(Sheet2!E1:E2,A3:A4)", "SUM(Sheet2!E1:E3,A3:A4)", "SUM(Sheet2!E2:E4,A3:A4)"},
+                       {"G1", "SUM(Sheet2!F1:F2,Sheet3!A3:A4)", "SUM(Sheet2!F1:F3,Sheet3!A3:A4)", "SUM(Sheet2!F2:F4,Sheet3!A3:A4)"},
+               }
+               for _, preset := range tbl {
+                       assert.NoError(t, f.SetCellFormula("Sheet1", preset[0], preset[1]))
+               }
+               // Test adjust formula on insert row in the middle of the range
+               assert.NoError(t, f.InsertRows("Sheet2", 2, 1))
+               for _, preset := range tbl {
+                       formula, err := f.GetCellFormula("Sheet1", preset[0])
+                       assert.NoError(t, err)
+                       assert.Equal(t, preset[2], formula)
+               }
+               // Test adjust formula on insert row in the top of the range
+               assert.NoError(t, f.InsertRows("Sheet2", 1, 1))
+               for _, preset := range tbl {
+                       formula, err := f.GetCellFormula("Sheet1", preset[0])
+                       assert.NoError(t, err)
+                       assert.Equal(t, preset[3], formula)
+               }
+       })
+       t.Run("for_cross_sheet_ref_with_cols_insert)", func(t *testing.T) {
+               f := NewFile()
+               _, err := f.NewSheet("Sheet2")
+               assert.NoError(t, err)
+               _, err = f.NewSheet("Sheet3")
+               assert.NoError(t, err)
+               // Tests formulas referencing Sheet2 should update but those referencing
+               // the original sheet or Sheet 3 should not update
+               tbl := [][]string{
+                       {"A1", "Sheet2!A1+Sheet2!B1+Sheet1!C1+Sheet1!D1", "Sheet2!A1+Sheet2!C1+Sheet1!C1+Sheet1!D1", "Sheet2!B1+Sheet2!D1+Sheet1!C1+Sheet1!D1"},
+                       {"A2", "Sheet2!A2+Sheet2!B2+C2+D2", "Sheet2!A2+Sheet2!C2+C2+D2", "Sheet2!B2+Sheet2!D2+C2+D2"},
+                       {"A3", "Sheet2!A3+Sheet2!B3+Sheet3!C3+Sheet3!D3", "Sheet2!A3+Sheet2!C3+Sheet3!C3+Sheet3!D3", "Sheet2!B3+Sheet2!D3+Sheet3!C3+Sheet3!D3"},
+                       {"A4", "SUM(Sheet2!A4:B4,Sheet1!C4:D4)", "SUM(Sheet2!A4:C4,Sheet1!C4:D4)", "SUM(Sheet2!B4:D4,Sheet1!C4:D4)"},
+                       {"A5", "SUM(Sheet2!A5:B5,C5:D5)", "SUM(Sheet2!A5:C5,C5:D5)", "SUM(Sheet2!B5:D5,C5:D5)"},
+                       {"A6", "SUM(Sheet2!A6:B6,Sheet3!C6:D6)", "SUM(Sheet2!A6:C6,Sheet3!C6:D6)", "SUM(Sheet2!B6:D6,Sheet3!C6:D6)"},
+               }
+               for _, preset := range tbl {
+                       assert.NoError(t, f.SetCellFormula("Sheet1", preset[0], preset[1]))
+               }
+               // Test adjust formula on insert row in the middle of the range
+               assert.NoError(t, f.InsertCols("Sheet2", "B", 1))
+               for _, preset := range tbl {
+                       formula, err := f.GetCellFormula("Sheet1", preset[0])
+                       assert.NoError(t, err)
+                       assert.Equal(t, preset[2], formula)
+               }
+               // Test adjust formula on insert row in the top of the range
+               assert.NoError(t, f.InsertCols("Sheet2", "A", 1))
+               for _, preset := range tbl {
+                       formula, err := f.GetCellFormula("Sheet1", preset[0])
+                       assert.NoError(t, err)
+                       assert.Equal(t, preset[3], formula)
+               }
+       })
+       t.Run("for_cross_sheet_ref_with_chart_sheet)", func(t *testing.T) {
+               assert.NoError(t, f.AddChartSheet("Chart1", &Chart{Type: Line}))
+               assert.NoError(t, f.InsertRows("Sheet1", 2, 1))
+               assert.NoError(t, f.InsertCols("Sheet1", "A", 1))
+       })
 }
diff --git a/rows.go b/rows.go
index 992a780..027d44c 100644 (file)
--- a/rows.go
+++ b/rows.go
@@ -653,7 +653,7 @@ func (f *File) DuplicateRowTo(sheet string, row, row2 int) error {
 
        rowCopy.C = append(make([]xlsxC, 0, len(rowCopy.C)), rowCopy.C...)
        rowCopy.adjustSingleRowDimensions(row2 - row)
-       _ = f.adjustSingleRowFormulas(sheet, &rowCopy, row, row2-row, true)
+       _ = f.adjustSingleRowFormulas(sheet, sheet, &rowCopy, row, row2-row, true)
 
        if idx2 != -1 {
                ws.SheetData.Row[idx2] = rowCopy