diff options
author | xuri <xuri.me@gmail.com> | 2020-02-25 00:19:22 +0800 |
---|---|---|
committer | xuri <xuri.me@gmail.com> | 2020-02-25 00:19:22 +0800 |
commit | 8b20ea1685cdb010be8f95ffc047fa44e1a0e90a (patch) | |
tree | fa0ac12c66de26ab0237254a37a38b839c9913e9 | |
parent | 6dcb7013eeeb8902be97c564c7a5a05dddcb06b8 (diff) |
Fix #586, duplicate row with merged cells
-rw-r--r-- | rows.go | 34 | ||||
-rw-r--r-- | rows_test.go | 64 |
2 files changed, 98 insertions, 0 deletions
@@ -519,6 +519,40 @@ func (f *File) DuplicateRowTo(sheet string, row, row2 int) error { } else { xlsx.SheetData.Row = append(xlsx.SheetData.Row, rowCopy) } + return f.duplicateMergeCells(sheet, xlsx, row, row2) +} + +// duplicateMergeCells merge cells in the destination row if there are single +// row merged cells in the copied row. +func (f *File) duplicateMergeCells(sheet string, xlsx *xlsxWorksheet, row, row2 int) error { + if xlsx.MergeCells == nil { + return nil + } + if row > row2 { + row++ + } + for _, rng := range xlsx.MergeCells.Cells { + coordinates, err := f.areaRefToCoordinates(rng.Ref) + if err != nil { + return err + } + if coordinates[1] < row2 && row2 < coordinates[3] { + return nil + } + } + for i := 0; i < len(xlsx.MergeCells.Cells); i++ { + areaData := xlsx.MergeCells.Cells[i] + coordinates, _ := f.areaRefToCoordinates(areaData.Ref) + x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3] + if y1 == y2 && y1 == row { + from, _ := CoordinatesToCellName(x1, row2) + to, _ := CoordinatesToCellName(x2, row2) + if err := f.MergeCell(sheet, from, to); err != nil { + return err + } + i++ + } + } return nil } diff --git a/rows_test.go b/rows_test.go index 9377d5e..a5ee428 100644 --- a/rows_test.go +++ b/rows_test.go @@ -693,6 +693,55 @@ func TestDuplicateRowInsertBeforeWithLargeOffset(t *testing.T) { }) } +func TestDuplicateRowInsertBeforeWithMergeCells(t *testing.T) { + const sheet = "Sheet1" + outFile := filepath.Join("test", "TestDuplicateRow.%s.xlsx") + + cells := map[string]string{ + "A1": "A1 Value", + "A2": "A2 Value", + "A3": "A3 Value", + "B1": "B1 Value", + "B2": "B2 Value", + "B3": "B3 Value", + } + + newFileWithDefaults := func() *File { + f := NewFile() + for cell, val := range cells { + assert.NoError(t, f.SetCellStr(sheet, cell, val)) + } + assert.NoError(t, f.MergeCell(sheet, "B2", "C2")) + assert.NoError(t, f.MergeCell(sheet, "C6", "C8")) + return f + } + + t.Run("InsertBeforeWithLargeOffset", func(t *testing.T) { + xlsx := newFileWithDefaults() + + assert.NoError(t, xlsx.DuplicateRowTo(sheet, 2, 1)) + assert.NoError(t, xlsx.DuplicateRowTo(sheet, 1, 8)) + + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBeforeWithMergeCells"))) { + t.FailNow() + } + + expect := []MergeCell{ + {"B3:C3", "B2 Value"}, + {"C7:C10", ""}, + {"B1:C1", "B2 Value"}, + } + + mergeCells, err := xlsx.GetMergeCells(sheet) + assert.NoError(t, err) + for idx, val := range expect { + if !assert.Equal(t, val, mergeCells[idx]) { + t.FailNow() + } + } + }) +} + func TestDuplicateRowInvalidRownum(t *testing.T) { const sheet = "Sheet1" outFile := filepath.Join("test", "TestDuplicateRowInvalidRownum.%s.xlsx") @@ -753,6 +802,21 @@ func TestDuplicateRowInvalidRownum(t *testing.T) { } } +func TestDuplicateRowTo(t *testing.T) { + f := File{} + assert.EqualError(t, f.DuplicateRowTo("SheetN", 1, 2), "sheet SheetN is not exist") +} + +func TestDuplicateMergeCells(t *testing.T) { + f := File{} + xlsx := &xlsxWorksheet{MergeCells: &xlsxMergeCells{ + Cells: []*xlsxMergeCell{&xlsxMergeCell{Ref: "A1:-"}}, + }} + assert.EqualError(t, f.duplicateMergeCells("Sheet1", xlsx, 0, 0), `cannot convert cell "-" to coordinates: invalid cell name "-"`) + xlsx.MergeCells.Cells[0].Ref = "A1:B1" + assert.EqualError(t, f.duplicateMergeCells("SheetN", xlsx, 1, 2), "sheet SheetN is not exist") +} + func TestGetValueFrom(t *testing.T) { c := &xlsxC{T: "inlineStr"} f := NewFile() |