Skip to content

Commit b23e5a2

Browse files
authored
This closes #1076, add new function MoveSheet to support changing sheet order in the workbook (#1996)
- Add unit tests
1 parent bebb802 commit b23e5a2

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

sheet.go

+43
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,49 @@ func (f *File) DeleteSheet(sheet string) error {
600600
return err
601601
}
602602

603+
// MoveSheet moves a sheet to a specified position in the workbook. The function
604+
// moves the source sheet before the target sheet. After moving, other sheets
605+
// will be shifted to the left or right. If the sheet is already at the target
606+
// position, the function will not perform any action. Not that this function
607+
// will be ungroup all sheets after moving. For example, move Sheet2 before
608+
// Sheet1:
609+
//
610+
// err := f.MoveSheet("Sheet2", "Sheet1")
611+
func (f *File) MoveSheet(source, target string) error {
612+
if strings.EqualFold(source, target) {
613+
return nil
614+
}
615+
wb, err := f.workbookReader()
616+
if err != nil {
617+
return err
618+
}
619+
sourceIdx, err := f.GetSheetIndex(source)
620+
if err != nil {
621+
return err
622+
}
623+
targetIdx, err := f.GetSheetIndex(target)
624+
if err != nil {
625+
return err
626+
}
627+
if sourceIdx < 0 {
628+
return ErrSheetNotExist{source}
629+
}
630+
if targetIdx < 0 {
631+
return ErrSheetNotExist{target}
632+
}
633+
_ = f.UngroupSheets()
634+
activeSheetName := f.GetSheetName(f.GetActiveSheetIndex())
635+
sourceSheet := wb.Sheets.Sheet[sourceIdx]
636+
wb.Sheets.Sheet = append(wb.Sheets.Sheet[:sourceIdx], wb.Sheets.Sheet[sourceIdx+1:]...)
637+
if targetIdx > sourceIdx {
638+
targetIdx--
639+
}
640+
wb.Sheets.Sheet = append(wb.Sheets.Sheet[:targetIdx], append([]xlsxSheet{sourceSheet}, wb.Sheets.Sheet[targetIdx:]...)...)
641+
activeSheetIdx, _ := f.GetSheetIndex(activeSheetName)
642+
f.SetActiveSheet(activeSheetIdx)
643+
return err
644+
}
645+
603646
// deleteAndAdjustDefinedNames delete and adjust defined name in the workbook
604647
// by given worksheet ID.
605648
func deleteAndAdjustDefinedNames(wb *xlsxWorkbook, deleteLocalSheetID int) {

sheet_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,43 @@ func TestDeleteSheet(t *testing.T) {
547547
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeleteSheet2.xlsx")))
548548
}
549549

550+
func TestMoveSheet(t *testing.T) {
551+
f := NewFile()
552+
defer f.Close()
553+
for i := 2; i < 6; i++ {
554+
_, err := f.NewSheet("Sheet" + strconv.Itoa(i))
555+
assert.NoError(t, err)
556+
}
557+
assert.Equal(t, []string{"Sheet1", "Sheet2", "Sheet3", "Sheet4", "Sheet5"}, f.GetSheetList())
558+
559+
// Move target to first position
560+
assert.NoError(t, f.MoveSheet("Sheet2", "Sheet1"))
561+
assert.Equal(t, []string{"Sheet2", "Sheet1", "Sheet3", "Sheet4", "Sheet5"}, f.GetSheetList())
562+
assert.Equal(t, "Sheet1", f.GetSheetName(f.GetActiveSheetIndex()))
563+
564+
// Move target to last position
565+
assert.NoError(t, f.MoveSheet("Sheet2", "Sheet5"))
566+
assert.NoError(t, f.MoveSheet("Sheet5", "Sheet2"))
567+
assert.Equal(t, []string{"Sheet1", "Sheet3", "Sheet4", "Sheet5", "Sheet2"}, f.GetSheetList())
568+
569+
// Move target to same position
570+
assert.NoError(t, f.MoveSheet("Sheet1", "Sheet1"))
571+
assert.Equal(t, []string{"Sheet1", "Sheet3", "Sheet4", "Sheet5", "Sheet2"}, f.GetSheetList())
572+
573+
// Test move sheet with invalid sheet name
574+
assert.Equal(t, ErrSheetNameBlank, f.MoveSheet("", "Sheet2"))
575+
assert.Equal(t, ErrSheetNameBlank, f.MoveSheet("Sheet1", ""))
576+
577+
// Test move sheet on not exists worksheet
578+
assert.Equal(t, ErrSheetNotExist{"SheetN"}, f.MoveSheet("SheetN", "Sheet2"))
579+
assert.Equal(t, ErrSheetNotExist{"SheetN"}, f.MoveSheet("Sheet1", "SheetN"))
580+
581+
// Test move sheet with unsupported workbook charset
582+
f.WorkBook = nil
583+
f.Pkg.Store("xl/workbook.xml", MacintoshCyrillicCharset)
584+
assert.EqualError(t, f.MoveSheet("Sheet2", "Sheet1"), "XML syntax error on line 1: invalid UTF-8")
585+
}
586+
550587
func TestDeleteAndAdjustDefinedNames(t *testing.T) {
551588
deleteAndAdjustDefinedNames(nil, 0)
552589
deleteAndAdjustDefinedNames(&xlsxWorkbook{}, 0)

0 commit comments

Comments
 (0)