Skip to content

Commit

Permalink
Fix qax-os#424, refactor merged cells adjuster
Browse files Browse the repository at this point in the history
  • Loading branch information
xuri committed Jun 12, 2019
1 parent 46a3632 commit 821632c
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 123 deletions.
161 changes: 100 additions & 61 deletions adjust.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@

package excelize

import "strings"
import (
"errors"
"strings"
)

type adjustDirection bool

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

rng := strings.Split(xlsx.AutoFilter.Ref, ":")
firstCell := rng[0]
lastCell := rng[1]

firstCol, firstRow, err := CellNameToCoordinates(firstCell)
coordinates, err := f.areaRefToCoordinates(xlsx.AutoFilter.Ref)
if err != nil {
return err
}
x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]

lastCol, lastRow, err := CellNameToCoordinates(lastCell)
if err != nil {
return err
}

if (dir == rows && firstRow == num && offset < 0) || (dir == columns && firstCol == num && lastCol == num) {
if (dir == rows && y1 == num && offset < 0) || (dir == columns && x1 == num && x2 == num) {
xlsx.AutoFilter = nil
for rowIdx := range xlsx.SheetData.Row {
rowData := &xlsx.SheetData.Row[rowIdx]
if rowData.R > firstRow && rowData.R <= lastRow {
if rowData.R > y1 && rowData.R <= y2 {
rowData.Hidden = false
}
}
return nil
}

coordinates = f.adjustAutoFilterHelper(dir, coordinates, num, offset)
x1, y1, x2, y2 = coordinates[0], coordinates[1], coordinates[2], coordinates[3]

if xlsx.AutoFilter.Ref, err = f.coordinatesToAreaRef([]int{x1, y1, x2, y2}); err != nil {
return err
}
return nil
}

// adjustAutoFilterHelper provides a function for adjusting auto filter to
// compare and calculate cell axis by the given adjust direction, operation
// axis and offset.
func (f *File) adjustAutoFilterHelper(dir adjustDirection, coordinates []int, num, offset int) []int {
if dir == rows {
if firstRow >= num {
firstCell, _ = CoordinatesToCellName(firstCol, firstRow+offset)
if coordinates[1] >= num {
coordinates[1] += offset
}
if lastRow >= num {
lastCell, _ = CoordinatesToCellName(lastCol, lastRow+offset)
if coordinates[3] >= num {
coordinates[3] += offset
}
} else {
if lastCol >= num {
lastCell, _ = CoordinatesToCellName(lastCol+offset, lastRow)
if coordinates[2] >= num {
coordinates[2] += offset
}
}
return coordinates
}

xlsx.AutoFilter.Ref = firstCell + ":" + lastCell
return nil
// areaRefToCoordinates provides a function to convert area reference to a
// pair of coordinates.
func (f *File) areaRefToCoordinates(ref string) ([]int, error) {
coordinates := make([]int, 4)
rng := strings.Split(ref, ":")
firstCell := rng[0]
lastCell := rng[1]
var err error
coordinates[0], coordinates[1], err = CellNameToCoordinates(firstCell)
if err != nil {
return coordinates, err
}
coordinates[2], coordinates[3], err = CellNameToCoordinates(lastCell)
if err != nil {
return coordinates, err
}
return coordinates, err
}

// coordinatesToAreaRef provides a function to convert a pair of coordinates
// to area reference.
func (f *File) coordinatesToAreaRef(coordinates []int) (string, error) {
if len(coordinates) != 4 {
return "", errors.New("coordinates length must be 4")
}
firstCell, err := CoordinatesToCellName(coordinates[0], coordinates[1])
if err != nil {
return "", err
}
lastCell, err := CoordinatesToCellName(coordinates[2], coordinates[3])
if err != nil {
return "", err
}
return firstCell + ":" + lastCell, err
}

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

for i, areaData := range xlsx.MergeCells.Cells {
rng := strings.Split(areaData.Ref, ":")
firstCell := rng[0]
lastCell := rng[1]

firstCol, firstRow, err := CellNameToCoordinates(firstCell)
coordinates, err := f.areaRefToCoordinates(areaData.Ref)
if err != nil {
return err
}

lastCol, lastRow, err := CellNameToCoordinates(lastCell)
if err != nil {
return err
}

adjust := func(v int) int {
if v >= num {
v += offset
if v < 1 {
return 1
}
return v
}
return v
}

x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]
if dir == rows {
firstRow = adjust(firstRow)
lastRow = adjust(lastRow)
if y1 == num && y2 == num && offset < 0 {
f.deleteMergeCell(xlsx, i)
}
y1 = f.adjustMergeCellsHelper(y1, num, offset)
y2 = f.adjustMergeCellsHelper(y2, num, offset)
} else {
firstCol = adjust(firstCol)
lastCol = adjust(lastCol)
}

if firstCol == lastCol && firstRow == lastRow {
if len(xlsx.MergeCells.Cells) > 1 {
xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
xlsx.MergeCells.Count = len(xlsx.MergeCells.Cells)
} else {
xlsx.MergeCells = nil
if x1 == num && x2 == num && offset < 0 {
f.deleteMergeCell(xlsx, i)
}
x1 = f.adjustMergeCellsHelper(x1, num, offset)
x2 = f.adjustMergeCellsHelper(x2, num, offset)
}

if firstCell, err = CoordinatesToCellName(firstCol, firstRow); err != nil {
if x1 == x2 && y1 == y2 {
f.deleteMergeCell(xlsx, i)
}
if areaData.Ref, err = f.coordinatesToAreaRef([]int{x1, y1, x2, y2}); err != nil {
return err
}
}
return nil
}

if lastCell, err = CoordinatesToCellName(lastCol, lastRow); err != nil {
return err
// adjustMergeCellsHelper provides a function for adjusting merge cells to
// compare and calculate cell axis by the given pivot, operation axis and
// offset.
func (f *File) adjustMergeCellsHelper(pivot, num, offset int) int {
if pivot >= num {
pivot += offset
if pivot < 1 {
return 1
}
return pivot
}
return pivot
}

areaData.Ref = firstCell + ":" + lastCell
// deleteMergeCell provides a function to delete merged cell by given index.
func (f *File) deleteMergeCell(sheet *xlsxWorksheet, idx int) {
if len(sheet.MergeCells.Cells) > 1 {
sheet.MergeCells.Cells = append(sheet.MergeCells.Cells[:idx], sheet.MergeCells.Cells[idx+1:]...)
sheet.MergeCells.Count = len(sheet.MergeCells.Cells)
} else {
sheet.MergeCells = nil
}
return nil
}

// adjustCalcChain provides a function to update the calculation chain when
Expand Down
31 changes: 31 additions & 0 deletions adjust_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ func TestAdjustMergeCells(t *testing.T) {
},
},
}, rows, 0, 0), `cannot convert cell "B" to coordinates: invalid cell name "B"`)
assert.NoError(t, f.adjustMergeCells(&xlsxWorksheet{
MergeCells: &xlsxMergeCells{
Cells: []*xlsxMergeCell{
{
Ref: "A1:B1",
},
},
},
}, rows, 1, -1))
assert.NoError(t, f.adjustMergeCells(&xlsxWorksheet{
MergeCells: &xlsxMergeCells{
Cells: []*xlsxMergeCell{
{
Ref: "A1:A2",
},
},
},
}, columns, 1, -1))
}

