Skip to content

Commit 821632c

Browse files
committed
Fix qax-os#424, refactor merged cells adjuster
1 parent 46a3632 commit 821632c

9 files changed

+221
-123
lines changed

adjust.go

+100-61
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99

1010
package excelize
1111

12-
import "strings"
12+
import (
13+
"errors"
14+
"strings"
15+
)
1316

1417
type adjustDirection bool
1518

@@ -140,46 +143,85 @@ func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, dir adjustDirection, num, o
140143
return nil
141144
}
142145

143-
rng := strings.Split(xlsx.AutoFilter.Ref, ":")
144-
firstCell := rng[0]
145-
lastCell := rng[1]
146-
147-
firstCol, firstRow, err := CellNameToCoordinates(firstCell)
146+
coordinates, err := f.areaRefToCoordinates(xlsx.AutoFilter.Ref)
148147
if err != nil {
149148
return err
150149
}
150+
x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]
151151

152-
lastCol, lastRow, err := CellNameToCoordinates(lastCell)
153-
if err != nil {
154-
return err
155-
}
156-
157-
if (dir == rows && firstRow == num && offset < 0) || (dir == columns && firstCol == num && lastCol == num) {
152+
if (dir == rows && y1 == num && offset < 0) || (dir == columns && x1 == num && x2 == num) {
158153
xlsx.AutoFilter = nil
159154
for rowIdx := range xlsx.SheetData.Row {
160155
rowData := &xlsx.SheetData.Row[rowIdx]
161-
if rowData.R > firstRow && rowData.R <= lastRow {
156+
if rowData.R > y1 && rowData.R <= y2 {
162157
rowData.Hidden = false
163158
}
164159
}
165160
return nil
166161
}
167162

163+
coordinates = f.adjustAutoFilterHelper(dir, coordinates, num, offset)
164+
x1, y1, x2, y2 = coordinates[0], coordinates[1], coordinates[2], coordinates[3]
165+
166+
if xlsx.AutoFilter.Ref, err = f.coordinatesToAreaRef([]int{x1, y1, x2, y2}); err != nil {
167+
return err
168+
}
169+
return nil
170+
}
171+
172+
// adjustAutoFilterHelper provides a function for adjusting auto filter to
173+
// compare and calculate cell axis by the given adjust direction, operation
174+
// axis and offset.
175+
func (f *File) adjustAutoFilterHelper(dir adjustDirection, coordinates []int, num, offset int) []int {
168176
if dir == rows {
169-
if firstRow >= num {
170-
firstCell, _ = CoordinatesToCellName(firstCol, firstRow+offset)
177+
if coordinates[1] >= num {
178+
coordinates[1] += offset
171179
}
172-
if lastRow >= num {
173-
lastCell, _ = CoordinatesToCellName(lastCol, lastRow+offset)
180+
if coordinates[3] >= num {
181+
coordinates[3] += offset
174182
}
175183
} else {
176-
if lastCol >= num {
177-
lastCell, _ = CoordinatesToCellName(lastCol+offset, lastRow)
184+
if coordinates[2] >= num {
185+
coordinates[2] += offset
178186
}
179187
}
188+
return coordinates
189+
}
180190

181-
xlsx.AutoFilter.Ref = firstCell + ":" + lastCell
182-
return nil
191+
// areaRefToCoordinates provides a function to convert area reference to a
192+
// pair of coordinates.
193+
func (f *File) areaRefToCoordinates(ref string) ([]int, error) {
194+
coordinates := make([]int, 4)
195+
rng := strings.Split(ref, ":")
196+
firstCell := rng[0]
197+
lastCell := rng[1]
198+
var err error
199+
coordinates[0], coordinates[1], err = CellNameToCoordinates(firstCell)
200+
if err != nil {
201+
return coordinates, err
202+
}
203+
coordinates[2], coordinates[3], err = CellNameToCoordinates(lastCell)
204+
if err != nil {
205+
return coordinates, err
206+
}
207+
return coordinates, err
208+
}
209+
210+
// coordinatesToAreaRef provides a function to convert a pair of coordinates
211+
// to area reference.
212+
func (f *File) coordinatesToAreaRef(coordinates []int) (string, error) {
213+
if len(coordinates) != 4 {
214+
return "", errors.New("coordinates length must be 4")
215+
}
216+
firstCell, err := CoordinatesToCellName(coordinates[0], coordinates[1])
217+
if err != nil {
218+
return "", err
219+
}
220+
lastCell, err := CoordinatesToCellName(coordinates[2], coordinates[3])
221+
if err != nil {
222+
return "", err
223+
}
224+
return firstCell + ":" + lastCell, err
183225
}
184226

185227
// adjustMergeCells provides a function to update merged cells when inserting
@@ -190,59 +232,56 @@ func (f *File) adjustMergeCells(xlsx *xlsxWorksheet, dir adjustDirection, num, o
190232
}
191233

192234
for i, areaData := range xlsx.MergeCells.Cells {
193-
rng := strings.Split(areaData.Ref, ":")
194-
firstCell := rng[0]
195-
lastCell := rng[1]
196-
197-
firstCol, firstRow, err := CellNameToCoordinates(firstCell)
235+
coordinates, err := f.areaRefToCoordinates(areaData.Ref)
198236
if err != nil {
199237
return err
200238
}
201-
202-
lastCol, lastRow, err := CellNameToCoordinates(lastCell)
203-
if err != nil {
204-
return err
205-
}
206-
207-
adjust := func(v int) int {
208-
if v >= num {
209-
v += offset
210-
if v < 1 {
211-
return 1
212-
}
213-
return v
214-
}
215-
return v
216-
}
217-
239+
x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]
218240
if dir == rows {
219-
firstRow = adjust(firstRow)
220-
lastRow = adjust(lastRow)
241+
if y1 == num && y2 == num && offset < 0 {
242+
f.deleteMergeCell(xlsx, i)
243+
}
244+
y1 = f.adjustMergeCellsHelper(y1, num, offset)
245+
y2 = f.adjustMergeCellsHelper(y2, num, offset)
221246
} else {
222-
firstCol = adjust(firstCol)
223-
lastCol = adjust(lastCol)
224-
}
225-
226-
if firstCol == lastCol && firstRow == lastRow {
227-
if len(xlsx.MergeCells.Cells) > 1 {
228-
xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
229-
xlsx.MergeCells.Count = len(xlsx.MergeCells.Cells)
230-
} else {
231-
xlsx.MergeCells = nil
247+
if x1 == num && x2 == num && offset < 0 {
248+
f.deleteMergeCell(xlsx, i)
232249
}
250+
x1 = f.adjustMergeCellsHelper(x1, num, offset)
251+
x2 = f.adjustMergeCellsHelper(x2, num, offset)
233252
}
234-
235-
if firstCell, err = CoordinatesToCellName(firstCol, firstRow); err != nil {
253+
if x1 == x2 && y1 == y2 {
254+
f.deleteMergeCell(xlsx, i)
255+
}
256+
if areaData.Ref, err = f.coordinatesToAreaRef([]int{x1, y1, x2, y2}); err != nil {
236257
return err
237258
}
259+
}
260+
return nil
261+
}
238262

239-
if lastCell, err = CoordinatesToCellName(lastCol, lastRow); err != nil {
240-
return err
263+
// adjustMergeCellsHelper provides a function for adjusting merge cells to
264+
// compare and calculate cell axis by the given pivot, operation axis and
265+
// offset.
266+
func (f *File) adjustMergeCellsHelper(pivot, num, offset int) int {
267+
if pivot >= num {
268+
pivot += offset
269+
if pivot < 1 {
270+
return 1
241271
}
272+
return pivot
273+
}
274+
return pivot
275+
}
242276

243-
areaData.Ref = firstCell + ":" + lastCell
277+
// deleteMergeCell provides a function to delete merged cell by given index.
278+
func (f *File) deleteMergeCell(sheet *xlsxWorksheet, idx int) {
279+
if len(sheet.MergeCells.Cells) > 1 {
280+
sheet.MergeCells.Cells = append(sheet.MergeCells.Cells[:idx], sheet.MergeCells.Cells[idx+1:]...)
281+
sheet.MergeCells.Count = len(sheet.MergeCells.Cells)
282+
} else {
283+
sheet.MergeCells = nil
244284
}
245-
return nil
246285
}
247286

248287
// adjustCalcChain provides a function to update the calculation chain when

adjust_test.go

+31
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ func TestAdjustMergeCells(t *testing.T) {
2727
},
2828
},
2929
}, rows, 0, 0), `cannot convert cell "B" to coordinates: invalid cell name "B"`)
30+
assert.NoError(t, f.adjustMergeCells(&xlsxWorksheet{
31+
MergeCells: &xlsxMergeCells{
32+
Cells: []*xlsxMergeCell{
33+
{
34+
Ref: "A1:B1",
35+
},
36+
},
37+
},
38+
}, rows, 1, -1))
39+
assert.NoError(t, f.adjustMergeCells(&xlsxWorksheet{
40+
MergeCells: &xlsxMergeCells{
41+
Cells: []*xlsxMergeCell{
42+
{
43+
Ref: "A1:A2",
44+
},
45+
},
46+
},
47+
}, columns, 1, -1))
3048
}
3149

