Browse Source

Resolve #570, flat columns for the column's operation

xuri 5 years ago
parent
commit
e51aff2d95
9 changed files with 117 additions and 67 deletions
  1. 1 1
      .travis.yml
  2. 4 2
      CONTRIBUTING.md
  3. 87 38
      col.go
  4. 2 2
      col_test.go
  5. 11 14
      merge.go
  6. 2 2
      picture.go
  7. 2 2
      sheet.go
  8. 4 2
      table.go
  9. 4 4
      xmlWorksheet.go

+ 1 - 1
.travis.yml

@@ -14,7 +14,7 @@ os:
   - osx
 
 env:
-  matrix:
+  jobs:
     - GOARCH=amd64
     - GOARCH=386
 

+ 4 - 2
CONTRIBUTING.md

@@ -234,7 +234,9 @@ By making a contribution to this project, I certify that:
 
 Then you just add a line to every git commit message:
 
-    Signed-off-by: Ri Xu https://xuri.me
+```text
+Signed-off-by: Ri Xu https://xuri.me
+```
 
 Use your real name (sorry, no pseudonyms or anonymous contributions.)
 
@@ -460,4 +462,4 @@ Do not use package math/rand to generate keys, even
 throwaway ones. Unseeded, the generator is completely predictable.
 Seeded with time.Nanoseconds(), there are just a few bits of entropy.
 Instead, use crypto/rand's Reader, and if you need text, print to
-hexadecimal or base64
+hexadecimal or base64.

+ 87 - 38
col.go

@@ -13,6 +13,8 @@ import (
 	"errors"
 	"math"
 	"strings"
+
+	"github.com/mohae/deepcopy"
 )
 
 // Define the default cell size and EMU unit of measurement.
@@ -59,7 +61,7 @@ func (f *File) GetColVisible(sheet, col string) (bool, error) {
 //
 //    err := f.SetColVisible("Sheet1", "D", false)
 //
-//    Hide the columns from D to F (included)
+// Hide the columns from D to F (included):
 //
 //    err := f.SetColVisible("Sheet1", "D:F", false)
 //
@@ -87,23 +89,31 @@ func (f *File) SetColVisible(sheet, columns string, visible bool) error {
 		return err
 	}
 	colData := xlsxCol{
-		Min:		min,
-		Max:		max,
-		Width:		9, // default width
-		Hidden:		!visible,
+		Min:         min,
+		Max:         max,
+		Width:       9, // default width
+		Hidden:      !visible,
 		CustomWidth: true,
 	}
-	if xlsx.Cols != nil {
-		xlsx.Cols.Col = append(xlsx.Cols.Col, colData)
-	} else {
+	if xlsx.Cols == nil {
 		cols := xlsxCols{}
 		cols.Col = append(cols.Col, colData)
 		xlsx.Cols = &cols
-	}
+		return nil
+	}
+	xlsx.Cols.Col = flatCols(colData, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol {
+		fc.BestFit = c.BestFit
+		fc.Collapsed = c.Collapsed
+		fc.CustomWidth = c.CustomWidth
+		fc.OutlineLevel = c.OutlineLevel
+		fc.Phonetic = c.Phonetic
+		fc.Style = c.Style
+		fc.Width = c.Width
+		return fc
+	})
 	return nil
 }
 
-
 // GetColOutlineLevel provides a function to get outline level of a single
 // column by given worksheet name and column name. For example, get outline
 // level of column D in Sheet1:
@@ -162,16 +172,16 @@ func (f *File) SetColOutlineLevel(sheet, col string, level uint8) error {
 		xlsx.Cols = &cols
 		return err
 	}
-	for v := range xlsx.Cols.Col {
-		if xlsx.Cols.Col[v].Min <= colNum && colNum <= xlsx.Cols.Col[v].Max {
-			colData = xlsx.Cols.Col[v]
-		}
-	}
-	colData.Min = colNum
-	colData.Max = colNum
-	colData.OutlineLevel = level
-	colData.CustomWidth = true
-	xlsx.Cols.Col = append(xlsx.Cols.Col, colData)
+	xlsx.Cols.Col = flatCols(colData, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol {
+		fc.BestFit = c.BestFit
+		fc.Collapsed = c.Collapsed
+		fc.CustomWidth = c.CustomWidth
+		fc.Hidden = c.Hidden
+		fc.Phonetic = c.Phonetic
+		fc.Style = c.Style
+		fc.Width = c.Width
+		return fc
+	})
 	return err
 }
 
