diff options
author | xuri <xuri.me@gmail.com> | 2021-02-16 00:02:14 +0800 |
---|---|---|
committer | xuri <xuri.me@gmail.com> | 2021-02-16 00:02:14 +0800 |
commit | bddea1262b9219df224d19b24928d8da78a2f8c0 (patch) | |
tree | 0aa179d35adaa4ef6ae5deea59e37900d7d8cd68 | |
parent | 36b7990d6ba1036823abf7a01ec8cf74509d4910 (diff) |
This closes #785, support to change tab color; new formula function: FISHER, FISHERINV, GAMMA, GAMMALN, MIN, MINA, PERMUT
-rw-r--r-- | calc.go | 278 | ||||
-rw-r--r-- | calc_test.go | 83 | ||||
-rw-r--r-- | drawing.go | 3 | ||||
-rw-r--r-- | sheetpr.go | 26 | ||||
-rw-r--r-- | sheetpr_test.go | 9 |
5 files changed, 380 insertions, 19 deletions
@@ -249,9 +249,13 @@ var tokenPriority = map[string]int{ // FACT // FACTDOUBLE // FALSE +// FISHER +// FISHERINV // FLOOR // FLOOR.MATH // FLOOR.PRECISE +// GAMMA +// GAMMALN // GCD // HLOOKUP // IF @@ -278,6 +282,8 @@ var tokenPriority = map[string]int{ // MAX // MDETERM // MEDIAN +// MIN +// MINA // MOD // MROUND // MULTINOMIAL @@ -286,6 +292,7 @@ var tokenPriority = map[string]int{ // NOT // ODD // OR +// PERMUT // PI // POWER // PRODUCT @@ -295,6 +302,7 @@ var tokenPriority = map[string]int{ // RAND // RANDBETWEEN // REPT +// ROMAN // ROUND // ROUNDDOWN // ROUNDUP @@ -1798,7 +1806,7 @@ func (fn *formulaFuncs) FACT(argsList *list.List) formulaArg { if number.Number < 0 { return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) } - return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", fact(number.Number)))) + return newNumberFormulaArg(fact(number.Number)) } // FACTDOUBLE function returns the double factorial of a supplied number. The @@ -2552,7 +2560,8 @@ func (fn *formulaFuncs) RANDBETWEEN(argsList *list.List) formulaArg { if top.Number < bottom.Number { return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) } - return newNumberFormulaArg(float64(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(int64(top.Number-bottom.Number+1)) + int64(bottom.Number))) + num := rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(int64(top.Number - bottom.Number + 1)) + return newNumberFormulaArg(float64(num + int64(bottom.Number))) } // romanNumerals defined a numeral system that originated in ancient Rome and @@ -2563,11 +2572,34 @@ type romanNumerals struct { s string } -var romanTable = [][]romanNumerals{{{1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"}, {90, "XC"}, {50, "L"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}}, - {{1000, "M"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {95, "VC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}}, - {{1000, "M"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}}, - {{1000, "M"}, {995, "VM"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {495, "VD"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}}, - {{1000, "M"}, {999, "IM"}, {995, "VM"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {499, "ID"}, {495, "VD"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}}} +var romanTable = [][]romanNumerals{ + { + {1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"}, {90, "XC"}, + {50, "L"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}, + }, + { + {1000, "M"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {450, "LD"}, {400, "CD"}, + {100, "C"}, {95, "VC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, + {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}, + }, + { + {1000, "M"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {490, "XD"}, + {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, + {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}, + }, + { + {1000, "M"}, {995, "VM"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, + {495, "VD"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, + {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, + {5, "V"}, {4, "IV"}, {1, "I"}, + }, + { + {1000, "M"}, {999, "IM"}, {995, "VM"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, + {500, "D"}, {499, "ID"}, {495, "VD"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, + {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, + {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}, + }, +} // ROMAN function converts an arabic number to Roman. I.e. for a supplied // integer, the function returns a text string depicting the roman numeral @@ -3191,6 +3223,112 @@ func (fn *formulaFuncs) COUNTBLANK(argsList *list.List) formulaArg { return newNumberFormulaArg(float64(count)) } +// FISHER function calculates the Fisher Transformation for a supplied value. +// The syntax of the function is: +// +// FISHER(x) +// +func (fn *formulaFuncs) FISHER(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "FISHER requires 1 numeric argument") + } + token := argsList.Front().Value.(formulaArg) + switch token.Type { + case ArgString: + arg := token.ToNumber() + if arg.Type == ArgNumber { + if arg.Number <= -1 || arg.Number >= 1 { + return newErrorFormulaArg(formulaErrorNA, formulaErrorNA) + } + return newNumberFormulaArg(0.5 * math.Log((1+arg.Number)/(1-arg.Number))) + } + case ArgNumber: + if token.Number <= -1 || token.Number >= 1 { + return newErrorFormulaArg(formulaErrorNA, formulaErrorNA) + } + return newNumberFormulaArg(0.5 * math.Log((1+token.Number)/(1-token.Number))) + } + return newErrorFormulaArg(formulaErrorVALUE, "FISHER requires 1 numeric argument") +} + +// FISHERINV function calculates the inverse of the Fisher Transformation and +// returns a value between -1 and +1. The syntax of the function is: +// +// FISHERINV(y) +// +func (fn *formulaFuncs) FISHERINV(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "FISHERINV requires 1 numeric argument") + } + token := argsList.Front().Value.(formulaArg) + switch token.Type { + case ArgString: + arg := token.ToNumber() + if arg.Type == ArgNumber { + return newNumberFormulaArg((math.Exp(2*arg.Number) - 1) / (math.Exp(2*arg.Number) + 1)) + } + case ArgNumber: + return newNumberFormulaArg((math.Exp(2*token.Number) - 1) / (math.Exp(2*token.Number) + 1)) + } + return newErrorFormulaArg(formulaErrorVALUE, "FISHERINV requires 1 numeric argument") +} + +// GAMMA function returns the value of the Gamma Function, Γ(n), for a +// specified number, n. The syntax of the function is: +// +// GAMMA(number) +// +func (fn *formulaFuncs) GAMMA(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "GAMMA requires 1 numeric argument") + } + token := argsList.Front().Value.(formulaArg) + switch token.Type { + case ArgString: + arg := token.ToNumber() + if arg.Type == ArgNumber { + if arg.Number <= 0 { + return newErrorFormulaArg(formulaErrorNA, formulaErrorNA) + } + return newNumberFormulaArg(math.Gamma(arg.Number)) + } + case ArgNumber: + if token.Number <= 0 { + return newErrorFormulaArg(formulaErrorNA, formulaErrorNA) + } + return newNumberFormulaArg(math.Gamma(token.Number)) + } + return newErrorFormulaArg(formulaErrorVALUE, "GAMMA requires 1 numeric argument") +} + +// GAMMALN function returns the natural logarithm of the Gamma Function, Γ +// (n). The syntax of the function is: +// +// GAMMALN(x) +// +func (fn *formulaFuncs) GAMMALN(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "GAMMALN requires 1 numeric argument") + } + token := argsList.Front().Value.(formulaArg) + switch token.Type { + case ArgString: + arg := token.ToNumber() + if arg.Type == ArgNumber { + if arg.Number <= 0 { + return newErrorFormulaArg(formulaErrorNA, formulaErrorNA) + } + return newNumberFormulaArg(math.Log(math.Gamma(arg.Number))) + } + case ArgNumber: + if token.Number <= 0 { + return newErrorFormulaArg(formulaErrorNA, formulaErrorNA) + } + return newNumberFormulaArg(math.Log(math.Gamma(token.Number))) + } + return newErrorFormulaArg(formulaErrorVALUE, "GAMMALN requires 1 numeric argument") +} + // MAX function returns the largest value from a supplied set of numeric // values. The syntax of the function is: // @@ -3203,7 +3341,10 @@ func (fn *formulaFuncs) MAX(argsList *list.List) formulaArg { return fn.max(false, argsList) } -// MAXA function returns the largest value from a supplied set of numeric values, while counting text and the logical value FALSE as the value 0 and counting the logical value TRUE as the value 1. The syntax of the function is: +// MAXA function returns the largest value from a supplied set of numeric +// values, while counting text and the logical value FALSE as the value 0 and +// counting the logical value TRUE as the value 1. The syntax of the function +// is: // // MAXA(number1,[number2],...) // @@ -3317,6 +3458,112 @@ func (fn *formulaFuncs) MEDIAN(argsList *list.List) formulaArg { return newNumberFormulaArg(median) } +// MIN function returns the smallest value from a supplied set of numeric +// values. The syntax of the function is: +// +// MIN(number1,[number2],...) +// +func (fn *formulaFuncs) MIN(argsList *list.List) formulaArg { + if argsList.Len() == 0 { + return newErrorFormulaArg(formulaErrorVALUE, "MIN requires at least 1 argument") + } + return fn.min(false, argsList) +} + +// MINA function returns the smallest value from a supplied set of numeric +// values, while counting text and the logical value FALSE as the value 0 and +// counting the logical value TRUE as the value 1. The syntax of the function +// is: +// +// MINA(number1,[number2],...) +// +func (fn *formulaFuncs) MINA(argsList *list.List) formulaArg { + if argsList.Len() == 0 { + return newErrorFormulaArg(formulaErrorVALUE, "MINA requires at least 1 argument") + } + return fn.min(true, argsList) +} + +// min is an implementation of the formula function MIN and MINA. +func (fn *formulaFuncs) min(mina bool, argsList *list.List) formulaArg { + min := math.MaxFloat64 + for token := argsList.Front(); token != nil; token = token.Next() { + arg := token.Value.(formulaArg) + switch arg.Type { + case ArgString: + if !mina && (arg.Value() == "TRUE" || arg.Value() == "FALSE") { + continue + } else { + num := arg.ToBool() + if num.Type == ArgNumber && num.Number < min { + min = num.Number + continue + } + } + num := arg.ToNumber() + if num.Type != ArgError && num.Number < min { + min = num.Number + } + case ArgNumber: + if arg.Number < min { + min = arg.Number + } + case ArgList, ArgMatrix: + for _, row := range arg.ToList() { + switch row.Type { + case ArgString: + if !mina && (row.Value() == "TRUE" || row.Value() == "FALSE") { + continue + } else { + num := row.ToBool() + if num.Type == ArgNumber && num.Number < min { + min = num.Number + continue + } + } + num := row.ToNumber() + if num.Type != ArgError && num.Number < min { + min = num.Number + } + case ArgNumber: + if row.Number < min { + min = row.Number + } + } + } + case ArgError: + return arg + } + } + if min == math.MaxFloat64 { + min = 0 + } + return newNumberFormulaArg(min) +} + +// PERMUT function calculates the number of permutations of a specified number +// of objects from a set of objects. The syntax of the function is: +// +// PERMUT(number,number_chosen) +// +func (fn *formulaFuncs) PERMUT(argsList *list.List) formulaArg { + if argsList.Len() != 2 { + return newErrorFormulaArg(formulaErrorVALUE, "PERMUT requires 2 numeric arguments") + } + number := argsList.Front().Value.(formulaArg).ToNumber() + chosen := argsList.Back().Value.(formulaArg).ToNumber() + if number.Type != ArgNumber { + return number + } + if chosen.Type != ArgNumber { + return chosen + } + if number.Number < chosen.Number { + return newErrorFormulaArg(formulaErrorNA, formulaErrorNA) + } + return newNumberFormulaArg(math.Round(fact(number.Number) / fact(number.Number-chosen.Number))) +} + // Information Functions // ISBLANK function tests if a specified cell is blank (empty) and if so, @@ -3356,7 +3603,11 @@ func (fn *formulaFuncs) ISERR(argsList *list.List) formulaArg { token := argsList.Front().Value.(formulaArg) result := "FALSE" if token.Type == ArgError { - for _, errType := range []string{formulaErrorDIV, formulaErrorNAME, formulaErrorNUM, formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA} { + for _, errType := range []string{ + formulaErrorDIV, formulaErrorNAME, formulaErrorNUM, + formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, + formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA, + } { if errType == token.String { result = "TRUE" } @@ -3378,7 +3629,11 @@ func (fn *formulaFuncs) ISERROR(argsList *list.List) formulaArg { token := argsList.Front().Value.(formulaArg) result := "FALSE" if token.Type == ArgError { - for _, errType := range []string{formulaErrorDIV, formulaErrorNAME, formulaErrorNA, formulaErrorNUM, formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA} { + for _, errType := range []string{ + formulaErrorDIV, formulaErrorNAME, formulaErrorNA, formulaErrorNUM, + formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL, + formulaErrorCALC, formulaErrorGETTINGDATA, + } { if errType == token.String { result = "TRUE" } @@ -4413,5 +4668,6 @@ func (fn *formulaFuncs) ENCODEURL(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "ENCODEURL requires 1 argument") } - return newStringFormulaArg(strings.Replace(url.QueryEscape(argsList.Front().Value.(formulaArg).Value()), "+", "%20", -1)) + token := argsList.Front().Value.(formulaArg).Value() + return newStringFormulaArg(strings.Replace(url.QueryEscape(token), "+", "%20", -1)) } diff --git a/calc_test.go b/calc_test.go index ef028a9..1f9fea6 100644 --- a/calc_test.go +++ b/calc_test.go @@ -205,7 +205,7 @@ func TestCalcCellValue(t *testing.T) { // FACT "=FACT(3)": "6", "=FACT(6)": "720", - "=FACT(10)": "3.6288E+06", + "=FACT(10)": "3.6288e+06", "=FACT(FACT(3))": "720", // FACTDOUBLE "=FACTDOUBLE(5)": "15", @@ -490,6 +490,23 @@ func TestCalcCellValue(t *testing.T) { "=COUNTBLANK(1)": "0", "=COUNTBLANK(B1:C1)": "1", "=COUNTBLANK(C1)": "1", + // FISHER + "=FISHER(-0.9)": "-1.47221948958322", + "=FISHER(-0.25)": "-0.255412811882995", + "=FISHER(0.8)": "1.09861228866811", + "=FISHER(INT(0))": "0", + // FISHERINV + "=FISHERINV(-0.2)": "-0.197375320224904", + "=FISHERINV(INT(0))": "0", + "=FISHERINV(2.8)": "0.992631520201128", + // GAMMA + "=GAMMA(0.1)": "9.513507698668732", + "=GAMMA(INT(1))": "1", + "=GAMMA(1.5)": "0.886226925452758", + "=GAMMA(5.5)": "52.34277778455352", + // GAMMALN + "=GAMMALN(4.5)": "2.453736570842443", + "=GAMMALN(INT(1))": "0", // MAX "=MAX(1)": "1", "=MAX(TRUE())": "1", @@ -509,6 +526,25 @@ func TestCalcCellValue(t *testing.T) { "=MEDIAN(A1:A5,12)": "2", "=MEDIAN(A1:A5)": "1.5", "=MEDIAN(A1:A5,MEDIAN(A1:A5,12))": "2", + // MIN + "=MIN(1)": "1", + "=MIN(TRUE())": "1", + "=MIN(0.5,FALSE())": "0", + "=MIN(FALSE())": "0", + "=MIN(MUNIT(2))": "0", + "=MIN(INT(1))": "1", + // MINA + "=MINA(1)": "1", + "=MINA(TRUE())": "1", + "=MINA(0.5,FALSE())": "0", + "=MINA(FALSE())": "0", + "=MINA(MUNIT(2))": "0", + "=MINA(INT(1))": "1", + "=MINA(A1:B4,MUNIT(1),INT(0),1,E1:F2,\"\")": "0", + // PERMUT + "=PERMUT(6,6)": "720", + "=PERMUT(7,6)": "5040", + "=PERMUT(10,6)": "151200", // Information Functions // ISBLANK "=ISBLANK(A1)": "FALSE", @@ -940,6 +976,24 @@ func TestCalcCellValue(t *testing.T) { // COUNTBLANK "=COUNTBLANK()": "COUNTBLANK requires 1 argument", "=COUNTBLANK(1,2)": "COUNTBLANK requires 1 argument", + // FISHER + "=FISHER()": "FISHER requires 1 numeric argument", + "=FISHER(2)": "#N/A", + "=FISHER(INT(-2)))": "#N/A", + "=FISHER(F1)": "FISHER requires 1 numeric argument", + // FISHERINV + "=FISHERINV()": "FISHERINV requires 1 numeric argument", + "=FISHERINV(F1)": "FISHERINV requires 1 numeric argument", + // GAMMA + "=GAMMA()": "GAMMA requires 1 numeric argument", + "=GAMMA(F1)": "GAMMA requires 1 numeric argument", + "=GAMMA(0)": "#N/A", + "=GAMMA(INT(0))": "#N/A", + // GAMMALN + "=GAMMALN()": "GAMMALN requires 1 numeric argument", + "=GAMMALN(F1)": "GAMMALN requires 1 numeric argument", + "=GAMMALN(0)": "#N/A", + "=GAMMALN(INT(0))": "#N/A", // MAX "=MAX()": "MAX requires at least 1 argument", "=MAX(NA())": "#N/A", @@ -950,6 +1004,17 @@ func TestCalcCellValue(t *testing.T) { "=MEDIAN()": "MEDIAN requires at least 1 argument", "=MEDIAN(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", "=MEDIAN(D1:D2)": "strconv.ParseFloat: parsing \"Month\": invalid syntax", + // MIN + "=MIN()": "MIN requires at least 1 argument", + "=MIN(NA())": "#N/A", + // MINA + "=MINA()": "MINA requires at least 1 argument", + "=MINA(NA())": "#N/A", + // PERMUT + "=PERMUT()": "PERMUT requires 2 numeric arguments", + "=PERMUT(\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=PERMUT(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=PERMUT(6,8)": "#N/A", // Information Functions // ISBLANK "=ISBLANK(A1,A2)": "ISBLANK requires 1 argument", @@ -1315,16 +1380,20 @@ func TestCalcVLOOKUP(t *testing.T) { } } -func TestCalcMAX(t *testing.T) { +func TestCalcMAXMIN(t *testing.T) { cellData := [][]interface{}{ - {0.5, "TRUE"}, + {0.5, "TRUE", -0.5, "FALSE"}, } f := prepareCalcData(cellData) formulaList := map[string]string{ - "=MAX(0.5,B1)": "0.5", - "=MAX(A1:B1)": "0.5", - "=MAXA(A1:B1)": "1", - "=MAXA(0.5,B1)": "1", + "=MAX(0.5,B1)": "0.5", + "=MAX(A1:B1)": "0.5", + "=MAXA(A1:B1)": "1", + "=MAXA(0.5,B1)": "1", + "=MIN(-0.5,D1)": "-0.5", + "=MIN(C1:D1)": "-0.5", + "=MINA(C1:D1)": "-0.5", + "=MINA(-0.5,D1)": "-0.5", } for formula, expected := range formulaList { assert.NoError(t, f.SetCellFormula("Sheet1", "B10", formula)) @@ -939,7 +939,8 @@ func (f *File) drawChartDLbls(formatSet *formatChart) *cDLbls { // given format sets. func (f *File) drawChartSeriesDLbls(formatSet *formatChart) *cDLbls { dLbls := f.drawChartDLbls(formatSet) - chartSeriesDLbls := map[string]*cDLbls{Scatter: nil, Surface3D: nil, WireframeSurface3D: nil, Contour: nil, WireframeContour: nil, Bubble: nil, Bubble3D: nil} + chartSeriesDLbls := map[string]*cDLbls{ + Scatter: nil, Surface3D: nil, WireframeSurface3D: nil, Contour: nil, WireframeContour: nil, Bubble: nil, Bubble3D: nil} if _, ok := chartSeriesDLbls[formatSet.Type]; ok { return nil } @@ -11,6 +11,8 @@ package excelize +import "strings" + // SheetPrOption is an option of a view of a worksheet. See SetSheetPrOptions(). type SheetPrOption interface { setSheetPrOption(view *xlsxSheetPr) @@ -31,6 +33,8 @@ type ( Published bool // FitToPage is a SheetPrOption FitToPage bool + // TabColor is a SheetPrOption + TabColor string // AutoPageBreaks is a SheetPrOption AutoPageBreaks bool // OutlineSummaryBelow is an outlinePr, within SheetPr option @@ -125,6 +129,28 @@ func (o *FitToPage) getSheetPrOption(pr *xlsxSheetPr) { *o = FitToPage(pr.PageSetUpPr.FitToPage) } +// setSheetPrOption implements the SheetPrOption interface and specifies a +// stable name of the sheet. +func (o TabColor) setSheetPrOption(pr *xlsxSheetPr) { + if pr.TabColor == nil { + if string(o) == "" { + return + } + pr.TabColor = new(xlsxTabColor) + } + pr.TabColor.RGB = getPaletteColor(string(o)) +} + +// getSheetPrOption implements the SheetPrOptionPtr interface and get the +// stable name of the sheet. +func (o *TabColor) getSheetPrOption(pr *xlsxSheetPr) { + if pr == nil || pr.TabColor == nil { + *o = "" + return + } + *o = TabColor(strings.TrimPrefix(pr.TabColor.RGB, "FF")) +} + // setSheetPrOption implements the SheetPrOption interface. func (o AutoPageBreaks) setSheetPrOption(pr *xlsxSheetPr) { if pr.PageSetUpPr == nil { diff --git a/sheetpr_test.go b/sheetpr_test.go index 29bd99e..42e2e0d 100644 --- a/sheetpr_test.go +++ b/sheetpr_test.go @@ -13,6 +13,7 @@ var _ = []SheetPrOption{ EnableFormatConditionsCalculation(false), Published(false), FitToPage(true), + TabColor("#FFFF00"), AutoPageBreaks(true), OutlineSummaryBelow(true), } @@ -22,6 +23,7 @@ var _ = []SheetPrOptionPtr{ (*EnableFormatConditionsCalculation)(nil), (*Published)(nil), (*FitToPage)(nil), + (*TabColor)(nil), (*AutoPageBreaks)(nil), (*OutlineSummaryBelow)(nil), } @@ -35,6 +37,7 @@ func ExampleFile_SetSheetPrOptions() { EnableFormatConditionsCalculation(false), Published(false), FitToPage(true), + TabColor("#FFFF00"), AutoPageBreaks(true), OutlineSummaryBelow(false), ); err != nil { @@ -52,6 +55,7 @@ func ExampleFile_GetSheetPrOptions() { enableFormatConditionsCalculation EnableFormatConditionsCalculation published Published fitToPage FitToPage + tabColor TabColor autoPageBreaks AutoPageBreaks outlineSummaryBelow OutlineSummaryBelow ) @@ -61,6 +65,7 @@ func ExampleFile_GetSheetPrOptions() { &enableFormatConditionsCalculation, &published, &fitToPage, + &tabColor, &autoPageBreaks, &outlineSummaryBelow, ); err != nil { @@ -71,6 +76,7 @@ func ExampleFile_GetSheetPrOptions() { fmt.Println("- enableFormatConditionsCalculation:", enableFormatConditionsCalculation) fmt.Println("- published:", published) fmt.Println("- fitToPage:", fitToPage) + fmt.Printf("- tabColor: %q\n", tabColor) fmt.Println("- autoPageBreaks:", autoPageBreaks) fmt.Println("- outlineSummaryBelow:", outlineSummaryBelow) // Output: @@ -79,6 +85,7 @@ func ExampleFile_GetSheetPrOptions() { // - enableFormatConditionsCalculation: true // - published: true // - fitToPage: false + // - tabColor: "" // - autoPageBreaks: false // - outlineSummaryBelow: true } @@ -94,6 +101,7 @@ func TestSheetPrOptions(t *testing.T) { {new(EnableFormatConditionsCalculation), EnableFormatConditionsCalculation(false)}, {new(Published), Published(false)}, {new(FitToPage), FitToPage(true)}, + {new(TabColor), TabColor("FFFF00")}, {new(AutoPageBreaks), AutoPageBreaks(true)}, {new(OutlineSummaryBelow), OutlineSummaryBelow(false)}, } @@ -147,6 +155,7 @@ func TestSheetPrOptions(t *testing.T) { func TestSetSheetrOptions(t *testing.T) { f := NewFile() + assert.NoError(t, f.SetSheetPrOptions("Sheet1", TabColor(""))) // Test SetSheetrOptions on not exists worksheet. assert.EqualError(t, f.SetSheetPrOptions("SheetN"), "sheet SheetN is not exist") } |