func TestAdjustAutoFilter(t *testing.T) {
Expand Down Expand Up @@ -83,3 +101,16 @@ func TestAdjustCalcChain(t *testing.T) {
f.CalcChain = nil
assert.NoError(t, f.InsertCol("Sheet1", "A"))
}

func TestCoordinatesToAreaRef(t *testing.T) {
f := NewFile()
ref, err := f.coordinatesToAreaRef([]int{})
assert.EqualError(t, err, "coordinates length must be 4")
ref, err = f.coordinatesToAreaRef([]int{1, -1, 1, 1})
assert.EqualError(t, err, "invalid cell coordinates [1, -1]")
ref, err = f.coordinatesToAreaRef([]int{1, 1, 1, -1})
assert.EqualError(t, err, "invalid cell coordinates [1, -1]")
ref, err = f.coordinatesToAreaRef([]int{1, 1, 1, 1})
assert.NoError(t, err)
assert.EqualValues(t, ref, "A1:A1")
}
22 changes: 9 additions & 13 deletions cell.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,31 +401,27 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) error {
// If you create a merged cell that overlaps with another existing merged cell,
// those merged cells that already exist will be removed.
func (f *File) MergeCell(sheet, hcell, vcell string) error {
hcol, hrow, err := CellNameToCoordinates(hcell)
coordinates, err := f.areaRefToCoordinates(hcell + ":" + vcell)
if err != nil {
return err
}
x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]

vcol, vrow, err := CellNameToCoordinates(vcell)
if err != nil {
return err
}

if hcol == vcol && hrow == vrow {
if x1 == x2 && y1 == y2 {
return err
}

// Correct the coordinate area, such correct C1:B3 to B1:C3.
if vcol < hcol {
hcol, vcol = vcol, hcol
if x2 < x1 {
x1, x2 = x2, x1
}

if vrow < hrow {
hrow, vrow = vrow, hrow
if y2 < y1 {
y1, y2 = y2, y1
}

hcell, _ = CoordinatesToCellName(hcol, hrow)
vcell, _ = CoordinatesToCellName(vcol, vrow)
hcell, _ = CoordinatesToCellName(x1, y1)
vcell, _ = CoordinatesToCellName(x2, y2)

xlsx, err := f.workSheetReader(sheet)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion rows.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ func (f *File) RemoveRow(sheet string, row int) error {
return err
}
if row > len(xlsx.SheetData.Row) {
return nil
return f.adjustHelper(sheet, rows, row, -1)
}
for rowIdx := range xlsx.SheetData.Row {
if xlsx.SheetData.Row[rowIdx].R == row {
Expand Down
Empty file modified styles.go
100755 → 100644
Empty file.
17 changes: 6 additions & 11 deletions table.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,29 +115,24 @@ func (f *File) addSheetTable(sheet string, rID int) {

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

// Correct table reference coordinate area, such correct C1:B3 to B1:C3.
hcell, err := CoordinatesToCellName(hcol, hrow)
ref, err := f.coordinatesToAreaRef([]int{x1, y1, x2, y2})
if err != nil {
return err
}
vcell, err := CoordinatesToCellName(vcol, vrow)
if err != nil {
return err
}
ref := hcell + ":" + vcell

var tableColumn []*xlsxTableColumn

idx := 0
for i := hcol; i <= vcol; i++ {
for i := x1; i <= x2; i++ {
idx++
cell, err := CoordinatesToCellName(i, hrow)
cell, err := CoordinatesToCellName(i, y1)
if err != nil {
return err
}
Expand Down
Empty file modified xmlChart.go
100755 → 100644
Empty file.
Loading

0 comments on commit 821632c

Please sign in to comment.