Resolve #570, flat columns for the column's operation

This commit is contained in:
xuri 2020-02-07 00:25:01 +08:00
parent a691c1048d
commit e51aff2d95
9 changed files with 116 additions and 66 deletions

View File

@ -14,7 +14,7 @@ os:
- osx - osx
env: env:
matrix: jobs:
- GOARCH=amd64 - GOARCH=amd64
- GOARCH=386 - GOARCH=386

View File

@ -234,7 +234,9 @@ By making a contribution to this project, I certify that:
Then you just add a line to every git commit message: Then you just add a line to every git commit message:
Signed-off-by: Ri Xu https://xuri.me ```text
Signed-off-by: Ri Xu https://xuri.me
```
Use your real name (sorry, no pseudonyms or anonymous contributions.) Use your real name (sorry, no pseudonyms or anonymous contributions.)
@ -460,4 +462,4 @@ Do not use package math/rand to generate keys, even
throwaway ones. Unseeded, the generator is completely predictable. throwaway ones. Unseeded, the generator is completely predictable.
Seeded with time.Nanoseconds(), there are just a few bits of entropy. Seeded with time.Nanoseconds(), there are just a few bits of entropy.
Instead, use crypto/rand's Reader, and if you need text, print to Instead, use crypto/rand's Reader, and if you need text, print to
hexadecimal or base64 hexadecimal or base64.

123
col.go
View File

@ -13,6 +13,8 @@ import (
"errors" "errors"
"math" "math"
"strings" "strings"
"github.com/mohae/deepcopy"
) )
// Define the default cell size and EMU unit of measurement. // Define the default cell size and EMU unit of measurement.
@ -59,7 +61,7 @@ func (f *File) GetColVisible(sheet, col string) (bool, error) {
// //
// err := f.SetColVisible("Sheet1", "D", false) // err := f.SetColVisible("Sheet1", "D", false)
// //
// Hide the columns from D to F (included) // Hide the columns from D to F (included):
// //
// err := f.SetColVisible("Sheet1", "D:F", false) // err := f.SetColVisible("Sheet1", "D:F", false)
// //
@ -87,23 +89,31 @@ func (f *File) SetColVisible(sheet, columns string, visible bool) error {
return err return err
} }
colData := xlsxCol{ colData := xlsxCol{
Min: min, Min: min,
Max: max, Max: max,
Width: 9, // default width Width: 9, // default width
Hidden: !visible, Hidden: !visible,
CustomWidth: true, CustomWidth: true,
} }
if xlsx.Cols != nil { if xlsx.Cols == nil {
xlsx.Cols.Col = append(xlsx.Cols.Col, colData)
} else {
cols := xlsxCols{} cols := xlsxCols{}
cols.Col = append(cols.Col, colData) cols.Col = append(cols.Col, colData)
xlsx.Cols = &cols xlsx.Cols = &cols
return nil
} }
xlsx.Cols.Col = flatCols(colData, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol {
fc.BestFit = c.BestFit
fc.Collapsed = c.Collapsed
fc.CustomWidth = c.CustomWidth
fc.OutlineLevel = c.OutlineLevel
fc.Phonetic = c.Phonetic
fc.Style = c.Style
fc.Width = c.Width
return fc
})
return nil return nil
} }
// GetColOutlineLevel provides a function to get outline level of a single // GetColOutlineLevel provides a function to get outline level of a single
// column by given worksheet name and column name. For example, get outline // column by given worksheet name and column name. For example, get outline
// level of column D in Sheet1: // level of column D in Sheet1:
@ -162,16 +172,16 @@ func (f *File) SetColOutlineLevel(sheet, col string, level uint8) error {
xlsx.Cols = &cols xlsx.Cols = &cols
return err return err
} }
for v := range xlsx.Cols.Col { xlsx.Cols.Col = flatCols(colData, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol {
if xlsx.Cols.Col[v].Min <= colNum && colNum <= xlsx.Cols.Col[v].Max { fc.BestFit = c.BestFit
colData = xlsx.Cols.Col[v] fc.Collapsed = c.Collapsed
} fc.CustomWidth = c.CustomWidth
} fc.Hidden = c.Hidden
colData.Min = colNum fc.Phonetic = c.Phonetic
colData.Max = colNum fc.Style = c.Style
colData.OutlineLevel = level fc.Width = c.Width
colData.CustomWidth = true return fc
xlsx.Cols.Col = append(xlsx.Cols.Col, colData) })
return err return err
} }
@ -214,21 +224,21 @@ func (f *File) SetColStyle(sheet, columns string, styleID int) error {
if xlsx.Cols == nil { if xlsx.Cols == nil {
xlsx.Cols = &xlsxCols{} xlsx.Cols = &xlsxCols{}
} }
var find bool xlsx.Cols.Col = flatCols(xlsxCol{
for idx, col := range xlsx.Cols.Col { Min: min,
if col.Min == min && col.Max == max { Max: max,
xlsx.Cols.Col[idx].Style = styleID Width: 9,
find = true Style: styleID,
} }, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol {
} fc.BestFit = c.BestFit
if !find { fc.Collapsed = c.Collapsed
xlsx.Cols.Col = append(xlsx.Cols.Col, xlsxCol{ fc.CustomWidth = c.CustomWidth
Min: min, fc.Hidden = c.Hidden
Max: max, fc.OutlineLevel = c.OutlineLevel
Width: 9, fc.Phonetic = c.Phonetic
Style: styleID, fc.Width = c.Width
}) return fc
} })
return nil return nil
} }
@ -261,16 +271,55 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) error
Width: width, Width: width,
CustomWidth: true, CustomWidth: true,
} }
if xlsx.Cols != nil { if xlsx.Cols == nil {
xlsx.Cols.Col = append(xlsx.Cols.Col, col)
} else {
cols := xlsxCols{} cols := xlsxCols{}
cols.Col = append(cols.Col, col) cols.Col = append(cols.Col, col)
xlsx.Cols = &cols xlsx.Cols = &cols
return err
} }
xlsx.Cols.Col = flatCols(col, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol {
fc.BestFit = c.BestFit
fc.Collapsed = c.Collapsed
fc.Hidden = c.Hidden
fc.OutlineLevel = c.OutlineLevel
fc.Phonetic = c.Phonetic
fc.Style = c.Style
return fc
})
return err return err
} }
// flatCols provides a method for the column's operation functions to flatten
// and check the worksheet columns.
func flatCols(col xlsxCol, cols []xlsxCol, replacer func(fc, c xlsxCol) xlsxCol) []xlsxCol {
fc := []xlsxCol{}
for i := col.Min; i <= col.Max; i++ {
c := deepcopy.Copy(col).(xlsxCol)
c.Min, c.Max = i, i
fc = append(fc, c)
}
inFlat := func(colID int, cols []xlsxCol) (int, bool) {
for idx, c := range cols {
if c.Max == colID && c.Min == colID {
return idx, true
}
}
return -1, false
}
for _, column := range cols {
for i := column.Min; i <= column.Max; i++ {
if idx, ok := inFlat(i, fc); ok {
fc[idx] = replacer(fc[idx], column)
continue
}
c := deepcopy.Copy(column).(xlsxCol)
c.Min, c.Max = i, i
fc = append(fc, c)
}
}
return fc
}
// positionObjectPixels calculate the vertices that define the position of a // positionObjectPixels calculate the vertices that define the position of a
// graphical object within the worksheet in pixels. // graphical object within the worksheet in pixels.
// //

View File

@ -31,7 +31,7 @@ func TestColumnVisibility(t *testing.T) {
assert.Equal(t, false, visible) assert.Equal(t, false, visible)
assert.NoError(t, err) assert.NoError(t, err)
// ...and displaying them back SetColVisible(...true) // ...and displaying them back SetColVisible(...true)
assert.NoError(t, f.SetColVisible("Sheet1", "F:V", true)) assert.NoError(t, f.SetColVisible("Sheet1", "V:F", true))
visible, err = f.GetColVisible("Sheet1", "F") visible, err = f.GetColVisible("Sheet1", "F")
assert.Equal(t, true, visible) assert.Equal(t, true, visible)
assert.NoError(t, err) assert.NoError(t, err)
@ -53,7 +53,7 @@ func TestColumnVisibility(t *testing.T) {
f.NewSheet("Sheet3") f.NewSheet("Sheet3")
assert.NoError(t, f.SetColVisible("Sheet3", "E", false)) assert.NoError(t, f.SetColVisible("Sheet3", "E", false))
assert.EqualError(t, f.SetColVisible("Sheet1", "A:-1", true), "invalid column name \"-1\"")
assert.EqualError(t, f.SetColVisible("SheetN", "E", false), "sheet SheetN is not exist") assert.EqualError(t, f.SetColVisible("SheetN", "E", false), "sheet SheetN is not exist")
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestColumnVisibility.xlsx"))) assert.NoError(t, f.SaveAs(filepath.Join("test", "TestColumnVisibility.xlsx")))
}) })

View File

@ -22,20 +22,17 @@ import (
// If you create a merged cell that overlaps with another existing merged cell, // If you create a merged cell that overlaps with another existing merged cell,
// those merged cells that already exist will be removed. // those merged cells that already exist will be removed.
// //
// B1(x1,y1) D1(x2,y1) // B1(x1,y1) D1(x2,y1)
// +--------------------------------+ // +------------------------+
// | | // | |
// | | // A4(x3,y3) | C4(x4,y3) |
// A4(x3,y3) | C4(x4,y3) | // +------------------------+ |
// +-----------------------------+ | // | | | |
// | | | | // | |B5(x1,y2) | D5(x2,y2)|
// | | | | // | +------------------------+
// | |B5(x1,y2) | D5(x2,y2)| // | |
// | +--------------------------------+ // |A8(x3,y4) C8(x4,y4)|
// | | // +------------------------+
// | |
// |A8(x3,y4) C8(x4,y4)|
// +-----------------------------+
// //
func (f *File) MergeCell(sheet, hcell, vcell string) error { func (f *File) MergeCell(sheet, hcell, vcell string) error {
rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell) rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell)

View File

@ -462,8 +462,8 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte, error) {
return f.getPicture(row, col, drawingXML, drawingRelationships) return f.getPicture(row, col, drawingXML, drawingRelationships)
} }
// DeletePicture provides a function to delete chart in XLSX by given // DeletePicture provides a function to delete charts in XLSX by given
// worksheet and cell name. Note that the image file won't deleted from the // worksheet and cell name. Note that the image file won't be deleted from the
// document currently. // document currently.
func (f *File) DeletePicture(sheet, cell string) (err error) { func (f *File) DeletePicture(sheet, cell string) (err error) {
col, row, err := CellNameToCoordinates(cell) col, row, err := CellNameToCoordinates(cell)

View File

@ -287,8 +287,8 @@ func (f *File) GetActiveSheetIndex() int {
return 0 return 0
} }
// SetSheetName provides a function to set the worksheet name be given old and // SetSheetName provides a function to set the worksheet name by given old and
// new worksheet name. Maximum 31 characters are allowed in sheet title and // new worksheet names. Maximum 31 characters are allowed in sheet title and
// this function only changes the name of the sheet and will not update the // this function only changes the name of the sheet and will not update the
// sheet name in the formula or reference associated with the cell. So there // sheet name in the formula or reference associated with the cell. So there
// may be problem formula error or reference missing. // may be problem formula error or reference missing.

View File

@ -39,8 +39,10 @@ func parseFormatTableSet(formatSet string) (*formatTable, error) {
// //
// err := f.AddTable("Sheet2", "F2", "H6", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`) // err := f.AddTable("Sheet2", "F2", "H6", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`)
// //
// Note that the table at least two lines include string type header. Multiple // Note that the table must be at least two lines including the header. The
// tables coordinate areas can't have an intersection. // header cells must contain strings and must be unique, and must set the
// header row data of the table before calling the AddTable function. Multiple
// tables coordinate areas that can't have an intersection.
// //
// table_name: The name of the table, in the same worksheet name of the table should be unique // table_name: The name of the table, in the same worksheet name of the table should be unique
// //

