forked from p30928647/excelize
Resolve #570, flat columns for the column's operation
This commit is contained in:
parent
a691c1048d
commit
e51aff2d95
|
@ -14,7 +14,7 @@ os:
|
||||||
- osx
|
- osx
|
||||||
|
|
||||||
env:
|
env:
|
||||||
matrix:
|
jobs:
|
||||||
- GOARCH=amd64
|
- GOARCH=amd64
|
||||||
- GOARCH=386
|
- GOARCH=386
|
||||||
|
|
||||||
|
|
|
@ -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
123
col.go
|
@ -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.
|
||||||
//
|
//
|
||||||
|
|
|
@ -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")))
|
||||||
})
|
})
|
||||||
|
|
25
merge.go
25
merge.go
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
4
sheet.go
4
sheet.go
|
@ -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.
|
||||||
|
|
6
table.go
6
table.go
|
@ -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
|
||||||
//
|
//
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue