forked from p30928647/excelize
This optimizes internal functions signature and mutex declarations
This commit is contained in:
parent
787453c6f0
commit
93c72b4d55
|
@ -60,8 +60,8 @@ func (f *File) adjustHelper(sheet string, dir adjustDirection, num, offset int)
|
||||||
if err = f.adjustCalcChain(dir, num, offset, sheetID); err != nil {
|
if err = f.adjustCalcChain(dir, num, offset, sheetID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
checkSheet(ws)
|
ws.checkSheet()
|
||||||
_ = checkRow(ws)
|
_ = ws.checkRow()
|
||||||
|
|
||||||
if ws.MergeCells != nil && len(ws.MergeCells.Cells) == 0 {
|
if ws.MergeCells != nil && len(ws.MergeCells.Cells) == 0 {
|
||||||
ws.MergeCells = nil
|
ws.MergeCells = nil
|
||||||
|
|
10
calc.go
10
calc.go
|
@ -215,7 +215,7 @@ var (
|
||||||
|
|
||||||
// calcContext defines the formula execution context.
|
// calcContext defines the formula execution context.
|
||||||
type calcContext struct {
|
type calcContext struct {
|
||||||
sync.Mutex
|
mu sync.Mutex
|
||||||
entry string
|
entry string
|
||||||
maxCalcIterations uint
|
maxCalcIterations uint
|
||||||
iterations map[string]uint
|
iterations map[string]uint
|
||||||
|
@ -1553,19 +1553,19 @@ func (f *File) cellResolver(ctx *calcContext, sheet, cell string) (formulaArg, e
|
||||||
)
|
)
|
||||||
ref := fmt.Sprintf("%s!%s", sheet, cell)
|
ref := fmt.Sprintf("%s!%s", sheet, cell)
|
||||||
if formula, _ := f.GetCellFormula(sheet, cell); len(formula) != 0 {
|
if formula, _ := f.GetCellFormula(sheet, cell); len(formula) != 0 {
|
||||||
ctx.Lock()
|
ctx.mu.Lock()
|
||||||
if ctx.entry != ref {
|
if ctx.entry != ref {
|
||||||
if ctx.iterations[ref] <= f.options.MaxCalcIterations {
|
if ctx.iterations[ref] <= f.options.MaxCalcIterations {
|
||||||
ctx.iterations[ref]++
|
ctx.iterations[ref]++
|
||||||
ctx.Unlock()
|
ctx.mu.Unlock()
|
||||||
arg, _ = f.calcCellValue(ctx, sheet, cell)
|
arg, _ = f.calcCellValue(ctx, sheet, cell)
|
||||||
ctx.iterationsCache[ref] = arg
|
ctx.iterationsCache[ref] = arg
|
||||||
return arg, nil
|
return arg, nil
|
||||||
}
|
}
|
||||||
ctx.Unlock()
|
ctx.mu.Unlock()
|
||||||
return ctx.iterationsCache[ref], nil
|
return ctx.iterationsCache[ref], nil
|
||||||
}
|
}
|
||||||
ctx.Unlock()
|
ctx.mu.Unlock()
|
||||||
}
|
}
|
||||||
if value, err = f.GetCellValue(sheet, cell, Options{RawCellValue: true}); err != nil {
|
if value, err = f.GetCellValue(sheet, cell, Options{RawCellValue: true}); err != nil {
|
||||||
return arg, err
|
return arg, err
|
||||||
|
|
|
@ -58,8 +58,8 @@ func (f *File) deleteCalcChain(index int, cell string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content.Lock()
|
content.mu.Lock()
|
||||||
defer content.Unlock()
|
defer content.mu.Unlock()
|
||||||
for k, v := range content.Overrides {
|
for k, v := range content.Overrides {
|
||||||
if v.PartName == "/xl/calcChain.xml" {
|
if v.PartName == "/xl/calcChain.xml" {
|
||||||
content.Overrides = append(content.Overrides[:k], content.Overrides[k+1:]...)
|
content.Overrides = append(content.Overrides[:k], content.Overrides[k+1:]...)
|
||||||
|
|
92
cell.go
92
cell.go
|
@ -236,13 +236,13 @@ func (f *File) setCellTimeFunc(sheet, cell string, value time.Time) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c, col, row, err := f.prepareCell(ws, cell)
|
c, col, row, err := ws.prepareCell(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
c.S = ws.prepareCellStyle(col, row, c.S)
|
||||||
ws.Unlock()
|
ws.mu.Unlock()
|
||||||
var date1904, isNum bool
|
var date1904, isNum bool
|
||||||
wb, err := f.workbookReader()
|
wb, err := f.workbookReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -292,13 +292,13 @@ func (f *File) SetCellInt(sheet, cell string, value int) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c, col, row, err := f.prepareCell(ws, cell)
|
c, col, row, err := ws.prepareCell(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
c.S = ws.prepareCellStyle(col, row, c.S)
|
||||||
c.T, c.V = setCellInt(value)
|
c.T, c.V = setCellInt(value)
|
||||||
c.IS = nil
|
c.IS = nil
|
||||||
return f.removeFormula(c, ws, sheet)
|
return f.removeFormula(c, ws, sheet)
|
||||||
|
@ -318,13 +318,13 @@ func (f *File) SetCellBool(sheet, cell string, value bool) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c, col, row, err := f.prepareCell(ws, cell)
|
c, col, row, err := ws.prepareCell(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
c.S = ws.prepareCellStyle(col, row, c.S)
|
||||||
c.T, c.V = setCellBool(value)
|
c.T, c.V = setCellBool(value)
|
||||||
c.IS = nil
|
c.IS = nil
|
||||||
return f.removeFormula(c, ws, sheet)
|
return f.removeFormula(c, ws, sheet)
|
||||||
|
@ -355,13 +355,13 @@ func (f *File) SetCellFloat(sheet, cell string, value float64, precision, bitSiz
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c, col, row, err := f.prepareCell(ws, cell)
|
c, col, row, err := ws.prepareCell(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
c.S = ws.prepareCellStyle(col, row, c.S)
|
||||||
c.T, c.V = setCellFloat(value, precision, bitSize)
|
c.T, c.V = setCellFloat(value, precision, bitSize)
|
||||||
c.IS = nil
|
c.IS = nil
|
||||||
return f.removeFormula(c, ws, sheet)
|
return f.removeFormula(c, ws, sheet)
|
||||||
|
@ -381,13 +381,13 @@ func (f *File) SetCellStr(sheet, cell, value string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c, col, row, err := f.prepareCell(ws, cell)
|
c, col, row, err := ws.prepareCell(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
c.S = ws.prepareCellStyle(col, row, c.S)
|
||||||
if c.T, c.V, err = f.setCellString(value); err != nil {
|
if c.T, c.V, err = f.setCellString(value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -413,8 +413,8 @@ func (f *File) setCellString(value string) (t, v string, err error) {
|
||||||
// sharedStringsLoader load shared string table from system temporary file to
|
// sharedStringsLoader load shared string table from system temporary file to
|
||||||
// memory, and reset shared string table for reader.
|
// memory, and reset shared string table for reader.
|
||||||
func (f *File) sharedStringsLoader() (err error) {
|
func (f *File) sharedStringsLoader() (err error) {
|
||||||
f.Lock()
|
f.mu.Lock()
|
||||||
defer f.Unlock()
|
defer f.mu.Unlock()
|
||||||
if path, ok := f.tempFiles.Load(defaultXMLPathSharedStrings); ok {
|
if path, ok := f.tempFiles.Load(defaultXMLPathSharedStrings); ok {
|
||||||
f.Pkg.Store(defaultXMLPathSharedStrings, f.readBytes(defaultXMLPathSharedStrings))
|
f.Pkg.Store(defaultXMLPathSharedStrings, f.readBytes(defaultXMLPathSharedStrings))
|
||||||
f.tempFiles.Delete(defaultXMLPathSharedStrings)
|
f.tempFiles.Delete(defaultXMLPathSharedStrings)
|
||||||
|
@ -443,8 +443,8 @@ func (f *File) setSharedString(val string) (int, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
f.Lock()
|
f.mu.Lock()
|
||||||
defer f.Unlock()
|
defer f.mu.Unlock()
|
||||||
if i, ok := f.sharedStringsMap[val]; ok {
|
if i, ok := f.sharedStringsMap[val]; ok {
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
@ -558,8 +558,8 @@ func (c *xlsxC) getCellDate(f *File, raw bool) (string, error) {
|
||||||
// intended to be used with for range on rows an argument with the spreadsheet
|
// intended to be used with for range on rows an argument with the spreadsheet
|
||||||
// opened file.
|
// opened file.
|
||||||
func (c *xlsxC) getValueFrom(f *File, d *xlsxSST, raw bool) (string, error) {
|
func (c *xlsxC) getValueFrom(f *File, d *xlsxSST, raw bool) (string, error) {
|
||||||
f.Lock()
|
f.mu.Lock()
|
||||||
defer f.Unlock()
|
defer f.mu.Unlock()
|
||||||
switch c.T {
|
switch c.T {
|
||||||
case "b":
|
case "b":
|
||||||
return c.getCellBool(f, raw)
|
return c.getCellBool(f, raw)
|
||||||
|
@ -600,13 +600,13 @@ func (f *File) SetCellDefault(sheet, cell, value string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c, col, row, err := f.prepareCell(ws, cell)
|
c, col, row, err := ws.prepareCell(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
c.S = ws.prepareCellStyle(col, row, c.S)
|
||||||
c.setCellDefault(value)
|
c.setCellDefault(value)
|
||||||
return f.removeFormula(c, ws, sheet)
|
return f.removeFormula(c, ws, sheet)
|
||||||
}
|
}
|
||||||
|
@ -718,7 +718,7 @@ func (f *File) SetCellFormula(sheet, cell, formula string, opts ...FormulaOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c, _, _, err := f.prepareCell(ws, cell)
|
c, _, _, err := ws.prepareCell(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -763,7 +763,7 @@ func (ws *xlsxWorksheet) setSharedFormula(ref string) error {
|
||||||
cnt := ws.countSharedFormula()
|
cnt := ws.countSharedFormula()
|
||||||
for c := coordinates[0]; c <= coordinates[2]; c++ {
|
for c := coordinates[0]; c <= coordinates[2]; c++ {
|
||||||
for r := coordinates[1]; r <= coordinates[3]; r++ {
|
for r := coordinates[1]; r <= coordinates[3]; r++ {
|
||||||
prepareSheetXML(ws, c, r)
|
ws.prepareSheetXML(c, r)
|
||||||
cell := &ws.SheetData.Row[r-1].C[c-1]
|
cell := &ws.SheetData.Row[r-1].C[c-1]
|
||||||
if cell.F == nil {
|
if cell.F == nil {
|
||||||
cell.F = &xlsxF{}
|
cell.F = &xlsxF{}
|
||||||
|
@ -867,7 +867,7 @@ func (f *File) SetCellHyperLink(sheet, cell, link, linkType string, opts ...Hype
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cell, err = f.mergeCellsParser(ws, cell); err != nil {
|
if cell, err = ws.mergeCellsParser(cell); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -944,7 +944,7 @@ func (f *File) GetCellRichText(sheet, cell string) (runs []RichTextRun, err erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c, _, _, err := f.prepareCell(ws, cell)
|
c, _, _, err := ws.prepareCell(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1171,14 +1171,14 @@ func (f *File) SetCellRichText(sheet, cell string, runs []RichTextRun) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c, col, row, err := f.prepareCell(ws, cell)
|
c, col, row, err := ws.prepareCell(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := f.sharedStringsLoader(); err != nil {
|
if err := f.sharedStringsLoader(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
c.S = ws.prepareCellStyle(col, row, c.S)
|
||||||
si := xlsxSI{}
|
si := xlsxSI{}
|
||||||
sst, err := f.sharedStringsReader()
|
sst, err := f.sharedStringsReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1252,9 +1252,9 @@ func (f *File) setSheetCells(sheet, cell string, slice interface{}, dir adjustDi
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCellInfo does common preparation for all set cell value functions.
|
// getCellInfo does common preparation for all set cell value functions.
|
||||||
func (f *File) prepareCell(ws *xlsxWorksheet, cell string) (*xlsxC, int, int, error) {
|
func (ws *xlsxWorksheet) prepareCell(cell string) (*xlsxC, int, int, error) {
|
||||||
var err error
|
var err error
|
||||||
cell, err = f.mergeCellsParser(ws, cell)
|
cell, err = ws.mergeCellsParser(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
@ -1263,9 +1263,9 @@ func (f *File) prepareCell(ws *xlsxWorksheet, cell string) (*xlsxC, int, int, er
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareSheetXML(ws, col, row)
|
ws.prepareSheetXML(col, row)
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
return &ws.SheetData.Row[row-1].C[col-1], col, row, err
|
return &ws.SheetData.Row[row-1].C[col-1], col, row, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1277,7 +1277,7 @@ func (f *File) getCellStringFunc(sheet, cell string, fn func(x *xlsxWorksheet, c
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
cell, err = f.mergeCellsParser(ws, cell)
|
cell, err = ws.mergeCellsParser(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -1286,8 +1286,8 @@ func (f *File) getCellStringFunc(sheet, cell string, fn func(x *xlsxWorksheet, c
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
|
|
||||||
lastRowNum := 0
|
lastRowNum := 0
|
||||||
if l := len(ws.SheetData.Row); l > 0 {
|
if l := len(ws.SheetData.Row); l > 0 {
|
||||||
|
@ -1366,7 +1366,7 @@ func (f *File) formattedValue(c *xlsxC, raw bool, cellType CellType) (string, er
|
||||||
|
|
||||||
// prepareCellStyle provides a function to prepare style index of cell in
|
// prepareCellStyle provides a function to prepare style index of cell in
|
||||||
// worksheet by given column index and style index.
|
// worksheet by given column index and style index.
|
||||||
func (f *File) prepareCellStyle(ws *xlsxWorksheet, col, row, style int) int {
|
func (ws *xlsxWorksheet) prepareCellStyle(col, row, style int) int {
|
||||||
if style != 0 {
|
if style != 0 {
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
|
@ -1387,7 +1387,7 @@ func (f *File) prepareCellStyle(ws *xlsxWorksheet, col, row, style int) int {
|
||||||
|
|
||||||
// mergeCellsParser provides a function to check merged cells in worksheet by
|
// mergeCellsParser provides a function to check merged cells in worksheet by
|
||||||
// given cell reference.
|
// given cell reference.
|
||||||
func (f *File) mergeCellsParser(ws *xlsxWorksheet, cell string) (string, error) {
|
func (ws *xlsxWorksheet) mergeCellsParser(cell string) (string, error) {
|
||||||
cell = strings.ToUpper(cell)
|
cell = strings.ToUpper(cell)
|
||||||
col, row, err := CellNameToCoordinates(cell)
|
col, row, err := CellNameToCoordinates(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
44
col.go
44
col.go
|
@ -215,11 +215,11 @@ func (f *File) Cols(sheet string) (*Cols, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrSheetNotExist{sheet}
|
return nil, ErrSheetNotExist{sheet}
|
||||||
}
|
}
|
||||||
if ws, ok := f.Sheet.Load(name); ok && ws != nil {
|
if worksheet, ok := f.Sheet.Load(name); ok && worksheet != nil {
|
||||||
worksheet := ws.(*xlsxWorksheet)
|
ws := worksheet.(*xlsxWorksheet)
|
||||||
worksheet.Lock()
|
ws.mu.Lock()
|
||||||
defer worksheet.Unlock()
|
defer ws.mu.Unlock()
|
||||||
output, _ := xml.Marshal(worksheet)
|
output, _ := xml.Marshal(ws)
|
||||||
f.saveFileList(name, f.replaceNameSpaceBytes(name, output))
|
f.saveFileList(name, f.replaceNameSpaceBytes(name, output))
|
||||||
}
|
}
|
||||||
var colIterator columnXMLIterator
|
var colIterator columnXMLIterator
|
||||||
|
@ -261,8 +261,8 @@ func (f *File) GetColVisible(sheet, col string) (bool, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
if ws.Cols == nil {
|
if ws.Cols == nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
@ -295,8 +295,8 @@ func (f *File) SetColVisible(sheet, columns string, visible bool) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
colData := xlsxCol{
|
colData := xlsxCol{
|
||||||
Min: min,
|
Min: min,
|
||||||
Max: max,
|
Max: max,
|
||||||
|
@ -432,17 +432,17 @@ func (f *File) SetColStyle(sheet, columns string, styleID int) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.Lock()
|
s.mu.Lock()
|
||||||
if styleID < 0 || s.CellXfs == nil || len(s.CellXfs.Xf) <= styleID {
|
if styleID < 0 || s.CellXfs == nil || len(s.CellXfs.Xf) <= styleID {
|
||||||
s.Unlock()
|
s.mu.Unlock()
|
||||||
return newInvalidStyleID(styleID)
|
return newInvalidStyleID(styleID)
|
||||||
}
|
}
|
||||||
s.Unlock()
|
s.mu.Unlock()
|
||||||
ws, err := f.workSheetReader(sheet)
|
ws, err := f.workSheetReader(sheet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
if ws.Cols == nil {
|
if ws.Cols == nil {
|
||||||
ws.Cols = &xlsxCols{}
|
ws.Cols = &xlsxCols{}
|
||||||
}
|
}
|
||||||
|
@ -461,7 +461,7 @@ func (f *File) SetColStyle(sheet, columns string, styleID int) error {
|
||||||
fc.Width = c.Width
|
fc.Width = c.Width
|
||||||
return fc
|
return fc
|
||||||
})
|
})
|
||||||
ws.Unlock()
|
ws.mu.Unlock()
|
||||||
if rows := len(ws.SheetData.Row); rows > 0 {
|
if rows := len(ws.SheetData.Row); rows > 0 {
|
||||||
for col := min; col <= max; col++ {
|
for col := min; col <= max; col++ {
|
||||||
from, _ := CoordinatesToCellName(col, 1)
|
from, _ := CoordinatesToCellName(col, 1)
|
||||||
|
@ -488,8 +488,8 @@ func (f *File) SetColWidth(sheet, startCol, endCol string, width float64) error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
col := xlsxCol{
|
col := xlsxCol{
|
||||||
Min: min,
|
Min: min,
|
||||||
Max: max,
|
Max: max,
|
||||||
|
@ -634,8 +634,8 @@ func (f *File) positionObjectPixels(sheet string, col, row, x1, y1, width, heigh
|
||||||
// sheet name and column number.
|
// sheet name and column number.
|
||||||
func (f *File) getColWidth(sheet string, col int) int {
|
func (f *File) getColWidth(sheet string, col int) int {
|
||||||
ws, _ := f.workSheetReader(sheet)
|
ws, _ := f.workSheetReader(sheet)
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
if ws.Cols != nil {
|
if ws.Cols != nil {
|
||||||
var width float64
|
var width float64
|
||||||
for _, v := range ws.Cols.Col {
|
for _, v := range ws.Cols.Col {
|
||||||
|
@ -663,8 +663,8 @@ func (f *File) GetColStyle(sheet, col string) (int, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return styleID, err
|
return styleID, err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
if ws.Cols != nil {
|
if ws.Cols != nil {
|
||||||
for _, v := range ws.Cols.Col {
|
for _, v := range ws.Cols.Col {
|
||||||
if v.Min <= colNum && colNum <= v.Max {
|
if v.Min <= colNum && colNum <= v.Max {
|
||||||
|
@ -686,8 +686,8 @@ func (f *File) GetColWidth(sheet, col string) (float64, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return defaultColWidth, err
|
return defaultColWidth, err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
if ws.Cols != nil {
|
if ws.Cols != nil {
|
||||||
var width float64
|
var width float64
|
||||||
for _, v := range ws.Cols.Col {
|
for _, v := range ws.Cols.Col {
|
||||||
|
|
|
@ -68,8 +68,8 @@ func (f *File) GetComments(sheet string) ([]Comment, error) {
|
||||||
func (f *File) getSheetComments(sheetFile string) string {
|
func (f *File) getSheetComments(sheetFile string) string {
|
||||||
rels, _ := f.relsReader("xl/worksheets/_rels/" + sheetFile + ".rels")
|
rels, _ := f.relsReader("xl/worksheets/_rels/" + sheetFile + ".rels")
|
||||||
if sheetRels := rels; sheetRels != nil {
|
if sheetRels := rels; sheetRels != nil {
|
||||||
sheetRels.Lock()
|
sheetRels.mu.Lock()
|
||||||
defer sheetRels.Unlock()
|
defer sheetRels.mu.Unlock()
|
||||||
for _, v := range sheetRels.Relationships {
|
for _, v := range sheetRels.Relationships {
|
||||||
if v.Type == SourceRelationshipComments {
|
if v.Type == SourceRelationshipComments {
|
||||||
return v.Target
|
return v.Target
|
||||||
|
|
|
@ -1285,8 +1285,8 @@ func (f *File) drawingParser(path string) (*xlsxWsDr, int, error) {
|
||||||
if drawing, ok := f.Drawings.Load(path); ok && drawing != nil {
|
if drawing, ok := f.Drawings.Load(path); ok && drawing != nil {
|
||||||
wsDr = drawing.(*xlsxWsDr)
|
wsDr = drawing.(*xlsxWsDr)
|
||||||
}
|
}
|
||||||
wsDr.Lock()
|
wsDr.mu.Lock()
|
||||||
defer wsDr.Unlock()
|
defer wsDr.mu.Unlock()
|
||||||
return wsDr, len(wsDr.OneCellAnchor) + len(wsDr.TwoCellAnchor) + 2, nil
|
return wsDr, len(wsDr.OneCellAnchor) + len(wsDr.TwoCellAnchor) + 2, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
excelize.go
32
excelize.go
|
@ -28,7 +28,7 @@ import (
|
||||||
|
|
||||||
// File define a populated spreadsheet file struct.
|
// File define a populated spreadsheet file struct.
|
||||||
type File struct {
|
type File struct {
|
||||||
sync.Mutex
|
mu sync.Mutex
|
||||||
options *Options
|
options *Options
|
||||||
xmlAttr map[string][]xml.Attr
|
xmlAttr map[string][]xml.Attr
|
||||||
checked map[string]bool
|
checked map[string]bool
|
||||||
|
@ -234,8 +234,8 @@ func (f *File) setDefaultTimeStyle(sheet, cell string, format int) error {
|
||||||
// workSheetReader provides a function to get the pointer to the structure
|
// workSheetReader provides a function to get the pointer to the structure
|
||||||
// after deserialization by given worksheet name.
|
// after deserialization by given worksheet name.
|
||||||
func (f *File) workSheetReader(sheet string) (ws *xlsxWorksheet, err error) {
|
func (f *File) workSheetReader(sheet string) (ws *xlsxWorksheet, err error) {
|
||||||
f.Lock()
|
f.mu.Lock()
|
||||||
defer f.Unlock()
|
defer f.mu.Unlock()
|
||||||
var (
|
var (
|
||||||
name string
|
name string
|
||||||
ok bool
|
ok bool
|
||||||
|
@ -271,8 +271,8 @@ func (f *File) workSheetReader(sheet string) (ws *xlsxWorksheet, err error) {
|
||||||
f.checked = make(map[string]bool)
|
f.checked = make(map[string]bool)
|
||||||
}
|
}
|
||||||
if ok = f.checked[name]; !ok {
|
if ok = f.checked[name]; !ok {
|
||||||
checkSheet(ws)
|
ws.checkSheet()
|
||||||
if err = checkRow(ws); err != nil {
|
if err = ws.checkRow(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.checked[name] = true
|
f.checked[name] = true
|
||||||
|
@ -283,7 +283,7 @@ func (f *File) workSheetReader(sheet string) (ws *xlsxWorksheet, err error) {
|
||||||
|
|
||||||
// checkSheet provides a function to fill each row element and make that is
|
// checkSheet provides a function to fill each row element and make that is
|
||||||
// continuous in a worksheet of XML.
|
// continuous in a worksheet of XML.
|
||||||
func checkSheet(ws *xlsxWorksheet) {
|
func (ws *xlsxWorksheet) checkSheet() {
|
||||||
var row int
|
var row int
|
||||||
var r0 xlsxRow
|
var r0 xlsxRow
|
||||||
for i, r := range ws.SheetData.Row {
|
for i, r := range ws.SheetData.Row {
|
||||||
|
@ -319,13 +319,13 @@ func checkSheet(ws *xlsxWorksheet) {
|
||||||
for i := 1; i <= row; i++ {
|
for i := 1; i <= row; i++ {
|
||||||
sheetData.Row[i-1].R = i
|
sheetData.Row[i-1].R = i
|
||||||
}
|
}
|
||||||
checkSheetR0(ws, &sheetData, &r0)
|
ws.checkSheetR0(&sheetData, &r0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkSheetR0 handle the row element with r="0" attribute, cells in this row
|
// checkSheetR0 handle the row element with r="0" attribute, cells in this row
|
||||||
// could be disorderly, the cell in this row can be used as the value of
|
// could be disorderly, the cell in this row can be used as the value of
|
||||||
// which cell is empty in the normal rows.
|
// which cell is empty in the normal rows.
|
||||||
func checkSheetR0(ws *xlsxWorksheet, sheetData *xlsxSheetData, r0 *xlsxRow) {
|
func (ws *xlsxWorksheet) checkSheetR0(sheetData *xlsxSheetData, r0 *xlsxRow) {
|
||||||
for _, cell := range r0.C {
|
for _, cell := range r0.C {
|
||||||
if col, row, err := CellNameToCoordinates(cell.R); err == nil {
|
if col, row, err := CellNameToCoordinates(cell.R); err == nil {
|
||||||
rows, rowIdx := len(sheetData.Row), row-1
|
rows, rowIdx := len(sheetData.Row), row-1
|
||||||
|
@ -351,8 +351,8 @@ func (f *File) setRels(rID, relPath, relType, target, targetMode string) int {
|
||||||
if rels == nil || rID == "" {
|
if rels == nil || rID == "" {
|
||||||
return f.addRels(relPath, relType, target, targetMode)
|
return f.addRels(relPath, relType, target, targetMode)
|
||||||
}
|
}
|
||||||
rels.Lock()
|
rels.mu.Lock()
|
||||||
defer rels.Unlock()
|
defer rels.mu.Unlock()
|
||||||
var ID int
|
var ID int
|
||||||
for i, rel := range rels.Relationships {
|
for i, rel := range rels.Relationships {
|
||||||
if rel.ID == rID {
|
if rel.ID == rID {
|
||||||
|
@ -376,8 +376,8 @@ func (f *File) addRels(relPath, relType, target, targetMode string) int {
|
||||||
if rels == nil {
|
if rels == nil {
|
||||||
rels = &xlsxRelationships{}
|
rels = &xlsxRelationships{}
|
||||||
}
|
}
|
||||||
rels.Lock()
|
rels.mu.Lock()
|
||||||
defer rels.Unlock()
|
defer rels.mu.Unlock()
|
||||||
var rID int
|
var rID int
|
||||||
for idx, rel := range rels.Relationships {
|
for idx, rel := range rels.Relationships {
|
||||||
ID, _ := strconv.Atoi(strings.TrimPrefix(rel.ID, "rId"))
|
ID, _ := strconv.Atoi(strings.TrimPrefix(rel.ID, "rId"))
|
||||||
|
@ -490,8 +490,8 @@ func (f *File) AddVBAProject(file []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rels.Lock()
|
rels.mu.Lock()
|
||||||
defer rels.Unlock()
|
defer rels.mu.Unlock()
|
||||||
var rID int
|
var rID int
|
||||||
var ok bool
|
var ok bool
|
||||||
for _, rel := range rels.Relationships {
|
for _, rel := range rels.Relationships {
|
||||||
|
@ -524,8 +524,8 @@ func (f *File) setContentTypePartProjectExtensions(contentType string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content.Lock()
|
content.mu.Lock()
|
||||||
defer content.Unlock()
|
defer content.mu.Unlock()
|
||||||
for _, v := range content.Defaults {
|
for _, v := range content.Defaults {
|
||||||
if v.Extension == "bin" {
|
if v.Extension == "bin" {
|
||||||
ok = true
|
ok = true
|
||||||
|
|
8
merge.go
8
merge.go
|
@ -64,8 +64,8 @@ func (f *File) MergeCell(sheet, hCell, vCell string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
ref := hCell + ":" + vCell
|
ref := hCell + ":" + vCell
|
||||||
if ws.MergeCells != nil {
|
if ws.MergeCells != nil {
|
||||||
ws.MergeCells.Cells = append(ws.MergeCells.Cells, &xlsxMergeCell{Ref: ref, rect: rect})
|
ws.MergeCells.Cells = append(ws.MergeCells.Cells, &xlsxMergeCell{Ref: ref, rect: rect})
|
||||||
|
@ -87,8 +87,8 @@ func (f *File) UnmergeCell(sheet, hCell, vCell string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
rect1, err := rangeRefToCoordinates(hCell + ":" + vCell)
|
rect1, err := rangeRefToCoordinates(hCell + ":" + vCell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -207,7 +207,7 @@ func TestFlatMergedCells(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeCellsParser(t *testing.T) {
|
func TestMergeCellsParser(t *testing.T) {
|
||||||
f := NewFile()
|
ws := &xlsxWorksheet{MergeCells: &xlsxMergeCells{Cells: []*xlsxMergeCell{nil}}}
|
||||||
_, err := f.mergeCellsParser(&xlsxWorksheet{MergeCells: &xlsxMergeCells{Cells: []*xlsxMergeCell{nil}}}, "A1")
|
_, err := ws.mergeCellsParser("A1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
36
picture.go
36
picture.go
|
@ -216,7 +216,7 @@ func (f *File) AddPictureFromBytes(sheet, cell string, pic *Picture) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
// Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder.
|
// Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder.
|
||||||
drawingID := f.countDrawings() + 1
|
drawingID := f.countDrawings() + 1
|
||||||
drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
|
drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
|
||||||
|
@ -231,7 +231,7 @@ func (f *File) AddPictureFromBytes(sheet, cell string, pic *Picture) error {
|
||||||
}
|
}
|
||||||
drawingHyperlinkRID = f.addRels(drawingRels, SourceRelationshipHyperLink, options.Hyperlink, hyperlinkType)
|
drawingHyperlinkRID = f.addRels(drawingRels, SourceRelationshipHyperLink, options.Hyperlink, hyperlinkType)
|
||||||
}
|
}
|
||||||
ws.Unlock()
|
ws.mu.Unlock()
|
||||||
err = f.addDrawingPicture(sheet, drawingXML, cell, ext, drawingRID, drawingHyperlinkRID, img, options)
|
err = f.addDrawingPicture(sheet, drawingXML, cell, ext, drawingRID, drawingHyperlinkRID, img, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -256,8 +256,8 @@ func (f *File) deleteSheetRelationships(sheet, rID string) {
|
||||||
if sheetRels == nil {
|
if sheetRels == nil {
|
||||||
sheetRels = &xlsxRelationships{}
|
sheetRels = &xlsxRelationships{}
|
||||||
}
|
}
|
||||||
sheetRels.Lock()
|
sheetRels.mu.Lock()
|
||||||
defer sheetRels.Unlock()
|
defer sheetRels.mu.Unlock()
|
||||||
for k, v := range sheetRels.Relationships {
|
for k, v := range sheetRels.Relationships {
|
||||||
if v.ID == rID {
|
if v.ID == rID {
|
||||||
sheetRels.Relationships = append(sheetRels.Relationships[:k], sheetRels.Relationships[k+1:]...)
|
sheetRels.Relationships = append(sheetRels.Relationships[:k], sheetRels.Relationships[k+1:]...)
|
||||||
|
@ -391,8 +391,8 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, ext string, rID, hyper
|
||||||
FLocksWithSheet: *opts.Locked,
|
FLocksWithSheet: *opts.Locked,
|
||||||
FPrintsWithSheet: *opts.PrintObject,
|
FPrintsWithSheet: *opts.PrintObject,
|
||||||
}
|
}
|
||||||
content.Lock()
|
content.mu.Lock()
|
||||||
defer content.Unlock()
|
defer content.mu.Unlock()
|
||||||
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
||||||
f.Drawings.Store(drawingXML, content)
|
f.Drawings.Store(drawingXML, content)
|
||||||
return err
|
return err
|
||||||
|
@ -447,8 +447,8 @@ func (f *File) setContentTypePartImageExtensions() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content.Lock()
|
content.mu.Lock()
|
||||||
defer content.Unlock()
|
defer content.mu.Unlock()
|
||||||
for _, file := range content.Defaults {
|
for _, file := range content.Defaults {
|
||||||
delete(imageTypes, file.Extension)
|
delete(imageTypes, file.Extension)
|
||||||
}
|
}
|
||||||
|
@ -469,8 +469,8 @@ func (f *File) setContentTypePartVMLExtensions() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content.Lock()
|
content.mu.Lock()
|
||||||
defer content.Unlock()
|
defer content.mu.Unlock()
|
||||||
for _, v := range content.Defaults {
|
for _, v := range content.Defaults {
|
||||||
if v.Extension == "vml" {
|
if v.Extension == "vml" {
|
||||||
vml = true
|
vml = true
|
||||||
|
@ -522,8 +522,8 @@ func (f *File) addContentTypePart(index int, contentType string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content.Lock()
|
content.mu.Lock()
|
||||||
defer content.Unlock()
|
defer content.mu.Unlock()
|
||||||
for _, v := range content.Overrides {
|
for _, v := range content.Overrides {
|
||||||
if v.PartName == partNames[contentType] {
|
if v.PartName == partNames[contentType] {
|
||||||
return err
|
return err
|
||||||
|
@ -549,8 +549,8 @@ func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string {
|
||||||
if sheetRels == nil {
|
if sheetRels == nil {
|
||||||
sheetRels = &xlsxRelationships{}
|
sheetRels = &xlsxRelationships{}
|
||||||
}
|
}
|
||||||
sheetRels.Lock()
|
sheetRels.mu.Lock()
|
||||||
defer sheetRels.Unlock()
|
defer sheetRels.mu.Unlock()
|
||||||
for _, v := range sheetRels.Relationships {
|
for _, v := range sheetRels.Relationships {
|
||||||
if v.ID == rID {
|
if v.ID == rID {
|
||||||
return v.Target
|
return v.Target
|
||||||
|
@ -683,8 +683,8 @@ func (f *File) getPicturesFromWsDr(row, col int, drawingRelationships string, ws
|
||||||
anchor *xdrCellAnchor
|
anchor *xdrCellAnchor
|
||||||
drawRel *xlsxRelationship
|
drawRel *xlsxRelationship
|
||||||
)
|
)
|
||||||
wsDr.Lock()
|
wsDr.mu.Lock()
|
||||||
defer wsDr.Unlock()
|
defer wsDr.mu.Unlock()
|
||||||
for _, anchor = range wsDr.TwoCellAnchor {
|
for _, anchor = range wsDr.TwoCellAnchor {
|
||||||
if anchor.From != nil && anchor.Pic != nil {
|
if anchor.From != nil && anchor.Pic != nil {
|
||||||
if anchor.From.Col == col && anchor.From.Row == row {
|
if anchor.From.Col == col && anchor.From.Row == row {
|
||||||
|
@ -710,8 +710,8 @@ func (f *File) getPicturesFromWsDr(row, col int, drawingRelationships string, ws
|
||||||
// relationship ID.
|
// relationship ID.
|
||||||
func (f *File) getDrawingRelationships(rels, rID string) *xlsxRelationship {
|
func (f *File) getDrawingRelationships(rels, rID string) *xlsxRelationship {
|
||||||
if drawingRels, _ := f.relsReader(rels); drawingRels != nil {
|
if drawingRels, _ := f.relsReader(rels); drawingRels != nil {
|
||||||
drawingRels.Lock()
|
drawingRels.mu.Lock()
|
||||||
defer drawingRels.Unlock()
|
defer drawingRels.mu.Unlock()
|
||||||
for _, v := range drawingRels.Relationships {
|
for _, v := range drawingRels.Relationships {
|
||||||
if v.ID == rID {
|
if v.ID == rID {
|
||||||
return &v
|
return &v
|
||||||
|
|
32
rows.go
32
rows.go
|
@ -267,12 +267,12 @@ func (f *File) Rows(sheet string) (*Rows, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrSheetNotExist{sheet}
|
return nil, ErrSheetNotExist{sheet}
|
||||||
}
|
}
|
||||||
if ws, ok := f.Sheet.Load(name); ok && ws != nil {
|
if worksheet, ok := f.Sheet.Load(name); ok && worksheet != nil {
|
||||||
worksheet := ws.(*xlsxWorksheet)
|
ws := worksheet.(*xlsxWorksheet)
|
||||||
worksheet.Lock()
|
ws.mu.Lock()
|
||||||
defer worksheet.Unlock()
|
defer ws.mu.Unlock()
|
||||||
// Flush data
|
// Flush data
|
||||||
output, _ := xml.Marshal(worksheet)
|
output, _ := xml.Marshal(ws)
|
||||||
f.saveFileList(name, f.replaceNameSpaceBytes(name, output))
|
f.saveFileList(name, f.replaceNameSpaceBytes(name, output))
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
|
@ -360,7 +360,7 @@ func (f *File) SetRowHeight(sheet string, row int, height float64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareSheetXML(ws, 0, row)
|
ws.prepareSheetXML(0, row)
|
||||||
|
|
||||||
rowIdx := row - 1
|
rowIdx := row - 1
|
||||||
ws.SheetData.Row[rowIdx].Ht = float64Ptr(height)
|
ws.SheetData.Row[rowIdx].Ht = float64Ptr(height)
|
||||||
|
@ -372,8 +372,8 @@ func (f *File) SetRowHeight(sheet string, row int, height float64) error {
|
||||||
// name and row number.
|
// name and row number.
|
||||||
func (f *File) getRowHeight(sheet string, row int) int {
|
func (f *File) getRowHeight(sheet string, row int) int {
|
||||||
ws, _ := f.workSheetReader(sheet)
|
ws, _ := f.workSheetReader(sheet)
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
for i := range ws.SheetData.Row {
|
for i := range ws.SheetData.Row {
|
||||||
v := &ws.SheetData.Row[i]
|
v := &ws.SheetData.Row[i]
|
||||||
if v.R == row && v.Ht != nil {
|
if v.R == row && v.Ht != nil {
|
||||||
|
@ -416,8 +416,8 @@ func (f *File) GetRowHeight(sheet string, row int) (float64, error) {
|
||||||
// after deserialization of xl/sharedStrings.xml.
|
// after deserialization of xl/sharedStrings.xml.
|
||||||
func (f *File) sharedStringsReader() (*xlsxSST, error) {
|
func (f *File) sharedStringsReader() (*xlsxSST, error) {
|
||||||
var err error
|
var err error
|
||||||
f.Lock()
|
f.mu.Lock()
|
||||||
defer f.Unlock()
|
defer f.mu.Unlock()
|
||||||
relPath := f.getWorkbookRelsPath()
|
relPath := f.getWorkbookRelsPath()
|
||||||
if f.SharedStrings == nil {
|
if f.SharedStrings == nil {
|
||||||
var sharedStrings xlsxSST
|
var sharedStrings xlsxSST
|
||||||
|
@ -470,7 +470,7 @@ func (f *File) SetRowVisible(sheet string, row int, visible bool) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
prepareSheetXML(ws, 0, row)
|
ws.prepareSheetXML(0, row)
|
||||||
ws.SheetData.Row[row-1].Hidden = !visible
|
ws.SheetData.Row[row-1].Hidden = !visible
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -511,7 +511,7 @@ func (f *File) SetRowOutlineLevel(sheet string, row int, level uint8) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
prepareSheetXML(ws, 0, row)
|
ws.prepareSheetXML(0, row)
|
||||||
ws.SheetData.Row[row-1].OutlineLevel = level
|
ws.SheetData.Row[row-1].OutlineLevel = level
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -724,7 +724,7 @@ func (f *File) duplicateMergeCells(sheet string, ws *xlsxWorksheet, row, row2 in
|
||||||
//
|
//
|
||||||
// Notice: this method could be very slow for large spreadsheets (more than
|
// Notice: this method could be very slow for large spreadsheets (more than
|
||||||
// 3000 rows one sheet).
|
// 3000 rows one sheet).
|
||||||
func checkRow(ws *xlsxWorksheet) error {
|
func (ws *xlsxWorksheet) checkRow() error {
|
||||||
for rowIdx := range ws.SheetData.Row {
|
for rowIdx := range ws.SheetData.Row {
|
||||||
rowData := &ws.SheetData.Row[rowIdx]
|
rowData := &ws.SheetData.Row[rowIdx]
|
||||||
|
|
||||||
|
@ -814,8 +814,8 @@ func (f *File) SetRowStyle(sheet string, start, end, styleID int) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.Lock()
|
s.mu.Lock()
|
||||||
defer s.Unlock()
|
defer s.mu.Unlock()
|
||||||
if styleID < 0 || s.CellXfs == nil || len(s.CellXfs.Xf) <= styleID {
|
if styleID < 0 || s.CellXfs == nil || len(s.CellXfs.Xf) <= styleID {
|
||||||
return newInvalidStyleID(styleID)
|
return newInvalidStyleID(styleID)
|
||||||
}
|
}
|
||||||
|
@ -823,7 +823,7 @@ func (f *File) SetRowStyle(sheet string, start, end, styleID int) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
prepareSheetXML(ws, 0, end)
|
ws.prepareSheetXML(0, end)
|
||||||
for row := start - 1; row < end; row++ {
|
for row := start - 1; row < end; row++ {
|
||||||
ws.SheetData.Row[row].S = styleID
|
ws.SheetData.Row[row].S = styleID
|
||||||
ws.SheetData.Row[row].CustomFormat = true
|
ws.SheetData.Row[row].CustomFormat = true
|
||||||
|
|
26
sheet.go
26
sheet.go
|
@ -70,8 +70,8 @@ func (f *File) NewSheet(sheet string) (int, error) {
|
||||||
func (f *File) contentTypesReader() (*xlsxTypes, error) {
|
func (f *File) contentTypesReader() (*xlsxTypes, error) {
|
||||||
if f.ContentTypes == nil {
|
if f.ContentTypes == nil {
|
||||||
f.ContentTypes = new(xlsxTypes)
|
f.ContentTypes = new(xlsxTypes)
|
||||||
f.ContentTypes.Lock()
|
f.ContentTypes.mu.Lock()
|
||||||
defer f.ContentTypes.Unlock()
|
defer f.ContentTypes.mu.Unlock()
|
||||||
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathContentTypes)))).
|
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathContentTypes)))).
|
||||||
Decode(f.ContentTypes); err != nil && err != io.EOF {
|
Decode(f.ContentTypes); err != nil && err != io.EOF {
|
||||||
return f.ContentTypes, err
|
return f.ContentTypes, err
|
||||||
|
@ -217,8 +217,8 @@ func (f *File) setContentTypes(partName, contentType string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content.Lock()
|
content.mu.Lock()
|
||||||
defer content.Unlock()
|
defer content.mu.Unlock()
|
||||||
content.Overrides = append(content.Overrides, xlsxOverride{
|
content.Overrides = append(content.Overrides, xlsxOverride{
|
||||||
PartName: partName,
|
PartName: partName,
|
||||||
ContentType: contentType,
|
ContentType: contentType,
|
||||||
|
@ -615,8 +615,8 @@ func deleteAndAdjustDefinedNames(wb *xlsxWorkbook, deleteLocalSheetID int) {
|
||||||
// relationships by given relationships ID in the file workbook.xml.rels.
|
// relationships by given relationships ID in the file workbook.xml.rels.
|
||||||
func (f *File) deleteSheetFromWorkbookRels(rID string) string {
|
func (f *File) deleteSheetFromWorkbookRels(rID string) string {
|
||||||
rels, _ := f.relsReader(f.getWorkbookRelsPath())
|
rels, _ := f.relsReader(f.getWorkbookRelsPath())
|
||||||
rels.Lock()
|
rels.mu.Lock()
|
||||||
defer rels.Unlock()
|
defer rels.mu.Unlock()
|
||||||
for k, v := range rels.Relationships {
|
for k, v := range rels.Relationships {
|
||||||
if v.ID == rID {
|
if v.ID == rID {
|
||||||
rels.Relationships = append(rels.Relationships[:k], rels.Relationships[k+1:]...)
|
rels.Relationships = append(rels.Relationships[:k], rels.Relationships[k+1:]...)
|
||||||
|
@ -636,8 +636,8 @@ func (f *File) deleteSheetFromContentTypes(target string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content.Lock()
|
content.mu.Lock()
|
||||||
defer content.Unlock()
|
defer content.mu.Unlock()
|
||||||
for k, v := range content.Overrides {
|
for k, v := range content.Overrides {
|
||||||
if v.PartName == target {
|
if v.PartName == target {
|
||||||
content.Overrides = append(content.Overrides[:k], content.Overrides[k+1:]...)
|
content.Overrides = append(content.Overrides[:k], content.Overrides[k+1:]...)
|
||||||
|
@ -1842,9 +1842,9 @@ func (f *File) relsReader(path string) (*xlsxRelationships, error) {
|
||||||
// fillSheetData ensures there are enough rows, and columns in the chosen
|
// fillSheetData ensures there are enough rows, and columns in the chosen
|
||||||
// row to accept data. Missing rows are backfilled and given their row number
|
// row to accept data. Missing rows are backfilled and given their row number
|
||||||
// Uses the last populated row as a hint for the size of the next row to add
|
// Uses the last populated row as a hint for the size of the next row to add
|
||||||
func prepareSheetXML(ws *xlsxWorksheet, col int, row int) {
|
func (ws *xlsxWorksheet) prepareSheetXML(col int, row int) {
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
rowCount := len(ws.SheetData.Row)
|
rowCount := len(ws.SheetData.Row)
|
||||||
sizeHint := 0
|
sizeHint := 0
|
||||||
var ht *float64
|
var ht *float64
|
||||||
|
@ -1879,8 +1879,8 @@ func fillColumns(rowData *xlsxRow, col, row int) {
|
||||||
|
|
||||||
// makeContiguousColumns make columns in specific rows as contiguous.
|
// makeContiguousColumns make columns in specific rows as contiguous.
|
||||||
func makeContiguousColumns(ws *xlsxWorksheet, fromRow, toRow, colCount int) {
|
func makeContiguousColumns(ws *xlsxWorksheet, fromRow, toRow, colCount int) {
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
for ; fromRow < toRow; fromRow++ {
|
for ; fromRow < toRow; fromRow++ {
|
||||||
rowData := &ws.SheetData.Row[fromRow-1]
|
rowData := &ws.SheetData.Row[fromRow-1]
|
||||||
fillColumns(rowData, colCount, fromRow)
|
fillColumns(rowData, colCount, fromRow)
|
||||||
|
|
22
styles.go
22
styles.go
|
@ -2008,8 +2008,8 @@ func (f *File) NewStyle(style *Style) (int, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cellXfsID, err
|
return cellXfsID, err
|
||||||
}
|
}
|
||||||
s.Lock()
|
s.mu.Lock()
|
||||||
defer s.Unlock()
|
defer s.mu.Unlock()
|
||||||
// check given style already exist.
|
// check given style already exist.
|
||||||
if cellXfsID, err = f.getStyleID(s, fs); err != nil || cellXfsID != -1 {
|
if cellXfsID, err = f.getStyleID(s, fs); err != nil || cellXfsID != -1 {
|
||||||
return cellXfsID, err
|
return cellXfsID, err
|
||||||
|
@ -2669,10 +2669,10 @@ func (f *File) GetCellStyle(sheet, cell string) (int, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
prepareSheetXML(ws, col, row)
|
ws.prepareSheetXML(col, row)
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
return f.prepareCellStyle(ws, col, row, ws.SheetData.Row[row-1].C[col-1].S), err
|
return ws.prepareCellStyle(col, row, ws.SheetData.Row[row-1].C[col-1].S), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCellStyle provides a function to add style attribute for cells by given
|
// SetCellStyle provides a function to add style attribute for cells by given
|
||||||
|
@ -2808,17 +2808,17 @@ func (f *File) SetCellStyle(sheet, hCell, vCell string, styleID int) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
prepareSheetXML(ws, vCol, vRow)
|
ws.prepareSheetXML(vCol, vRow)
|
||||||
makeContiguousColumns(ws, hRow, vRow, vCol)
|
makeContiguousColumns(ws, hRow, vRow, vCol)
|
||||||
ws.Lock()
|
ws.mu.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.mu.Unlock()
|
||||||
|
|
||||||
s, err := f.stylesReader()
|
s, err := f.stylesReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.Lock()
|
s.mu.Lock()
|
||||||
defer s.Unlock()
|
defer s.mu.Unlock()
|
||||||
if styleID < 0 || s.CellXfs == nil || len(s.CellXfs.Xf) <= styleID {
|
if styleID < 0 || s.CellXfs == nil || len(s.CellXfs.Xf) <= styleID {
|
||||||
return newInvalidStyleID(styleID)
|
return newInvalidStyleID(styleID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,8 +145,8 @@ func (f *File) setWorkbook(name string, sheetID, rid int) {
|
||||||
// the spreadsheet.
|
// the spreadsheet.
|
||||||
func (f *File) getWorkbookPath() (path string) {
|
func (f *File) getWorkbookPath() (path string) {
|
||||||
if rels, _ := f.relsReader("_rels/.rels"); rels != nil {
|
if rels, _ := f.relsReader("_rels/.rels"); rels != nil {
|
||||||
rels.Lock()
|
rels.mu.Lock()
|
||||||
defer rels.Unlock()
|
defer rels.mu.Unlock()
|
||||||
for _, rel := range rels.Relationships {
|
for _, rel := range rels.Relationships {
|
||||||
if rel.Type == SourceRelationshipOfficeDocument {
|
if rel.Type == SourceRelationshipOfficeDocument {
|
||||||
path = strings.TrimPrefix(rel.Target, "/")
|
path = strings.TrimPrefix(rel.Target, "/")
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
// parts, it takes a Multipurpose Internet Mail Extension (MIME) media type as a
|
// parts, it takes a Multipurpose Internet Mail Extension (MIME) media type as a
|
||||||
// value.
|
// value.
|
||||||
type xlsxTypes struct {
|
type xlsxTypes struct {
|
||||||
sync.Mutex
|
mu sync.Mutex
|
||||||
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/content-types Types"`
|
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/content-types Types"`
|
||||||
Defaults []xlsxDefault `xml:"Default"`
|
Defaults []xlsxDefault `xml:"Default"`
|
||||||
Overrides []xlsxOverride `xml:"Override"`
|
Overrides []xlsxOverride `xml:"Override"`
|
||||||
|
|
|
@ -440,7 +440,7 @@ type xlsxPoint2D struct {
|
||||||
// xlsxWsDr directly maps the root element for a part of this content type shall
|
// xlsxWsDr directly maps the root element for a part of this content type shall
|
||||||
// wsDr.
|
// wsDr.
|
||||||
type xlsxWsDr struct {
|
type xlsxWsDr struct {
|
||||||
sync.Mutex
|
mu sync.Mutex
|
||||||
XMLName xml.Name `xml:"xdr:wsDr"`
|
XMLName xml.Name `xml:"xdr:wsDr"`
|
||||||
A string `xml:"xmlns:a,attr,omitempty"`
|
A string `xml:"xmlns:a,attr,omitempty"`
|
||||||
Xdr string `xml:"xmlns:xdr,attr,omitempty"`
|
Xdr string `xml:"xmlns:xdr,attr,omitempty"`
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
|
|
||||||
// xlsxStyleSheet is the root element of the Styles part.
|
// xlsxStyleSheet is the root element of the Styles part.
|
||||||
type xlsxStyleSheet struct {
|
type xlsxStyleSheet struct {
|
||||||
sync.Mutex
|
mu sync.Mutex
|
||||||
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main styleSheet"`
|
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main styleSheet"`
|
||||||
NumFmts *xlsxNumFmts `xml:"numFmts"`
|
NumFmts *xlsxNumFmts `xml:"numFmts"`
|
||||||
Fonts *xlsxFonts `xml:"fonts"`
|
Fonts *xlsxFonts `xml:"fonts"`
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
|
|
||||||
// xlsxRelationships describe references from parts to other internal resources in the package or to external resources.
|
// xlsxRelationships describe references from parts to other internal resources in the package or to external resources.
|
||||||
type xlsxRelationships struct {
|
type xlsxRelationships struct {
|
||||||
sync.Mutex
|
mu sync.Mutex
|
||||||
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"`
|
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"`
|
||||||
Relationships []xlsxRelationship `xml:"Relationship"`
|
Relationships []xlsxRelationship `xml:"Relationship"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
// xlsxWorksheet directly maps the worksheet element in the namespace
|
// xlsxWorksheet directly maps the worksheet element in the namespace
|
||||||
// http://schemas.openxmlformats.org/spreadsheetml/2006/main.
|
// http://schemas.openxmlformats.org/spreadsheetml/2006/main.
|
||||||
type xlsxWorksheet struct {
|
type xlsxWorksheet struct {
|
||||||
sync.Mutex
|
mu sync.Mutex
|
||||||
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main worksheet"`
|
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main worksheet"`
|
||||||
SheetPr *xlsxSheetPr `xml:"sheetPr"`
|
SheetPr *xlsxSheetPr `xml:"sheetPr"`
|
||||||
Dimension *xlsxDimension `xml:"dimension"`
|
Dimension *xlsxDimension `xml:"dimension"`
|
||||||
|
|
Loading…
Reference in New Issue