diff --git a/excelize.go b/excelize.go index 4b4aa321..b162b799 100644 --- a/excelize.go +++ b/excelize.go @@ -238,18 +238,19 @@ func (f *File) adjustRowDimensions(xlsx *xlsxWorksheet, rowIndex, offset int) { } for i, r := range xlsx.SheetData.Row { if r.R >= rowIndex { - xlsx.SheetData.Row[i].R += offset - for k, v := range xlsx.SheetData.Row[i].C { - axis := v.R - col := string(strings.Map(letterOnlyMapF, axis)) - row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis)) - xAxis := row + offset - xlsx.SheetData.Row[i].C[k].R = col + strconv.Itoa(xAxis) - } + f.ajustSingleRowDimensions(&xlsx.SheetData.Row[i], offset) } } } +func (f *File) ajustSingleRowDimensions(r *xlsxRow, offset int) { + r.R += offset + for i, col := range r.C { + row, _ := strconv.Atoi(strings.Map(intOnlyMapF, col.R)) + r.C[i].R = string(strings.Map(letterOnlyMapF, col.R)) + strconv.Itoa(row+offset) + } +} + // adjustHyperlinks provides a function to update hyperlinks when inserting or // deleting rows or columns. func (f *File) adjustHyperlinks(sheet string, column, rowIndex, offset int) { diff --git a/excelize_test.go b/excelize_test.go index 19950583..8c19a3e9 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -12,6 +12,8 @@ import ( "strings" "testing" "time" + + "github.com/stretchr/testify/assert" ) func TestOpenFile(t *testing.T) { @@ -1029,6 +1031,71 @@ func TestInsertRow(t *testing.T) { } } +func TestDuplicateRow(t *testing.T) { + const ( + file = "./test/Book_DuplicateRow_%s.xlsx" + sheet = "Sheet1" + a1 = "A1" + b1 = "B1" + a2 = "A2" + b2 = "B2" + a3 = "A3" + b3 = "B3" + a4 = "A4" + b4 = "B4" + a1Value = "A1 value" + a2Value = "A2 value" + a3Value = "A3 value" + bnValue = "Bn value" + ) + xlsx := NewFile() + xlsx.SetCellStr(sheet, a1, a1Value) + xlsx.SetCellStr(sheet, b1, bnValue) + + t.Run("FromSingleRow", func(t *testing.T) { + xlsx.DuplicateRow(sheet, 1) + xlsx.DuplicateRow(sheet, 2) + + if assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(file, "SignleRow"))) { + assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a1)) + assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a2)) + assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a3)) + assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b1)) + assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b2)) + assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b3)) + } + }) + + t.Run("UpdateDuplicatedRows", func(t *testing.T) { + xlsx.SetCellStr(sheet, a2, a2Value) + xlsx.SetCellStr(sheet, a3, a3Value) + + if assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(file, "Updated"))) { + assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a1)) + assert.Equal(t, a2Value, xlsx.GetCellValue(sheet, a2)) + assert.Equal(t, a3Value, xlsx.GetCellValue(sheet, a3)) + assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b1)) + assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b2)) + assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b3)) + } + }) + + t.Run("FromFirstOfMultipleRows", func(t *testing.T) { + xlsx.DuplicateRow(sheet, 1) + + if assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(file, "FirstOfMultipleRows"))) { + assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a1)) + assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a2)) + assert.Equal(t, a2Value, xlsx.GetCellValue(sheet, a3)) + assert.Equal(t, a3Value, xlsx.GetCellValue(sheet, a4)) + assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b1)) + assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b2)) + assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b3)) + assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b4)) + } + }) +} + func TestSetPane(t *testing.T) { xlsx := NewFile() xlsx.SetPanes("Sheet1", `{"freeze":false,"split":false}`) diff --git a/go.mod b/go.mod index 05363712..8db2fe6c 100644 --- a/go.mod +++ b/go.mod @@ -1 +1,8 @@ module github.com/360EntSecGroup-Skylar/excelize + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.2.2 +) diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..ca5f759f --- /dev/null +++ b/go.sum @@ -0,0 +1,8 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= diff --git a/rows.go b/rows.go index b6336331..def150d1 100644 --- a/rows.go +++ b/rows.go @@ -359,7 +359,7 @@ func (f *File) RemoveRow(sheet string, row int) { } } -// InsertRow provides a function to insert a new row before given row index. +// InsertRow provides a function to insert a new row after given row index. // For example, create a new row before row 3 in Sheet1: // // xlsx.InsertRow("Sheet1", 2) @@ -372,6 +372,46 @@ func (f *File) InsertRow(sheet string, row int) { f.adjustHelper(sheet, -1, row, 1) } +// DuplicateRow inserts a copy of specified row below specified +// +// xlsx.DuplicateRow("Sheet1", 2) +// +func (f *File) DuplicateRow(sheet string, row int) { + if row < 0 { + return + } + row2 := row + 1 + f.adjustHelper(sheet, -1, row2, 1) + + xlsx := f.workSheetReader(sheet) + idx := -1 + idx2 := -1 + + for i, r := range xlsx.SheetData.Row { + if r.R == row { + idx = i + } else if r.R == row2 { + idx2 = i + } + if idx != -1 && idx2 != -1 { + break + } + } + + if idx == -1 || (idx2 == -1 && len(xlsx.SheetData.Row) >= row2) { + return + } + rowData := xlsx.SheetData.Row[idx] + cols := make([]xlsxC, 0, len(rowData.C)) + rowData.C = append(cols, rowData.C...) + f.ajustSingleRowDimensions(&rowData, 1) + if idx2 != -1 { + xlsx.SheetData.Row[idx2] = rowData + } else { + xlsx.SheetData.Row = append(xlsx.SheetData.Row, rowData) + } +} + // checkRow provides a function to check and fill each column element for all // rows and make that is continuous in a worksheet of XML. For example: //