This closes #1861, fix missing parentheses in the adjusted formula
- Allow adjust cell reference with max rows/columns - Fix incorrect data validation escape result - Update out date reference link in the documentation - Update unit tests
This commit is contained in:
parent
5975d87f7e
commit
703b73779c
57
adjust.go
57
adjust.go
|
@ -239,6 +239,17 @@ func (f *File) adjustSingleRowFormulas(sheet, sheetN string, r *xlsxRow, num, of
|
|||
// adjustCellRef provides a function to adjust cell reference.
|
||||
func (f *File) adjustCellRef(cellRef string, dir adjustDirection, num, offset int) (string, error) {
|
||||
var SQRef []string
|
||||
applyOffset := func(coordinates []int, idx1, idx2, maxVal int) []int {
|
||||
if coordinates[idx1] >= num {
|
||||
coordinates[idx1] += offset
|
||||
}
|
||||
if coordinates[idx2] >= num {
|
||||
if coordinates[idx2] += offset; coordinates[idx2] > maxVal {
|
||||
coordinates[idx2] = maxVal
|
||||
}
|
||||
}
|
||||
return coordinates
|
||||
}
|
||||
for _, ref := range strings.Split(cellRef, " ") {
|
||||
if !strings.Contains(ref, ":") {
|
||||
ref += ":" + ref
|
||||
|
@ -251,22 +262,12 @@ func (f *File) adjustCellRef(cellRef string, dir adjustDirection, num, offset in
|
|||
if offset < 0 && coordinates[0] == coordinates[2] {
|
||||
continue
|
||||
}
|
||||
if coordinates[0] >= num {
|
||||
coordinates[0] += offset
|
||||
}
|
||||
if coordinates[2] >= num {
|
||||
coordinates[2] += offset
|
||||
}
|
||||
coordinates = applyOffset(coordinates, 0, 2, MaxColumns)
|
||||
} else {
|
||||
if offset < 0 && coordinates[1] == coordinates[3] {
|
||||
continue
|
||||
}
|
||||
if coordinates[1] >= num {
|
||||
coordinates[1] += offset
|
||||
}
|
||||
if coordinates[3] >= num {
|
||||
coordinates[3] += offset
|
||||
}
|
||||
coordinates = applyOffset(coordinates, 1, 3, TotalRows)
|
||||
}
|
||||
if ref, err = coordinatesToRangeRef(coordinates); err != nil {
|
||||
return "", err
|
||||
|
@ -446,12 +447,8 @@ func (f *File) adjustFormulaRef(sheet, sheetN, formula string, keepRelative bool
|
|||
val += operand
|
||||
continue
|
||||
}
|
||||
if isFunctionStartToken(token) {
|
||||
val += token.TValue + string(efp.ParenOpen)
|
||||
continue
|
||||
}
|
||||
if isFunctionStopToken(token) {
|
||||
val += token.TValue + string(efp.ParenClose)
|
||||
if paren := transformParenthesesToken(token); paren != "" {
|
||||
val += transformParenthesesToken(token)
|
||||
continue
|
||||
}
|
||||
if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeText {
|
||||
|
@ -463,6 +460,18 @@ func (f *File) adjustFormulaRef(sheet, sheetN, formula string, keepRelative bool
|
|||
return val, nil
|
||||
}
|
||||
|
||||
// transformParenthesesToken returns formula part with parentheses by given
|
||||
// token.
|
||||
func transformParenthesesToken(token efp.Token) string {
|
||||
if isFunctionStartToken(token) || isBeginParenthesesToken(token) {
|
||||
return token.TValue + string(efp.ParenOpen)
|
||||
}
|
||||
if isFunctionStopToken(token) || isEndParenthesesToken(token) {
|
||||
return token.TValue + string(efp.ParenClose)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// adjustRangeSheetName returns replaced range reference by given source and
|
||||
// target sheet name.
|
||||
func adjustRangeSheetName(rng, source, target string) string {
|
||||
|
@ -551,12 +560,8 @@ func transformArrayFormula(tokens []efp.Token, afs []arrayFormulaOperandToken) s
|
|||
if skip {
|
||||
continue
|
||||
}
|
||||
if isFunctionStartToken(token) {
|
||||
val += token.TValue + string(efp.ParenOpen)
|
||||
continue
|
||||
}
|
||||
if isFunctionStopToken(token) {
|
||||
val += token.TValue + string(efp.ParenClose)
|
||||
if paren := transformParenthesesToken(token); paren != "" {
|
||||
val += transformParenthesesToken(token)
|
||||
continue
|
||||
}
|
||||
if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeText {
|
||||
|
@ -985,14 +990,14 @@ func (f *File) adjustDataValidations(ws *xlsxWorksheet, sheet string, dir adjust
|
|||
worksheet.DataValidations.DataValidation[i].Sqref = ref
|
||||
}
|
||||
if worksheet.DataValidations.DataValidation[i].Formula1 != nil {
|
||||
formula := unescapeDataValidationFormula(worksheet.DataValidations.DataValidation[i].Formula1.Content)
|
||||
formula := formulaUnescaper.Replace(worksheet.DataValidations.DataValidation[i].Formula1.Content)
|
||||
if formula, err = f.adjustFormulaRef(sheet, sheetN, formula, false, dir, num, offset); err != nil {
|
||||
return err
|
||||
}
|
||||
worksheet.DataValidations.DataValidation[i].Formula1 = &xlsxInnerXML{Content: formulaEscaper.Replace(formula)}
|
||||
}
|
||||
if worksheet.DataValidations.DataValidation[i].Formula2 != nil {
|
||||
formula := unescapeDataValidationFormula(worksheet.DataValidations.DataValidation[i].Formula2.Content)
|
||||
formula := formulaUnescaper.Replace(worksheet.DataValidations.DataValidation[i].Formula2.Content)
|
||||
if formula, err = f.adjustFormulaRef(sheet, sheetN, formula, false, dir, num, offset); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -463,6 +463,14 @@ func TestAdjustCols(t *testing.T) {
|
|||
|
||||
assert.NoError(t, f.InsertCols("Sheet1", "A", 2))
|
||||
assert.Nil(t, ws.(*xlsxWorksheet).Cols)
|
||||
|
||||
f = NewFile()
|
||||
assert.NoError(t, f.SetCellFormula("Sheet1", "A2", "(1-0.5)/2"))
|
||||
assert.NoError(t, f.InsertCols("Sheet1", "A", 1))
|
||||
formula, err := f.GetCellFormula("Sheet1", "B2")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "(1-0.5)/2", formula)
|
||||
assert.NoError(t, f.Close())
|
||||
}
|
||||
|
||||
func TestAdjustColDimensions(t *testing.T) {
|
||||
|
@ -1061,13 +1069,13 @@ func TestAdjustDataValidations(t *testing.T) {
|
|||
|
||||
// Test adjust data validation with multiple cell range
|
||||
dv = NewDataValidation(true)
|
||||
dv.Sqref = "G1:G3 H1:H3"
|
||||
dv.Sqref = "G1:G3 H1:H3 A3:A1048576"
|
||||
assert.NoError(t, dv.SetDropList([]string{"1", "2", "3"}))
|
||||
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
|
||||
assert.NoError(t, f.InsertRows("Sheet1", 2, 1))
|
||||
dvs, err = f.GetDataValidations("Sheet1")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "G1:G4 H1:H4", dvs[3].Sqref)
|
||||
assert.Equal(t, "G1:G4 H1:H4 A4:A1048576", dvs[3].Sqref)
|
||||
|
||||
dv = NewDataValidation(true)
|
||||
dv.Sqref = "C5:D6"
|
||||
|
|
|
@ -453,14 +453,14 @@ func (f *File) addRels(relPath, relType, target, targetMode string) int {
|
|||
// UpdateLinkedValue fix linked values within a spreadsheet are not updating in
|
||||
// Office Excel application. This function will be remove value tag when met a
|
||||
// cell have a linked value. Reference
|
||||
// https://social.technet.microsoft.com/Forums/office/en-US/e16bae1f-6a2c-4325-8013-e989a3479066/excel-2010-linked-cells-not-updating
|
||||
// https://learn.microsoft.com/en-us/archive/msdn-technet-forums/e16bae1f-6a2c-4325-8013-e989a3479066
|
||||
//
|
||||
// Notice: after opening generated workbook, Excel will update the linked value
|
||||
// and generate a new value and will prompt to save the file or not.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// <row r="19" spans="2:2">
|
||||
// <row r="19">
|
||||
// <c r="B19">
|
||||
// <f>SUM(Sheet2!D2,Sheet2!D11)</f>
|
||||
// <v>100</v>
|
||||
|
@ -469,7 +469,7 @@ func (f *File) addRels(relPath, relType, target, targetMode string) int {
|
|||
//
|
||||
// to
|
||||
//
|
||||
// <row r="19" spans="2:2">
|
||||
// <row r="19">
|
||||
// <c r="B19">
|
||||
// <f>SUM(Sheet2!D2,Sheet2!D11)</f>
|
||||
// </c>
|
||||
|
|
Loading…
Reference in New Issue