Skip to content

Commit

Permalink
Resolve qax-os#394, init set header and footer support
Browse files Browse the repository at this point in the history
  • Loading branch information
xuri committed May 5, 2019
1 parent 72701e8 commit 69b38dd
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 37 deletions.
30 changes: 15 additions & 15 deletions datavalidation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,44 +19,44 @@ import (
func TestDataValidation(t *testing.T) {
resultFile := filepath.Join("test", "TestDataValidation.xlsx")

xlsx := NewFile()
f := NewFile()

dvRange := NewDataValidation(true)
dvRange.Sqref = "A1:B2"
dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorBetween)
dvRange.SetError(DataValidationErrorStyleStop, "error title", "error body")
dvRange.SetError(DataValidationErrorStyleWarning, "error title", "error body")
dvRange.SetError(DataValidationErrorStyleInformation, "error title", "error body")
xlsx.AddDataValidation("Sheet1", dvRange)
if !assert.NoError(t, xlsx.SaveAs(resultFile)) {
f.AddDataValidation("Sheet1", dvRange)
if !assert.NoError(t, f.SaveAs(resultFile)) {
t.FailNow()
}

dvRange = NewDataValidation(true)
dvRange.Sqref = "A3:B4"
dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan)
dvRange.SetInput("input title", "input body")
xlsx.AddDataValidation("Sheet1", dvRange)
if !assert.NoError(t, xlsx.SaveAs(resultFile)) {
f.AddDataValidation("Sheet1", dvRange)
if !assert.NoError(t, f.SaveAs(resultFile)) {
t.FailNow()
}

dvRange = NewDataValidation(true)
dvRange.Sqref = "A5:B6"
dvRange.SetDropList([]string{"1", "2", "3"})
xlsx.AddDataValidation("Sheet1", dvRange)
if !assert.NoError(t, xlsx.SaveAs(resultFile)) {
f.AddDataValidation("Sheet1", dvRange)
if !assert.NoError(t, f.SaveAs(resultFile)) {
t.FailNow()
}
}

func TestDataValidationError(t *testing.T) {
resultFile := filepath.Join("test", "TestDataValidationError.xlsx")

xlsx := NewFile()
xlsx.SetCellStr("Sheet1", "E1", "E1")
xlsx.SetCellStr("Sheet1", "E2", "E2")
xlsx.SetCellStr("Sheet1", "E3", "E3")
f := NewFile()
f.SetCellStr("Sheet1", "E1", "E1")
f.SetCellStr("Sheet1", "E2", "E2")
f.SetCellStr("Sheet1", "E3", "E3")

dvRange := NewDataValidation(true)
dvRange.SetSqref("A7:B8")
Expand All @@ -66,8 +66,8 @@ func TestDataValidationError(t *testing.T) {
err := dvRange.SetSqrefDropList("$E$1:$E$3", false)
assert.EqualError(t, err, "cross-sheet sqref cell are not supported")

xlsx.AddDataValidation("Sheet1", dvRange)
if !assert.NoError(t, xlsx.SaveAs(resultFile)) {
f.AddDataValidation("Sheet1", dvRange)
if !assert.NoError(t, f.SaveAs(resultFile)) {
t.FailNow()
}

Expand All @@ -81,8 +81,8 @@ func TestDataValidationError(t *testing.T) {
dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan)
dvRange.SetSqref("A9:B10")

xlsx.AddDataValidation("Sheet1", dvRange)
if !assert.NoError(t, xlsx.SaveAs(resultFile)) {
f.AddDataValidation("Sheet1", dvRange)
if !assert.NoError(t, f.SaveAs(resultFile)) {
t.FailNow()
}
}
8 changes: 4 additions & 4 deletions excelize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -789,9 +789,9 @@ func TestCopySheet(t *testing.T) {
}

idx := f.NewSheet("CopySheet")
assert.EqualError(t, f.CopySheet(1, idx), "sheet sheet1 is not exist")
assert.NoError(t, f.CopySheet(1, idx))

f.SetCellValue("Sheet4", "F1", "Hello")
f.SetCellValue("CopySheet", "F1", "Hello")
val, err := f.GetCellValue("Sheet1", "F1")
assert.NoError(t, err)
assert.NotEqual(t, "Hello", val)
Expand All @@ -805,8 +805,8 @@ func TestCopySheetError(t *testing.T) {
t.FailNow()
}

err = f.CopySheet(0, -1)
if !assert.EqualError(t, err, "invalid worksheet index") {
assert.EqualError(t, f.copySheet(0, -1), "sheet is not exist")
if !assert.EqualError(t, f.CopySheet(0, -1), "invalid worksheet index") {
t.FailNow()
}

Expand Down
155 changes: 153 additions & 2 deletions sheet.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"os"
"path"
"reflect"
"regexp"
"strconv"
"strings"
Expand Down Expand Up @@ -466,7 +468,7 @@ func (f *File) CopySheet(from, to int) error {
// copySheet provides a function to duplicate a worksheet by gave source and
// target worksheet name.
func (f *File) copySheet(from, to int) error {
sheet, err := f.workSheetReader("sheet" + strconv.Itoa(from))
sheet, err := f.workSheetReader(f.GetSheetName(from))
if err != nil {
return err
}
Expand Down Expand Up @@ -761,6 +763,155 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
return result, nil
}

// SetHeaderFooter provides a function to set headers and footers by given
// worksheet name and the control characters.
//
// Headers and footers are specified using the following settings fields:
//
// Fields | Description
// ------------------+-----------------------------------------------------------
// AlignWithMargins | Align header footer margins with page margins
// DifferentFirst | Different first-page header and footer indicator
// DifferentOddEven | Different odd and even page headers and footers indicator
// ScaleWithDoc | Scale header and footer with document scaling
// OddFooter | Odd Page Footer
// OddHeader | Odd Header
// EvenFooter | Even Page Footer
// EvenHeader | Even Page Header
// FirstFooter | First Page Footer
// FirstHeader | First Page Header
//
// The following formatting codes can be used in 6 string type fields:
// OddHeader, OddFooter, EvenHeader, EvenFooter, FirstFooter, FirstHeader
//
// Formatting Code | Description
// ------------------------+-------------------------------------------------------------------------
// && | The character "&"
// |
// &font-size | Size of the text font, where font-size is a decimal font size in points
// |
// &"font name,font type" | A text font-name string, font name, and a text font-type string,
// | font type
// |
// &"-,Regular" | Regular text format. Toggles bold and italic modes to off
// |
// &A | Current worksheet's tab name
// |
// &B or &"-,Bold" | Bold text format, from off to on, or vice versa. The default mode is off
// |
// &D | Current date
// |
// &C | Center section
// |
// &E | Double-underline text format
// |
// &F | Current workbook's file name
// |
// &G | Drawing object as background
// |
// &H | Shadow text format
// |
// &I or &"-,Italic" | Italic text format
// |
// &K | Text font color
// |
// | An RGB Color is specified as RRGGBB
// |
// | A Theme Color is specified as TTSNNN where TT is the theme color Id,
// | S is either "+" or "-" of the tint/shade value, and NNN is the
// | tint/shade value
// |
// &L | Left section
// |
// &N | Total number of pages
// |
// &O | Outline text format
// |
// &P[[+|-]n] | Without the optional suffix, the current page number in decimal
// |
// &R | Right section
// |
// &S | Strikethrough text format
// |
// &T | Current time
// |
// &U | Single-underline text format. If double-underline mode is on, the next
// | occurrence in a section specifier toggles double-underline mode to off;
// | otherwise, it toggles single-underline mode, from off to on, or vice
// | versa. The default mode is off
// |
// &X | Superscript text format
// |
// &Y | Subscript text format
// |
// &Z | Current workbook's file path
//
// For example:
//
// err := f.SetHeaderFooter("Sheet1", &excelize.FormatHeaderFooter{
// DifferentFirst: true,
// DifferentOddEven: true,
// OddHeader: "&R&P",
// OddFooter: "&C&F",
// EvenHeader: "&L&P",
// EvenFooter: "&L&D&R&T",
// FirstHeader: `&CCenter &"-,Bold"Bold&"-,Regular"HeaderU+000A&D`,
// })
//
// This example shows:
//
// - The first page has its own header and footer
//
// - Odd and even-numbered pages have different headers and footers
//
// - Current page number in the right section of odd-page headers
//
// - Current workbook's file name in the center section of odd-page footers
//
// - Current page number in the left section of even-page headers
//
// - Current date in the left section and the current time in the right section
// of even-page footers
//
// - The text "Center Bold Header" on the first line of the center section of
// the first page, and the date on the second line of the center section of
// that same page
//
// - No footer on the first page
//
func (f *File) SetHeaderFooter(sheet string, settings *FormatHeaderFooter) error {
xlsx, err := f.workSheetReader(sheet)
if err != nil {
return err
}
if settings == nil {
xlsx.HeaderFooter = nil
return err
}

v := reflect.ValueOf(*settings)
// Check 6 string type fields: OddHeader, OddFooter, EvenHeader, EvenFooter,
// FirstFooter, FirstHeader
for i := 4; i < v.NumField()-1; i++ {
if v.Field(i).Len() >= 255 {
return fmt.Errorf("field %s must be less than 255 characters", v.Type().Field(i).Name)
}
}
xlsx.HeaderFooter = &xlsxHeaderFooter{
AlignWithMargins: settings.AlignWithMargins,
DifferentFirst: settings.DifferentFirst,
DifferentOddEven: settings.DifferentOddEven,
ScaleWithDoc: settings.ScaleWithDoc,
OddHeader: settings.OddHeader,
OddFooter: settings.OddFooter,
EvenHeader: settings.EvenHeader,
EvenFooter: settings.EvenFooter,
FirstFooter: settings.FirstFooter,
FirstHeader: settings.FirstHeader,
}
return err
}

// ProtectSheet provides a function to prevent other users from accidentally
// or deliberately changing, moving, or deleting data in a worksheet. For
// example, protect Sheet1 with protection settings:
Expand Down Expand Up @@ -898,7 +1049,7 @@ func (p *PageLayoutPaperSize) getPageLayout(ps *xlsxPageSetUp) {
//
// Available options:
// PageLayoutOrientation(string)
// PageLayoutPaperSize(int)
// PageLayoutPaperSize(int)
//
// The following shows the paper size sorted by excelize index number:
//
Expand Down
Loading

0 comments on commit 69b38dd

Please sign in to comment.