@@ -214,21 +224,21 @@ func (f *File) SetColStyle(sheet, columns string, styleID int) error {
 	if xlsx.Cols == nil {
 		xlsx.Cols = &xlsxCols{}
 	}
-	var find bool
-	for idx, col := range xlsx.Cols.Col {
-		if col.Min == min && col.Max == max {
-			xlsx.Cols.Col[idx].Style = styleID
-			find = true
-		}
-	}
-	if !find {
-		xlsx.Cols.Col = append(xlsx.Cols.Col, xlsxCol{
-			Min:   min,
-			Max:   max,
-			Width: 9,
-			Style: styleID,
-		})
-	}
+	xlsx.Cols.Col = flatCols(xlsxCol{
+		Min:   min,
+		Max:   max,
+		Width: 9,
+		Style: styleID,
+	}, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol {
+		fc.BestFit = c.BestFit
+		fc.Collapsed = c.Collapsed
+		fc.CustomWidth = c.CustomWidth
+		fc.Hidden = c.Hidden
+		fc.OutlineLevel = c.OutlineLevel
+		fc.Phonetic = c.Phonetic
+		fc.Width = c.Width
+		return fc
+	})
 	return nil
 }
 
@@ -261,16 +271,55 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) error
 		Width:       width,
 		CustomWidth: true,
 	}
-	if xlsx.Cols != nil {
-		xlsx.Cols.Col = append(xlsx.Cols.Col, col)
-	} else {
+	if xlsx.Cols == nil {
 		cols := xlsxCols{}
 		cols.Col = append(cols.Col, col)
 		xlsx.Cols = &cols
+		return err
 	}
+	xlsx.Cols.Col = flatCols(col, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol {
+		fc.BestFit = c.BestFit
+		fc.Collapsed = c.Collapsed
+		fc.Hidden = c.Hidden
+		fc.OutlineLevel = c.OutlineLevel
+		fc.Phonetic = c.Phonetic
+		fc.Style = c.Style
+		return fc
+	})
 	return err
 }
 
+// flatCols provides a method for the column's operation functions to flatten
+// and check the worksheet columns.
+func flatCols(col xlsxCol, cols []xlsxCol, replacer func(fc, c xlsxCol) xlsxCol) []xlsxCol {
+	fc := []xlsxCol{}
+	for i := col.Min; i <= col.Max; i++ {
+		c := deepcopy.Copy(col).(xlsxCol)
+		c.Min, c.Max = i, i
+		fc = append(fc, c)
+	}
+	inFlat := func(colID int, cols []xlsxCol) (int, bool) {
+		for idx, c := range cols {
+			if c.Max == colID && c.Min == colID {
+				return idx, true
+			}
+		}
+		return -1, false
+	}
+	for _, column := range cols {
+		for i := column.Min; i <= column.Max; i++ {
+			if idx, ok := inFlat(i, fc); ok {
+				fc[idx] = replacer(fc[idx], column)
+				continue
+			}
+			c := deepcopy.Copy(column).(xlsxCol)
+			c.Min, c.Max = i, i
+			fc = append(fc, c)
+		}
+	}
+	return fc
+}
+
 // positionObjectPixels calculate the vertices that define the position of a
 // graphical object within the worksheet in pixels.
 //

+ 2 - 2
col_test.go

@@ -31,7 +31,7 @@ func TestColumnVisibility(t *testing.T) {
 		assert.Equal(t, false, visible)
 		assert.NoError(t, err)
 		// ...and displaying them back SetColVisible(...true)
-		assert.NoError(t, f.SetColVisible("Sheet1", "F:V", true))
+		assert.NoError(t, f.SetColVisible("Sheet1", "V:F", true))
 		visible, err = f.GetColVisible("Sheet1", "F")
 		assert.Equal(t, true, visible)
 		assert.NoError(t, err)
@@ -53,7 +53,7 @@ func TestColumnVisibility(t *testing.T) {
 
 		f.NewSheet("Sheet3")
 		assert.NoError(t, f.SetColVisible("Sheet3", "E", false))
-
+		assert.EqualError(t, f.SetColVisible("Sheet1", "A:-1", true), "invalid column name \"-1\"")
 		assert.EqualError(t, f.SetColVisible("SheetN", "E", false), "sheet SheetN is not exist")
 		assert.NoError(t, f.SaveAs(filepath.Join("test", "TestColumnVisibility.xlsx")))
 	})

