summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2020-02-25 00:19:22 +0800
committerxuri <xuri.me@gmail.com>2020-02-25 00:19:22 +0800
commit8b20ea1685cdb010be8f95ffc047fa44e1a0e90a (patch)
treefa0ac12c66de26ab0237254a37a38b839c9913e9
parent6dcb7013eeeb8902be97c564c7a5a05dddcb06b8 (diff)
Fix #586, duplicate row with merged cells
-rw-r--r--rows.go34
-rw-r--r--rows_test.go64
2 files changed, 98 insertions, 0 deletions
diff --git a/rows.go b/rows.go
index 23f3a2c..0684b18 100644
--- a/rows.go
+++ b/rows.go
@@ -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()