3250
func TestAdjustAutoFilter(t *testing.T) {
@@ -83,3 +101,16 @@ func TestAdjustCalcChain(t *testing.T) {
83101
f.CalcChain = nil
84102
assert.NoError(t, f.InsertCol("Sheet1", "A"))
85103
}
104+
105+
func TestCoordinatesToAreaRef(t *testing.T) {
106+
f := NewFile()
107+
ref, err := f.coordinatesToAreaRef([]int{})
108+
assert.EqualError(t, err, "coordinates length must be 4")
109+
ref, err = f.coordinatesToAreaRef([]int{1, -1, 1, 1})
110+
assert.EqualError(t, err, "invalid cell coordinates [1, -1]")
111+
ref, err = f.coordinatesToAreaRef([]int{1, 1, 1, -1})
112+
assert.EqualError(t, err, "invalid cell coordinates [1, -1]")
113+
ref, err = f.coordinatesToAreaRef([]int{1, 1, 1, 1})
114+
assert.NoError(t, err)
115+
assert.EqualValues(t, ref, "A1:A1")
116+
}

cell.go

+9-13
Original file line numberDiff line numberDiff line change
@@ -401,31 +401,27 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) error {
401401
// If you create a merged cell that overlaps with another existing merged cell,
402402
// those merged cells that already exist will be removed.
403403
func (f *File) MergeCell(sheet, hcell, vcell string) error {
404-
hcol, hrow, err := CellNameToCoordinates(hcell)
404+
coordinates, err := f.areaRefToCoordinates(hcell + ":" + vcell)
405405
if err != nil {
406406
return err
407407
}
408+
x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]
408409

409-
vcol, vrow, err := CellNameToCoordinates(vcell)
410-
if err != nil {
411-
return err
412-
}
413-
414-
if hcol == vcol && hrow == vrow {
410+
if x1 == x2 && y1 == y2 {
415411
return err
416412
}
417413

418414
// Correct the coordinate area, such correct C1:B3 to B1:C3.
419-
if vcol < hcol {
420-
hcol, vcol = vcol, hcol
415+
if x2 < x1 {
416+
x1, x2 = x2, x1
421417
}
422418

423-
if vrow < hrow {
424-
hrow, vrow = vrow, hrow
419+
if y2 < y1 {
420+
y1, y2 = y2, y1
425421
}
426422

427-
hcell, _ = CoordinatesToCellName(hcol, hrow)
428-
vcell, _ = CoordinatesToCellName(vcol, vrow)
423+
hcell, _ = CoordinatesToCellName(x1, y1)
424+
vcell, _ = CoordinatesToCellName(x2, y2)
429425

430426
xlsx, err := f.workSheetReader(sheet)
431427
if err != nil {

rows.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ func (f *File) RemoveRow(sheet string, row int) error {
421421
return err
422422
}
423423
if row > len(xlsx.SheetData.Row) {
424-
return nil
424+
return f.adjustHelper(sheet, rows, row, -1)
425425
}
426426
for rowIdx := range xlsx.SheetData.Row {
427427
if xlsx.SheetData.Row[rowIdx].R == row {

styles.go

100755100644
File mode changed.

table.go

+6-11
Original file line numberDiff line numberDiff line change
@@ -115,29 +115,24 @@ func (f *File) addSheetTable(sheet string, rID int) {
115115

116116
// addTable provides a function to add table by given worksheet name,
117117
// coordinate area and format set.
118-
func (f *File) addTable(sheet, tableXML string, hcol, hrow, vcol, vrow, i int, formatSet *formatTable) error {
118+
func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, formatSet *formatTable) error {
119119
// Correct the minimum number of rows, the table at least two lines.
120-
if hrow == vrow {
121-
vrow++
120+
if y1 == y2 {
121+
y2++
122122
}
123123

124124
// Correct table reference coordinate area, such correct C1:B3 to B1:C3.
125-
hcell, err := CoordinatesToCellName(hcol, hrow)
125+
ref, err := f.coordinatesToAreaRef([]int{x1, y1, x2, y2})
126126
if err != nil {
127127
return err
128128
}
129-
vcell, err := CoordinatesToCellName(vcol, vrow)
130-
if err != nil {
131-
return err
132-
}
133-
ref := hcell + ":" + vcell
134129

135130
var tableColumn []*xlsxTableColumn
136131

137132
idx := 0
138-
for i := hcol; i <= vcol; i++ {
133+
for i := x1; i <= x2; i++ {
139134
idx++
140-
cell, err := CoordinatesToCellName(i, hrow)
135+
cell, err := CoordinatesToCellName(i, y1)
141136
if err != nil {
142137
return err
143138
}

xmlChart.go

100755100644
File mode changed.

0 commit comments

Comments
 (0)