+ 11 - 14
merge.go

@@ -22,20 +22,17 @@ import (
 // If you create a merged cell that overlaps with another existing merged cell,
 // those merged cells that already exist will be removed.
 //
-//                 B1(x1,y1)              D1(x2,y1)
-//                +--------------------------------+
-//                |                                |
-//                |                                |
-//     A4(x3,y3)  |        C4(x4,y3)               |
-//    +-----------------------------+              |
-//    |           |                 |              |
-//    |           |                 |              |
-//    |           |B5(x1,y2)        |     D5(x2,y2)|
-//    |           +--------------------------------+
-//    |                             |
-//    |                             |
-//    |A8(x3,y4)           C8(x4,y4)|
-//    +-----------------------------+
+//                 B1(x1,y1)      D1(x2,y1)
+//               +------------------------+
+//               |                        |
+//     A4(x3,y3) |    C4(x4,y3)           |
+//    +------------------------+          |
+//    |          |             |          |
+//    |          |B5(x1,y2)    | D5(x2,y2)|
+//    |          +------------------------+
+//    |                        |
+//    |A8(x3,y4)      C8(x4,y4)|
+//    +------------------------+
 //
 func (f *File) MergeCell(sheet, hcell, vcell string) error {
 	rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell)

+ 2 - 2
picture.go

@@ -462,8 +462,8 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte, error) {
 	return f.getPicture(row, col, drawingXML, drawingRelationships)
 }
 
-// DeletePicture provides a function to delete chart in XLSX by given
-// worksheet and cell name. Note that the image file won't deleted from the
+// DeletePicture provides a function to delete charts in XLSX by given
+// worksheet and cell name. Note that the image file won't be deleted from the
 // document currently.
 func (f *File) DeletePicture(sheet, cell string) (err error) {
 	col, row, err := CellNameToCoordinates(cell)

+ 2 - 2
sheet.go

@@ -287,8 +287,8 @@ func (f *File) GetActiveSheetIndex() int {
 	return 0
 }
 
-// SetSheetName provides a function to set the worksheet name be given old and
-// new worksheet name. Maximum 31 characters are allowed in sheet title and
+// SetSheetName provides a function to set the worksheet name by given old and
+// new worksheet names. Maximum 31 characters are allowed in sheet title and
 // this function only changes the name of the sheet and will not update the
 // sheet name in the formula or reference associated with the cell. So there
 // may be problem formula error or reference missing.

+ 4 - 2
table.go

@@ -39,8 +39,10 @@ func parseFormatTableSet(formatSet string) (*formatTable, error) {
 //
 //    err := f.AddTable("Sheet2", "F2", "H6", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`)
 //
-// Note that the table at least two lines include string type header. Multiple
-// tables coordinate areas can't have an intersection.
+// Note that the table must be at least two lines including the header. The
+// header cells must contain strings and must be unique, and must set the
+// header row data of the table before calling the AddTable function. Multiple
+// tables coordinate areas that can't have an intersection.
 //
 // table_name: The name of the table, in the same worksheet name of the table should be unique
 //

+ 4 - 4
xmlWorksheet.go

@@ -278,15 +278,15 @@ type xlsxCols struct {
 // width and column formatting for one or more columns of the worksheet.
 type xlsxCol struct {
 	BestFit      bool    `xml:"bestFit,attr,omitempty"`
-	Collapsed    bool    `xml:"collapsed,attr"`
+	Collapsed    bool    `xml:"collapsed,attr,omitempty"`
 	CustomWidth  bool    `xml:"customWidth,attr,omitempty"`
-	Hidden       bool    `xml:"hidden,attr"`
+	Hidden       bool    `xml:"hidden,attr,omitempty"`
 	Max          int     `xml:"max,attr"`
 	Min          int     `xml:"min,attr"`
 	OutlineLevel uint8   `xml:"outlineLevel,attr,omitempty"`
 	Phonetic     bool    `xml:"phonetic,attr,omitempty"`
-	Style        int     `xml:"style,attr"`
-	Width        float64 `xml:"width,attr"`
+	Style        int     `xml:"style,attr,omitempty"`
+	Width        float64 `xml:"width,attr,omitempty"`
 }
 
 // xlsxDimension directly maps the dimension element in the namespace