@@ -18,6 +18,7 @@ import (
18
18
"io"
19
19
"log"
20
20
"math"
21
+ "reflect"
21
22
"strconv"
22
23
"strings"
23
24
)
@@ -1920,30 +1921,110 @@ func (f *File) NewStyle(style interface{}) (int, error) {
1920
1921
return cellXfsID , errors .New ("invalid parameter type" )
1921
1922
}
1922
1923
s := f .stylesReader ()
1923
- numFmtID := setNumFmt (s , fs )
1924
+ // check given style already exist.
1925
+ if cellXfsID = f .getStyleID (s , fs ); cellXfsID != - 1 {
1926
+ return cellXfsID , err
1927
+ }
1928
+
1929
+ numFmtID := newNumFmt (s , fs )
1924
1930
1925
1931
if fs .Font != nil {
1926
- s .Fonts .Count ++
1927
- s .Fonts .Font = append (s .Fonts .Font , f .setFont (fs ))
1928
- fontID = s .Fonts .Count - 1
1932
+ fontID = f .getFontID (s , fs )
1933
+ if fontID == - 1 {
1934
+ s .Fonts .Count ++
1935
+ s .Fonts .Font = append (s .Fonts .Font , f .newFont (fs ))
1936
+ fontID = s .Fonts .Count - 1
1937
+ }
1929
1938
}
1930
1939
1931
- s .Borders .Count ++
1932
- s .Borders .Border = append (s .Borders .Border , setBorders (fs ))
1933
- borderID = s .Borders .Count - 1
1940
+ borderID = getBorderID (s , fs )
1941
+ if borderID == - 1 {
1942
+ if len (fs .Border ) == 0 {
1943
+ borderID = 0
1944
+ } else {
1945
+ s .Borders .Count ++
1946
+ s .Borders .Border = append (s .Borders .Border , newBorders (fs ))
1947
+ borderID = s .Borders .Count - 1
1948
+ }
1949
+ }
1934
1950
1935
- if fill := setFills (fs , true ); fill != nil {
1936
- s .Fills .Count ++
1937
- s .Fills .Fill = append (s .Fills .Fill , fill )
1938
- fillID = s .Fills .Count - 1
1951
+ if fillID = getFillID (s , fs ); fillID == - 1 {
1952
+ if fill := newFills (fs , true ); fill != nil {
1953
+ s .Fills .Count ++
1954
+ s .Fills .Fill = append (s .Fills .Fill , fill )
1955
+ fillID = s .Fills .Count - 1
1956
+ } else {
1957
+ fillID = 0
1958
+ }
1939
1959
}
1940
1960
1941
- applyAlignment , alignment := fs .Alignment != nil , setAlignment (fs )
1942
- applyProtection , protection := fs .Protection != nil , setProtection (fs )
1961
+ applyAlignment , alignment := fs .Alignment != nil , newAlignment (fs )
1962
+ applyProtection , protection := fs .Protection != nil , newProtection (fs )
1943
1963
cellXfsID = setCellXfs (s , fontID , numFmtID , fillID , borderID , applyAlignment , applyProtection , alignment , protection )
1944
1964
return cellXfsID , nil
1945
1965
}
1946
1966
1967
+ var getXfIDFuncs = map [string ]func (int , xlsxXf , * Style ) bool {
1968
+ "numFmt" : func (numFmtID int , xf xlsxXf , style * Style ) bool {
1969
+ return xf .NumFmtID != nil && * xf .NumFmtID == numFmtID
1970
+ },
1971
+ "font" : func (fontID int , xf xlsxXf , style * Style ) bool {
1972
+ if style .Font == nil {
1973
+ return (xf .FontID == nil || * xf .FontID == 0 ) && (xf .ApplyFont == nil || * xf .ApplyFont == false )
1974
+ }
1975
+ return xf .FontID != nil && * xf .FontID == fontID && xf .ApplyFont != nil && * xf .ApplyFont == true
1976
+ },
1977
+ "fill" : func (fillID int , xf xlsxXf , style * Style ) bool {
1978
+ if style .Fill .Type == "" {
1979
+ return (xf .FillID == nil || * xf .FillID == 0 ) && (xf .ApplyFill == nil || * xf .ApplyFill == false )
1980
+ }
1981
+ return xf .FillID != nil && * xf .FillID == fillID && xf .ApplyFill != nil && * xf .ApplyFill == true
1982
+ },
1983
+ "border" : func (borderID int , xf xlsxXf , style * Style ) bool {
1984
+ if len (style .Border ) == 0 {
1985
+ return (xf .BorderID == nil || * xf .BorderID == 0 ) && (xf .ApplyBorder == nil || * xf .ApplyBorder == false )
1986
+ }
1987
+ return xf .BorderID != nil && * xf .BorderID == borderID && xf .ApplyBorder != nil && * xf .ApplyBorder == true
1988
+ },
1989
+ "alignment" : func (ID int , xf xlsxXf , style * Style ) bool {
1990
+ if style .Alignment == nil {
1991
+ return xf .ApplyAlignment == nil || * xf .ApplyAlignment == false
1992
+ }
1993
+ return reflect .DeepEqual (xf .Alignment , newAlignment (style )) && xf .ApplyBorder != nil && * xf .ApplyBorder == true
1994
+ },
1995
+ "protection" : func (ID int , xf xlsxXf , style * Style ) bool {
1996
+ if style .Protection == nil {
1997
+ return xf .ApplyProtection == nil || * xf .ApplyProtection == false
1998
+ }
1999
+ return reflect .DeepEqual (xf .Protection , newProtection (style )) && xf .ApplyProtection != nil && * xf .ApplyProtection == true
2000
+ },
2001
+ }
2002
+
2003
+ // getStyleID provides a function to get styleID by given style. If given
2004
+ // style is not exist, will return -1.
2005
+ func (f * File ) getStyleID (ss * xlsxStyleSheet , style * Style ) (styleID int ) {
2006
+ styleID = - 1
2007
+ if ss .CellXfs == nil {
2008
+ return
2009
+ }
2010
+ numFmtID , borderID , fillID , fontID := style .NumFmt , getBorderID (ss , style ), getFillID (ss , style ), f .getFontID (ss , style )
2011
+ if style .CustomNumFmt != nil {
2012
+ numFmtID = getCustomNumFmtID (ss , style )
2013
+ }
2014
+ for xfID , xf := range ss .CellXfs .Xf {
2015
+ if getXfIDFuncs ["numFmt" ](numFmtID , xf , style ) &&
2016
+ getXfIDFuncs ["font" ](fontID , xf , style ) &&
2017
+ getXfIDFuncs ["fill" ](fillID , xf , style ) &&
2018
+ getXfIDFuncs ["border" ](borderID , xf , style ) &&
2019
+ getXfIDFuncs ["alignment" ](0 , xf , style ) &&
2020
+ getXfIDFuncs ["protection" ](0 , xf , style ) {
2021
+ styleID = xfID
2022
+ return
2023
+ }
2024
+ }
2025
+ return
2026
+ }
2027
+
1947
2028
// NewConditionalStyle provides a function to create style for conditional
1948
2029
// format by given style format. The parameters are the same as function
1949
2030
// NewStyle(). Note that the color field uses RGB color code and only support
@@ -1955,16 +2036,16 @@ func (f *File) NewConditionalStyle(style string) (int, error) {
1955
2036
return 0 , err
1956
2037
}
1957
2038
dxf := dxf {
1958
- Fill : setFills (fs , false ),
2039
+ Fill : newFills (fs , false ),
1959
2040
}
1960
2041
if fs .Alignment != nil {
1961
- dxf .Alignment = setAlignment (fs )
2042
+ dxf .Alignment = newAlignment (fs )
1962
2043
}
1963
2044
if len (fs .Border ) > 0 {
1964
- dxf .Border = setBorders (fs )
2045
+ dxf .Border = newBorders (fs )
1965
2046
}
1966
2047
if fs .Font != nil {
1967
- dxf .Font = f .setFont (fs )
2048
+ dxf .Font = f .newFont (fs )
1968
2049
}
1969
2050
dxfStr , _ := xml .Marshal (dxf )
1970
2051
if s .Dxfs == nil {
@@ -2000,9 +2081,25 @@ func (f *File) readDefaultFont() *xlsxFont {
2000
2081
return s .Fonts .Font [0 ]
2001
2082
}
2002
2083
2003
- // setFont provides a function to add font style by given cell format
2084
+ // getFontID provides a function to get font ID.
2085
+ // If given font is not exist, will return -1.
2086
+ func (f * File ) getFontID (styleSheet * xlsxStyleSheet , style * Style ) (fontID int ) {
2087
+ fontID = - 1
2088
+ if styleSheet .Fonts == nil || style .Font == nil {
2089
+ return
2090
+ }
2091
+ for idx , fnt := range styleSheet .Fonts .Font {
2092
+ if reflect .DeepEqual (* fnt , * f .newFont (style )) {
2093
+ fontID = idx
2094
+ return
2095
+ }
2096
+ }
2097
+ return
2098
+ }
2099
+
2100
+ // newFont provides a function to add font style by given cell format
2004
2101
// settings.
2005
- func (f * File ) setFont (style * Style ) * xlsxFont {
2102
+ func (f * File ) newFont (style * Style ) * xlsxFont {
2006
2103
fontUnderlineType := map [string ]string {"single" : "single" , "double" : "double" }
2007
2104
if style .Font .Size < 1 {
2008
2105
style .Font .Size = 11
@@ -2036,9 +2133,9 @@ func (f *File) setFont(style *Style) *xlsxFont {
2036
2133
return & fnt
2037
2134
}
2038
2135
2039
- // setNumFmt provides a function to check if number format code in the range
2136
+ // newNumFmt provides a function to check if number format code in the range
2040
2137
// of built-in values.
2041
- func setNumFmt (styleSheet * xlsxStyleSheet , style * Style ) int {
2138
+ func newNumFmt (styleSheet * xlsxStyleSheet , style * Style ) int {
2042
2139
dp := "0."
2043
2140
numFmtID := 164 // Default custom number format code from 164.
2044
2141
if style .DecimalPlaces < 0 || style .DecimalPlaces > 30 {
@@ -2048,6 +2145,9 @@ func setNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
2048
2145
dp += "0"
2049
2146
}
2050
2147
if style .CustomNumFmt != nil {
2148
+ if customNumFmtID := getCustomNumFmtID (styleSheet , style ); customNumFmtID != - 1 {
2149
+ return customNumFmtID
2150
+ }
2051
2151
return setCustomNumFmt (styleSheet , style )
2052
2152
}
2053
2153
_ , ok := builtInNumFmt [style .NumFmt ]
@@ -2102,6 +2202,22 @@ func setCustomNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
2102
2202
return nf .NumFmtID
2103
2203
}
2104
2204
2205
+ // getCustomNumFmtID provides a function to get custom number format code ID.
2206
+ // If given custom number format code is not exist, will return -1.
2207
+ func getCustomNumFmtID (styleSheet * xlsxStyleSheet , style * Style ) (customNumFmtID int ) {
2208
+ customNumFmtID = - 1
2209
+ if styleSheet .NumFmts == nil {
2210
+ return
2211
+ }
2212
+ for _ , numFmt := range styleSheet .NumFmts .NumFmt {
2213
+ if style .CustomNumFmt != nil && numFmt .FormatCode == * style .CustomNumFmt {
2214
+ customNumFmtID = numFmt .NumFmtID
2215
+ return
2216
+ }
2217
+ }
2218
+ return
2219
+ }
2220
+
2105
2221
// setLangNumFmt provides a function to set number format code with language.
2106
2222
func setLangNumFmt (styleSheet * xlsxStyleSheet , style * Style ) int {
2107
2223
numFmts , ok := langNumFmt [style .Lang ]
@@ -2129,9 +2245,29 @@ func setLangNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
2129
2245
return nf .NumFmtID
2130
2246
}
2131
2247
2132
- // setFills provides a function to add fill elements in the styles.xml by
2248
+ // getFillID provides a function to get fill ID. If given fill is not
2249
+ // exist, will return -1.
2250
+ func getFillID (styleSheet * xlsxStyleSheet , style * Style ) (fillID int ) {
2251
+ fillID = - 1
2252
+ if styleSheet .Fills == nil || style .Fill .Type == "" {
2253
+ return
2254
+ }
2255
+ fills := newFills (style , true )
2256
+ if fills == nil {
2257
+ return
2258
+ }
2259
+ for idx , fill := range styleSheet .Fills .Fill {
2260
+ if reflect .DeepEqual (fill , fills ) {
2261
+ fillID = idx
2262
+ return
2263
+ }
2264
+ }
2265
+ return
2266
+ }
2267
+
2268
+ // newFills provides a function to add fill elements in the styles.xml by
2133
2269
// given cell format settings.
2134
- func setFills (style * Style , fg bool ) * xlsxFill {
2270
+ func newFills (style * Style , fg bool ) * xlsxFill {
2135
2271
var patterns = []string {
2136
2272
"none" ,
2137
2273
"solid" ,
@@ -2212,11 +2348,11 @@ func setFills(style *Style, fg bool) *xlsxFill {
2212
2348
return & fill
2213
2349
}
2214
2350
2215
- // setAlignment provides a function to formatting information pertaining to
2351
+ // newAlignment provides a function to formatting information pertaining to
2216
2352
// text alignment in cells. There are a variety of choices for how text is
2217
2353
// aligned both horizontally and vertically, as well as indentation settings,
2218
2354
// and so on.
2219
- func setAlignment (style * Style ) * xlsxAlignment {
2355
+ func newAlignment (style * Style ) * xlsxAlignment {
2220
2356
var alignment xlsxAlignment
2221
2357
if style .Alignment != nil {
2222
2358
alignment .Horizontal = style .Alignment .Horizontal
@@ -2232,9 +2368,9 @@ func setAlignment(style *Style) *xlsxAlignment {
2232
2368
return & alignment
2233
2369
}
2234
2370
2235
- // setProtection provides a function to set protection properties associated
2371
+ // newProtection provides a function to set protection properties associated
2236
2372
// with the cell.
2237
- func setProtection (style * Style ) * xlsxProtection {
2373
+ func newProtection (style * Style ) * xlsxProtection {
2238
2374
var protection xlsxProtection
2239
2375
if style .Protection != nil {
2240
2376
protection .Hidden = style .Protection .Hidden
@@ -2243,9 +2379,25 @@ func setProtection(style *Style) *xlsxProtection {
2243
2379
return & protection
2244
2380
}
2245
2381
2246
- // setBorders provides a function to add border elements in the styles.xml by
2382
+ // getBorderID provides a function to get border ID. If given border is not
2383
+ // exist, will return -1.
2384
+ func getBorderID (styleSheet * xlsxStyleSheet , style * Style ) (borderID int ) {
2385
+ borderID = - 1
2386
+ if styleSheet .Borders == nil || len (style .Border ) == 0 {
2387
+ return
2388
+ }
2389
+ for idx , border := range styleSheet .Borders .Border {
2390
+ if reflect .DeepEqual (* border , * newBorders (style )) {
2391
+ borderID = idx
2392
+ return
2393
+ }
2394
+ }
2395
+ return
2396
+ }
2397
+
2398
+ // newBorders provides a function to add border elements in the styles.xml by
2247
2399
// given borders format settings.
2248
- func setBorders (style * Style ) * xlsxBorder {
2400
+ func newBorders (style * Style ) * xlsxBorder {
2249
2401
var styles = []string {
2250
2402
"none" ,
2251
2403
"thin" ,
@@ -2308,10 +2460,18 @@ func setCellXfs(style *xlsxStyleSheet, fontID, numFmtID, fillID, borderID int, a
2308
2460
xf .ApplyNumberFormat = boolPtr (true )
2309
2461
}
2310
2462
xf .FillID = intPtr (fillID )
2463
+ if fillID != 0 {
2464
+ xf .ApplyFill = boolPtr (true )
2465
+ }
2311
2466
xf .BorderID = intPtr (borderID )
2467
+ if borderID != 0 {
2468
+ xf .ApplyBorder = boolPtr (true )
2469
+ }
2312
2470
style .CellXfs .Count ++
2313
2471
xf .Alignment = alignment
2314
- xf .ApplyAlignment = boolPtr (applyAlignment )
2472
+ if alignment != nil {
2473
+ xf .ApplyAlignment = boolPtr (applyAlignment )
2474
+ }
2315
2475
if applyProtection {
2316
2476
xf .ApplyProtection = boolPtr (applyProtection )
2317
2477
xf .Protection = protection
0 commit comments