OSDN Git Service

This closes #652, new SetColWidth API, support set column width in stream writing...
authorxuri <xuri.me@gmail.com>
Sun, 9 May 2021 16:09:24 +0000 (00:09 +0800)
committerxuri <xuri.me@gmail.com>
Sun, 9 May 2021 16:09:24 +0000 (00:09 +0800)
24 files changed:
adjust.go
adjust_test.go
calc.go
calc_test.go
cell.go
chart.go
chart_test.go
col.go
col_test.go
date.go
date_test.go
errors.go
excelize.go
excelize_test.go
file.go
lib.go
lib_test.go
picture.go
picture_test.go
rows.go
rows_test.go
sheet.go
stream.go
stream_test.go

index e06d4f6..28b62cc 100644 (file)
--- a/adjust.go
+++ b/adjust.go
@@ -12,7 +12,6 @@
 package excelize
 
 import (
-       "errors"
        "strings"
 )
 
@@ -219,7 +218,7 @@ func areaRangeToCoordinates(firstCell, lastCell string) ([]int, error) {
 // correct C1:B3 to B1:C3.
 func sortCoordinates(coordinates []int) error {
        if len(coordinates) != 4 {
-               return errors.New("coordinates length must be 4")
+               return ErrCoordinates
        }
        if coordinates[2] < coordinates[0] {
                coordinates[2], coordinates[0] = coordinates[0], coordinates[2]
@@ -234,7 +233,7 @@ func sortCoordinates(coordinates []int) error {
 // to area reference.
 func (f *File) coordinatesToAreaRef(coordinates []int) (string, error) {
        if len(coordinates) != 4 {
-               return "", errors.New("coordinates length must be 4")
+               return "", ErrCoordinates
        }
        firstCell, err := CoordinatesToCellName(coordinates[0], coordinates[1])
        if err != nil {
index bdbaebe..0d63ed6 100644 (file)
@@ -113,7 +113,7 @@ func TestAdjustCalcChain(t *testing.T) {
 func TestCoordinatesToAreaRef(t *testing.T) {
        f := NewFile()
        _, err := f.coordinatesToAreaRef([]int{})
-       assert.EqualError(t, err, "coordinates length must be 4")
+       assert.EqualError(t, err, ErrCoordinates.Error())
        _, err = f.coordinatesToAreaRef([]int{1, -1, 1, 1})
        assert.EqualError(t, err, "invalid cell coordinates [1, -1]")
        _, err = f.coordinatesToAreaRef([]int{1, 1, 1, -1})
@@ -124,5 +124,5 @@ func TestCoordinatesToAreaRef(t *testing.T) {
 }
 
 func TestSortCoordinates(t *testing.T) {
-       assert.EqualError(t, sortCoordinates(make([]int, 3)), "coordinates length must be 4")
+       assert.EqualError(t, sortCoordinates(make([]int, 3)), ErrCoordinates.Error())
 }
diff --git a/calc.go b/calc.go
index b65a3c4..573abf2 100644 (file)
--- a/calc.go
+++ b/calc.go
@@ -647,7 +647,7 @@ func (f *File) evalInfixExp(sheet, cell string, tokens []efp.Token) (efp.Token,
                optStack.Pop()
        }
        if opdStack.Len() == 0 {
-               return efp.Token{}, errors.New("formula not valid")
+               return efp.Token{}, ErrInvalidFormula
        }
        return opdStack.Peek().(efp.Token), err
 }
@@ -849,7 +849,7 @@ func calcDiv(rOpd, lOpd string, opdStack *Stack) error {
 func calculate(opdStack *Stack, opt efp.Token) error {
        if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorPrefix {
                if opdStack.Len() < 1 {
-                       return errors.New("formula not valid")
+                       return ErrInvalidFormula
                }
                opd := opdStack.Pop().(efp.Token)
                opdVal, err := strconv.ParseFloat(opd.TValue, 64)
@@ -874,7 +874,7 @@ func calculate(opdStack *Stack, opt efp.Token) error {
        }
        if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorInfix {
                if opdStack.Len() < 2 {
-                       return errors.New("formula not valid")
+                       return ErrInvalidFormula
                }
                rOpd := opdStack.Pop().(efp.Token)
                lOpd := opdStack.Pop().(efp.Token)
@@ -885,7 +885,7 @@ func calculate(opdStack *Stack, opt efp.Token) error {
        fn, ok := tokenCalcFunc[opt.TValue]
        if ok {
                if opdStack.Len() < 2 {
-                       return errors.New("formula not valid")
+                       return ErrInvalidFormula
                }
                rOpd := opdStack.Pop().(efp.Token)
                lOpd := opdStack.Pop().(efp.Token)
index d5d5439..23568ff 100644 (file)
@@ -1710,12 +1710,12 @@ func TestCalcCellValue(t *testing.T) {
                "=POISSON(0,0,\"\")":     "strconv.ParseBool: parsing \"\": invalid syntax",
                "=POISSON(0,-1,TRUE)":    "#N/A",
                // SUM
-               "=SUM((":   "formula not valid",
-               "=SUM(-)":  "formula not valid",
-               "=SUM(1+)": "formula not valid",
-               "=SUM(1-)": "formula not valid",
-               "=SUM(1*)": "formula not valid",
-               "=SUM(1/)": "formula not valid",
+               "=SUM((":   ErrInvalidFormula.Error(),
+               "=SUM(-)":  ErrInvalidFormula.Error(),
+               "=SUM(1+)": ErrInvalidFormula.Error(),
+               "=SUM(1-)": ErrInvalidFormula.Error(),
+               "=SUM(1*)": ErrInvalidFormula.Error(),
+               "=SUM(1/)": ErrInvalidFormula.Error(),
                // SUMIF
                "=SUMIF()": "SUMIF requires at least 2 argument",
                // SUMSQ
diff --git a/cell.go b/cell.go
index 27d24d9..f94b81e 100644 (file)
--- a/cell.go
+++ b/cell.go
@@ -475,7 +475,7 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string, opts ...Hype
        }
 
        if len(ws.Hyperlinks.Hyperlink) > TotalSheetHyperlinks {
-               return errors.New("over maximum limit hyperlinks in a worksheet")
+               return ErrTotalSheetHyperlinks
        }
 
        switch linkType {
index 3ac460b..23ea776 100644 (file)
--- a/chart.go
+++ b/chart.go
@@ -919,7 +919,7 @@ func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
 func (f *File) AddChartSheet(sheet, format string, combo ...string) error {
        // Check if the worksheet already exists
        if f.GetSheetIndex(sheet) != -1 {
-               return errors.New("the same name worksheet already exists")
+               return ErrExistsWorksheet
        }
        formatSet, comboCharts, err := f.getFormatChart(format, combo)
        if err != nil {
index 6ee0a0f..657230b 100644 (file)
@@ -232,7 +232,7 @@ func TestAddChartSheet(t *testing.T) {
        // Test cell value on chartsheet
        assert.EqualError(t, f.SetCellValue("Chart1", "A1", true), "sheet Chart1 is chart sheet")
        // Test add chartsheet on already existing name sheet
-       assert.EqualError(t, f.AddChartSheet("Sheet1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`), "the same name worksheet already exists")
+       assert.EqualError(t, f.AddChartSheet("Sheet1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`), ErrExistsWorksheet.Error())
        // Test with unsupported chart type
        assert.EqualError(t, f.AddChartSheet("Chart2", `{"type":"unknown","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`), "unsupported chart type unknown")
 
diff --git a/col.go b/col.go
index 09a172a..e1ac5a5 100644 (file)
--- a/col.go
+++ b/col.go
@@ -14,7 +14,6 @@ package excelize
 import (
        "bytes"
        "encoding/xml"
-       "errors"
        "math"
        "strconv"
        "strings"
@@ -360,7 +359,7 @@ func (f *File) parseColRange(columns string) (start, end int, err error) {
 //
 func (f *File) SetColOutlineLevel(sheet, col string, level uint8) error {
        if level > 7 || level < 1 {
-               return errors.New("invalid outline level")
+               return ErrOutlineLevel
        }
        colNum, err := ColumnNameToNumber(col)
        if err != nil {
@@ -452,7 +451,7 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) error
                return err
        }
        if width > MaxColumnWidth {
-               return errors.New("the width of the column must be smaller than or equal to 255 characters")
+               return ErrColumnWidth
        }
        if min > max {
                min, max = max, min
index add1c11..6ab5e57 100644 (file)
@@ -246,12 +246,12 @@ func TestOutlineLevel(t *testing.T) {
        assert.EqualError(t, err, "sheet Shee2 is not exist")
 
        assert.NoError(t, f.SetColWidth("Sheet2", "A", "D", 13))
-       assert.EqualError(t, f.SetColWidth("Sheet2", "A", "D", MaxColumnWidth+1), "the width of the column must be smaller than or equal to 255 characters")
+       assert.EqualError(t, f.SetColWidth("Sheet2", "A", "D", MaxColumnWidth+1), ErrColumnWidth.Error())
 
        assert.NoError(t, f.SetColOutlineLevel("Sheet2", "B", 2))
        assert.NoError(t, f.SetRowOutlineLevel("Sheet1", 2, 7))
-       assert.EqualError(t, f.SetColOutlineLevel("Sheet1", "D", 8), "invalid outline level")
-       assert.EqualError(t, f.SetRowOutlineLevel("Sheet1", 2, 8), "invalid outline level")
+       assert.EqualError(t, f.SetColOutlineLevel("Sheet1", "D", 8), ErrOutlineLevel.Error())
+       assert.EqualError(t, f.SetRowOutlineLevel("Sheet1", 2, 8), ErrOutlineLevel.Error())
        // Test set row outline level on not exists worksheet.
        assert.EqualError(t, f.SetRowOutlineLevel("SheetN", 1, 4), "sheet SheetN is not exist")
        // Test get row outline level on not exists worksheet.
diff --git a/date.go b/date.go
index 3e50e3d..9ef5caf 100644 (file)
--- a/date.go
+++ b/date.go
@@ -12,7 +12,6 @@
 package excelize
 
 import (
-       "errors"
        "math"
        "time"
 )
@@ -35,7 +34,7 @@ func timeToExcelTime(t time.Time) (float64, error) {
        // Because for example 1900-01-01 00:00:00 +0300 MSK converts to 1900-01-01 00:00:00 +0230 LMT
        // probably due to daylight saving.
        if t.Location() != time.UTC {
-               return 0.0, errors.New("only UTC time expected")
+               return 0.0, ErrToExcelTime
        }
 
        if t.Before(excelMinTime1900) {
index 79462c5..ecc96ba 100644 (file)
@@ -55,7 +55,7 @@ func TestTimeToExcelTime_Timezone(t *testing.T) {
        for i, test := range trueExpectedDateList {
                t.Run(fmt.Sprintf("TestData%d", i+1), func(t *testing.T) {
                        _, err := timeToExcelTime(test.GoValue.In(location))
-                       assert.EqualError(t, err, "only UTC time expected")
+                       assert.EqualError(t, err, ErrToExcelTime.Error())
                })
        }
 }
index 0ab2642..a0c61c8 100644 (file)
--- a/errors.go
+++ b/errors.go
 
 package excelize
 
-import "fmt"
+import (
+       "errors"
+       "fmt"
+)
 
 func newInvalidColumnNameError(col string) error {
        return fmt.Errorf("invalid column name %q", col)
@@ -28,3 +31,44 @@ func newInvalidCellNameError(cell string) error {
 func newInvalidExcelDateError(dateValue float64) error {
        return fmt.Errorf("invalid date value %f, negative values are not supported supported", dateValue)
 }
+
+var (
+       // ErrStreamSetColWidth defined the error message on set column width in
+       // stream writing mode.
+       ErrStreamSetColWidth = errors.New("must call the SetColWidth function before the SetRow function")
+       // ErrColumnNumber defined the error message on receive an invalid column
+       // number.
+       ErrColumnNumber = errors.New("column number exceeds maximum limit")
+       // ErrColumnWidth defined the error message on receive an invalid column
+       // width.
+       ErrColumnWidth = errors.New("the width of the column must be smaller than or equal to 255 characters")
+       // ErrOutlineLevel defined the error message on receive an invalid outline
+       // level number.
+       ErrOutlineLevel = errors.New("invalid outline level")
+       // ErrCoordinates defined the error message on invalid coordinates tuples
+       // length.
+       ErrCoordinates = errors.New("coordinates length must be 4")
+       // ErrExistsWorksheet defined the error message on given worksheet already
+       // exists.
+       ErrExistsWorksheet = errors.New("the same name worksheet already exists")
+       // ErrTotalSheetHyperlinks defined the error message on hyperlinks count
+       // overflow.
+       ErrTotalSheetHyperlinks = errors.New("over maximum limit hyperlinks in a worksheet")
+       // ErrInvalidFormula defined the error message on receive an invalid
+       // formula.
+       ErrInvalidFormula = errors.New("formula not valid")
+       // ErrAddVBAProject defined the error message on add the VBA project in
+       // the workbook.
+       ErrAddVBAProject = errors.New("unsupported VBA project extension")
+       // ErrToExcelTime defined the error message on receive a not UTC time.
+       ErrToExcelTime = errors.New("only UTC time expected")
+       // ErrMaxRowHeight defined the error message on receive an invalid row
+       // height.
+       ErrMaxRowHeight = errors.New("the height of the row must be smaller than or equal to 409 points")
+       // ErrImgExt defined the error message on receive an unsupported image
+       // extension.
+       ErrImgExt = errors.New("unsupported image extension")
+       // ErrMaxFileNameLength defined the error message on receive the file name
+       // length overflow.
+       ErrMaxFileNameLength = errors.New("file name length exceeds maximum limit")
+)
index 6b3d406..940acf1 100644 (file)
@@ -16,7 +16,6 @@ import (
        "archive/zip"
        "bytes"
        "encoding/xml"
-       "errors"
        "fmt"
        "io"
        "io/ioutil"
@@ -351,7 +350,7 @@ func (f *File) AddVBAProject(bin string) error {
                return fmt.Errorf("stat %s: no such file or directory", bin)
        }
        if path.Ext(bin) != ".bin" {
-               return errors.New("unsupported VBA project extension")
+               return ErrAddVBAProject
        }
        f.setContentTypePartVBAProjectExtensions()
        wb := f.relsReader(f.getWorkbookRelsPath())
index 0dcfacb..0c42178 100644 (file)
@@ -144,7 +144,7 @@ func TestOpenFile(t *testing.T) {
 
        assert.NoError(t, f.SetCellValue("Sheet2", "G2", nil))
 
-       assert.EqualError(t, f.SetCellValue("Sheet2", "G4", time.Now()), "only UTC time expected")
+       assert.EqualError(t, f.SetCellValue("Sheet2", "G4", time.Now()), ErrToExcelTime.Error())
 
        assert.NoError(t, f.SetCellValue("Sheet2", "G4", time.Now().UTC()))
        // 02:46:40
@@ -166,7 +166,7 @@ func TestOpenFile(t *testing.T) {
                assert.NoError(t, f.SetCellStr("Sheet2", "c"+strconv.Itoa(i), strconv.Itoa(i)))
        }
        assert.NoError(t, f.SaveAs(filepath.Join("test", "TestOpenFile.xlsx")))
-       assert.EqualError(t, f.SaveAs(filepath.Join("test", strings.Repeat("c", 199), ".xlsx")), "file name length exceeds maximum limit")
+       assert.EqualError(t, f.SaveAs(filepath.Join("test", strings.Repeat("c", 199), ".xlsx")), ErrMaxFileNameLength.Error())
 }
 
 func TestSaveFile(t *testing.T) {
@@ -344,7 +344,7 @@ func TestSetCellHyperLink(t *testing.T) {
        _, err = f.workSheetReader("Sheet1")
        assert.NoError(t, err)
        f.Sheet["xl/worksheets/sheet1.xml"].Hyperlinks = &xlsxHyperlinks{Hyperlink: make([]xlsxHyperlink, 65530)}
-       assert.EqualError(t, f.SetCellHyperLink("Sheet1", "A65531", "https://github.com/360EntSecGroup-Skylar/excelize", "External"), "over maximum limit hyperlinks in a worksheet")
+       assert.EqualError(t, f.SetCellHyperLink("Sheet1", "A65531", "https://github.com/360EntSecGroup-Skylar/excelize", "External"), ErrTotalSheetHyperlinks.Error())
 
        f = NewFile()
        _, err = f.workSheetReader("Sheet1")
@@ -449,7 +449,7 @@ func TestSetSheetBackgroundErrors(t *testing.T) {
        }
 
        err = f.SetSheetBackground("Sheet2", filepath.Join("test", "Book1.xlsx"))
-       assert.EqualError(t, err, "unsupported image extension")
+       assert.EqualError(t, err, ErrImgExt.Error())
 }
 
 // TestWriteArrayFormula tests the extended options of SetCellFormula by writing an array function
@@ -1187,7 +1187,7 @@ func TestAddVBAProject(t *testing.T) {
        f := NewFile()
        assert.NoError(t, f.SetSheetPrOptions("Sheet1", CodeName("Sheet1")))
        assert.EqualError(t, f.AddVBAProject("macros.bin"), "stat macros.bin: no such file or directory")
-       assert.EqualError(t, f.AddVBAProject(filepath.Join("test", "Book1.xlsx")), "unsupported VBA project extension")
+       assert.EqualError(t, f.AddVBAProject(filepath.Join("test", "Book1.xlsx")), ErrAddVBAProject.Error())
        assert.NoError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")))
        // Test add VBA project twice.
        assert.NoError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")))
diff --git a/file.go b/file.go
index 8a37aef..36b1a42 100644 (file)
--- a/file.go
+++ b/file.go
@@ -14,7 +14,6 @@ package excelize
 import (
        "archive/zip"
        "bytes"
-       "errors"
        "fmt"
        "io"
        "os"
@@ -66,7 +65,7 @@ func (f *File) Save() error {
 // provided path.
 func (f *File) SaveAs(name string, opt ...Options) error {
        if len(name) > MaxFileNameLength {
-               return errors.New("file name length exceeds maximum limit")
+               return ErrMaxFileNameLength
        }
        file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
        if err != nil {
diff --git a/lib.go b/lib.go
index 3a9e807..99083b1 100644 (file)
--- a/lib.go
+++ b/lib.go
@@ -149,7 +149,7 @@ func ColumnNameToNumber(name string) (int, error) {
                multi *= 26
        }
        if col > TotalColumns {
-               return -1, fmt.Errorf("column number exceeds maximum limit")
+               return -1, ErrColumnNumber
        }
        return col, nil
 }
@@ -166,7 +166,7 @@ func ColumnNumberToName(num int) (string, error) {
                return "", fmt.Errorf("incorrect column number %d", num)
        }
        if num > TotalColumns {
-               return "", fmt.Errorf("column number exceeds maximum limit")
+               return "", ErrColumnNumber
        }
        var col string
        for num > 0 {
index 10d7c3a..eb0a289 100644 (file)
@@ -73,7 +73,7 @@ func TestColumnNameToNumber_Error(t *testing.T) {
                }
        }
        _, err := ColumnNameToNumber("XFE")
-       assert.EqualError(t, err, "column number exceeds maximum limit")
+       assert.EqualError(t, err, ErrColumnNumber.Error())
 }
 
 func TestColumnNumberToName_OK(t *testing.T) {
@@ -98,7 +98,7 @@ func TestColumnNumberToName_Error(t *testing.T) {
        }
 
        _, err = ColumnNumberToName(TotalColumns + 1)
-       assert.EqualError(t, err, "column number exceeds maximum limit")
+       assert.EqualError(t, err, ErrColumnNumber.Error())
 }
 
 func TestSplitCellName_OK(t *testing.T) {
index de7e0f8..92e0106 100644 (file)
@@ -15,7 +15,6 @@ import (
        "bytes"
        "encoding/json"
        "encoding/xml"
-       "errors"
        "fmt"
        "image"
        "io"
@@ -93,7 +92,7 @@ func (f *File) AddPicture(sheet, cell, picture, format string) error {
        }
        ext, ok := supportImageTypes[path.Ext(picture)]
        if !ok {
-               return errors.New("unsupported image extension")
+               return ErrImgExt
        }
        file, _ := ioutil.ReadFile(picture)
        _, name := filepath.Split(picture)
@@ -134,7 +133,7 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
        var hyperlinkType string
        ext, ok := supportImageTypes[extension]
        if !ok {
-               return errors.New("unsupported image extension")
+               return ErrImgExt
        }
        formatSet, err := parseFormatPictureSet(format)
        if err != nil {
index 28d8aa8..be917b8 100644 (file)
@@ -82,10 +82,10 @@ func TestAddPictureErrors(t *testing.T) {
 
        // Test add picture to worksheet with unsupported file type.
        err = xlsx.AddPicture("Sheet1", "G21", filepath.Join("test", "Book1.xlsx"), "")
-       assert.EqualError(t, err, "unsupported image extension")
+       assert.EqualError(t, err, ErrImgExt.Error())
 
        err = xlsx.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", "jpg", make([]byte, 1))
-       assert.EqualError(t, err, "unsupported image extension")
+       assert.EqualError(t, err, ErrImgExt.Error())
 
        // Test add picture to worksheet with invalid file data.
        err = xlsx.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", ".jpg", make([]byte, 1))
diff --git a/rows.go b/rows.go
index 76a8f67..451dbe9 100644 (file)
--- a/rows.go
+++ b/rows.go
@@ -14,7 +14,6 @@ package excelize
 import (
        "bytes"
        "encoding/xml"
-       "errors"
        "fmt"
        "io"
        "log"
@@ -245,7 +244,7 @@ func (f *File) SetRowHeight(sheet string, row int, height float64) error {
                return newInvalidRowNumberError(row)
        }
        if height > MaxRowHeight {
-               return errors.New("the height of the row must be smaller than or equal to 409 points")
+               return ErrMaxRowHeight
        }
        ws, err := f.workSheetReader(sheet)
        if err != nil {
@@ -436,7 +435,7 @@ func (f *File) SetRowOutlineLevel(sheet string, row int, level uint8) error {
                return newInvalidRowNumberError(row)
        }
        if level > 7 || level < 1 {
-               return errors.New("invalid outline level")
+               return ErrOutlineLevel
        }
        ws, err := f.workSheetReader(sheet)
        if err != nil {
index 0180498..5e7fd37 100644 (file)
@@ -109,7 +109,7 @@ func TestRowHeight(t *testing.T) {
        assert.Equal(t, 111.0, height)
 
        // Test set row height overflow max row height limit.
-       assert.EqualError(t, f.SetRowHeight(sheet1, 4, MaxRowHeight+1), "the height of the row must be smaller than or equal to 409 points")
+       assert.EqualError(t, f.SetRowHeight(sheet1, 4, MaxRowHeight+1), ErrMaxRowHeight.Error())
 
        // Test get row height that rows index over exists rows.
        height, err = f.GetRowHeight(sheet1, 5)
index 7541f43..97ef57e 100644 (file)
--- a/sheet.go
+++ b/sheet.go
@@ -482,7 +482,7 @@ func (f *File) SetSheetBackground(sheet, picture string) error {
        }
        ext, ok := supportImageTypes[path.Ext(picture)]
        if !ok {
-               return errors.New("unsupported image extension")
+               return ErrImgExt
        }
        file, _ := ioutil.ReadFile(picture)
        name := f.addMedia(file, ext)
index 57bf4a2..f12b201 100644 (file)
--- a/stream.go
+++ b/stream.go
@@ -29,6 +29,8 @@ type StreamWriter struct {
        File            *File
        Sheet           string
        SheetID         int
+       sheetWritten    bool
+       cols            string
        worksheet       *xlsxWorksheet
        rawData         bufferedWriter
        mergeCellsCount int
@@ -104,8 +106,7 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
        f.streams[sheetXML] = sw
 
        _, _ = sw.rawData.WriteString(XMLHeader + `<worksheet` + templateNamespaceIDMap)
-       bulkAppendFields(&sw.rawData, sw.worksheet, 2, 6)
-       _, _ = sw.rawData.WriteString(`<sheetData>`)
+       bulkAppendFields(&sw.rawData, sw.worksheet, 2, 5)
        return sw, err
 }
 
@@ -298,7 +299,13 @@ func (sw *StreamWriter) SetRow(axis string, values []interface{}) error {
        if err != nil {
                return err
        }
-
+       if !sw.sheetWritten {
+               if len(sw.cols) > 0 {
+                       sw.rawData.WriteString("<cols>" + sw.cols + "</cols>")
+               }
+               _, _ = sw.rawData.WriteString(`<sheetData>`)
+               sw.sheetWritten = true
+       }
        fmt.Fprintf(&sw.rawData, `<row r="%d">`, row)
        for i, val := range values {
                axis, err := CoordinatesToCellName(col+i, row)
@@ -325,6 +332,33 @@ func (sw *StreamWriter) SetRow(axis string, values []interface{}) error {
        return sw.rawData.Sync()
 }
 
+// SetColWidth provides a function to set the width of a single column or
+// multiple columns for the the StreamWriter. Note that you must call
+// the 'SetColWidth' function before the 'SetRow' function. For example set
+// the width column B:C as 20:
+//
+//    err := streamWriter.SetColWidth(2, 3, 20)
+//
+func (sw *StreamWriter) SetColWidth(min, max int, width float64) error {
+       if sw.sheetWritten {
+               return ErrStreamSetColWidth
+       }
+       if min > TotalColumns || max > TotalColumns {
+               return ErrColumnNumber
+       }
+       if min < 1 || max < 1 {
+               return ErrColumnNumber
+       }
+       if width > MaxColumnWidth {
+               return ErrColumnWidth
+       }
+       if min > max {
+               min, max = max, min
+       }
+       sw.cols += fmt.Sprintf(`<col min="%d" max="%d" width="%f" customWidth="1"/>`, min, max, width)
+       return nil
+}
+
 // MergeCell provides a function to merge cells by a given coordinate area for
 // the StreamWriter. Don't create a merged cell that overlaps with another
 // existing merged cell.
index d36883a..0834a2d 100644 (file)
@@ -57,7 +57,7 @@ func TestStreamWriter(t *testing.T) {
        assert.NoError(t, err)
        assert.NoError(t, streamWriter.SetRow("A4", []interface{}{Cell{StyleID: styleID}, Cell{Formula: "SUM(A10,B10)"}}))
        assert.NoError(t, streamWriter.SetRow("A5", []interface{}{&Cell{StyleID: styleID, Value: "cell"}, &Cell{Formula: "SUM(A10,B10)"}}))
-       assert.EqualError(t, streamWriter.SetRow("A6", []interface{}{time.Now()}), "only UTC time expected")
+       assert.EqualError(t, streamWriter.SetRow("A6", []interface{}{time.Now()}), ErrToExcelTime.Error())
 
        for rowID := 10; rowID <= 51200; rowID++ {
                row := make([]interface{}, 50)
@@ -68,6 +68,9 @@ func TestStreamWriter(t *testing.T) {
                assert.NoError(t, streamWriter.SetRow(cell, row))
        }
 
+       // Test set cell column overflow.
+       assert.EqualError(t, streamWriter.SetRow("XFD1", []interface{}{"A", "B", "C"}), ErrColumnNumber.Error())
+
        assert.NoError(t, streamWriter.Flush())
        // Save spreadsheet by the given path.
        assert.NoError(t, file.SaveAs(filepath.Join("test", "TestStreamWriter.xlsx")))
@@ -112,6 +115,18 @@ func TestStreamWriter(t *testing.T) {
        assert.Equal(t, "Data", cellValue)
 }
 
+func TestStreamSetColWidth(t *testing.T) {
+       file := NewFile()
+       streamWriter, err := file.NewStreamWriter("Sheet1")
+       assert.NoError(t, err)
+       assert.NoError(t, streamWriter.SetColWidth(3, 2, 20))
+       assert.EqualError(t, streamWriter.SetColWidth(0, 3, 20), ErrColumnNumber.Error())
+       assert.EqualError(t, streamWriter.SetColWidth(TotalColumns+1, 3, 20), ErrColumnNumber.Error())
+       assert.EqualError(t, streamWriter.SetColWidth(1, 3, MaxColumnWidth+1), ErrColumnWidth.Error())
+       assert.NoError(t, streamWriter.SetRow("A1", []interface{}{"A", "B", "C"}))
+       assert.EqualError(t, streamWriter.SetColWidth(2, 3, 20), ErrStreamSetColWidth.Error())
+}
+
 func TestStreamTable(t *testing.T) {
        file := NewFile()
        streamWriter, err := file.NewStreamWriter("Sheet1")