View File

@ -278,15 +278,15 @@ type xlsxCols struct {
// width and column formatting for one or more columns of the worksheet. // width and column formatting for one or more columns of the worksheet.
type xlsxCol struct { type xlsxCol struct {
BestFit bool `xml:"bestFit,attr,omitempty"` BestFit bool `xml:"bestFit,attr,omitempty"`
Collapsed bool `xml:"collapsed,attr"` Collapsed bool `xml:"collapsed,attr,omitempty"`
CustomWidth bool `xml:"customWidth,attr,omitempty"` CustomWidth bool `xml:"customWidth,attr,omitempty"`
Hidden bool `xml:"hidden,attr"` Hidden bool `xml:"hidden,attr,omitempty"`
Max int `xml:"max,attr"` Max int `xml:"max,attr"`
Min int `xml:"min,attr"` Min int `xml:"min,attr"`
OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"` OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"`
Phonetic bool `xml:"phonetic,attr,omitempty"` Phonetic bool `xml:"phonetic,attr,omitempty"`
Style int `xml:"style,attr"` Style int `xml:"style,attr,omitempty"`
Width float64 `xml:"width,attr"` Width float64 `xml:"width,attr,omitempty"`
} }
// xlsxDimension directly maps the dimension element in the namespace // xlsxDimension directly maps the dimension element in the namespace