Skip to content
This repository was archived by the owner on Aug 13, 2025. It is now read-only.

Commit 0618e1b

Browse files
authored
Merge pull request #798 from martoche/fix-libreoffice-autofilter
fix AutoFilter not working in LibreOffice
2 parents e1849b7 + ea15a71 commit 0618e1b

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

file.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,41 @@ func addRelationshipNameSpaceToWorksheet(worksheetMarshal string) string {
296296
return newSheetMarshall
297297
}
298298

299+
func cellIDStringWithFixed(cellIDString string) string {
300+
letterPart := strings.Map(letterOnlyMapF, cellIDString)
301+
intPart := strings.Map(intOnlyMapF, cellIDString)
302+
303+
if letterPart != "" && intPart == "" {
304+
return fixedCellRefChar + letterPart
305+
} else if letterPart != "" && intPart != "" {
306+
return fixedCellRefChar + letterPart + fixedCellRefChar + intPart
307+
}
308+
309+
return ""
310+
}
311+
312+
// AutoFilter doesn't work in LibreOffice unless a special "FilterDatabase" tag
313+
// is present in the "DefinedNames" array. See:
314+
// - https://github.com/SheetJS/sheetjs/issues/1165
315+
// - https://bugs.documentfoundation.org/show_bug.cgi?id=118592
316+
func autoFilterDefinedName(sheet *Sheet, sheetIndex int) (*xlsxDefinedName, error) {
317+
if sheet.AutoFilter == nil {
318+
return nil, nil
319+
}
320+
321+
return &xlsxDefinedName{
322+
Data: fmt.Sprintf(
323+
"'%s'!%v:%v",
324+
strings.ReplaceAll(sheet.Name, "'", "''"),
325+
cellIDStringWithFixed(sheet.AutoFilter.TopLeftCell),
326+
cellIDStringWithFixed(sheet.AutoFilter.BottomRightCell),
327+
),
328+
Name: "_xlnm._FilterDatabase",
329+
LocalSheetID: sheetIndex - 1,
330+
Hidden: true,
331+
}, nil
332+
}
333+
299334
// MakeStreamParts constructs a map of file name to XML content
300335
// representing the file in terms of the structure of an XLSX file.
301336
func (f *File) MakeStreamParts() (map[string]string, error) {
@@ -370,6 +405,14 @@ func (f *File) MakeStreamParts() (map[string]string, error) {
370405
return parts, err
371406
}
372407
}
408+
409+
definedName, err := autoFilterDefinedName(sheet, sheetIndex)
410+
if err != nil {
411+
return parts, err
412+
} else if definedName != nil {
413+
workbook.DefinedNames.DefinedName = append(workbook.DefinedNames.DefinedName, *definedName)
414+
}
415+
373416
sheetIndex++
374417
}
375418

@@ -511,6 +554,14 @@ func (f *File) MarshallParts(zipWriter *zip.Writer) error {
511554
return wrap(err)
512555
}
513556
}
557+
558+
definedName, err := autoFilterDefinedName(sheet, sheetIndex)
559+
if err != nil {
560+
return wrap(err)
561+
} else if definedName != nil {
562+
workbook.DefinedNames.DefinedName = append(workbook.DefinedNames.DefinedName, *definedName)
563+
}
564+
514565
sheetIndex++
515566
}
516567

file_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,25 @@ func TestFile(t *testing.T) {
965965
c.Assert(s.Hidden, qt.Equals, true)
966966
})
967967

968+
csRunO(c, "TestMarshalFileWithAutoFilter", func(c *qt.C, option FileOption) {
969+
var f *File
970+
f = NewFile(option)
971+
sheet1, _ := f.AddSheet("MySheet")
972+
sheet1.AutoFilter = &AutoFilter{
973+
TopLeftCell: "A1",
974+
BottomRightCell: "D",
975+
}
976+
977+
row1 := sheet1.AddRow()
978+
cell1 := row1.AddCell()
979+
cell1.SetString("A cell!")
980+
981+
parts, err := f.MakeStreamParts()
982+
c.Assert(err, qt.IsNil)
983+
c.Assert(parts["xl/workbook.xml"], qt.Contains, `<definedNames><definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="true">&#39;MySheet&#39;!$A$1:$D</definedName></definedNames>`)
984+
c.Assert(parts["xl/worksheets/sheet1.xml"], qt.Contains, `<autoFilter ref="A1:D"></autoFilter>`)
985+
})
986+
968987
// We can save a File as a valid XLSX file at a given path.
969988
csRunO(c, "TestSaveFileWithHyperlinks", func(c *qt.C, option FileOption) {
970989
tmpPath, err := ioutil.TempDir("", "testsavefilewithhyperlinks")

xmlWorkbook.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ type xlsxDefinedName struct {
141141
Help string `xml:"help,attr,omitempty"`
142142
ShortcutKey string `xml:"shortcutKey,attr,omitempty"`
143143
StatusBar string `xml:"statusBar,attr,omitempty"`
144-
LocalSheetID int `xml:"localSheetId,attr,omitempty"`
144+
LocalSheetID int `xml:"localSheetId,attr"`
145145
FunctionGroupID int `xml:"functionGroupId,attr,omitempty"`
146146
Function bool `xml:"function,attr,omitempty"`
147147
Hidden bool `xml:"hidden,attr,omitempty"`

0 commit comments

Comments
 (0)