forked from p30928647/excelize
Stream writer support to set inline rich text cell (#1121)
Co-authored-by: zhengchao.deng <zhengchao.deng@meican.com>
This commit is contained in:
parent
b1e776ee33
commit
2f5704b114
42
cell.go
42
cell.go
|
@ -885,6 +885,28 @@ func newRpr(fnt *Font) *xlsxRPr {
|
|||
return &rpr
|
||||
}
|
||||
|
||||
// setRichText provides a function to set rich text of a cell.
|
||||
func setRichText(runs []RichTextRun) ([]xlsxR, error) {
|
||||
var (
|
||||
textRuns []xlsxR
|
||||
totalCellChars int
|
||||
)
|
||||
for _, textRun := range runs {
|
||||
totalCellChars += len(textRun.Text)
|
||||
if totalCellChars > TotalCellChars {
|
||||
return textRuns, ErrCellCharsLength
|
||||
}
|
||||
run := xlsxR{T: &xlsxT{}}
|
||||
_, run.T.Val, run.T.Space = setCellStr(textRun.Text)
|
||||
fnt := textRun.Font
|
||||
if fnt != nil {
|
||||
run.RPr = newRpr(fnt)
|
||||
}
|
||||
textRuns = append(textRuns, run)
|
||||
}
|
||||
return textRuns, nil
|
||||
}
|
||||
|
||||
// SetCellRichText provides a function to set cell with rich text by given
|
||||
// worksheet. For example, set rich text on the A1 cell of the worksheet named
|
||||
// Sheet1:
|
||||
|
@ -1016,24 +1038,10 @@ func (f *File) SetCellRichText(sheet, cell string, runs []RichTextRun) error {
|
|||
return err
|
||||
}
|
||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
||||
si := xlsxSI{}
|
||||
sst := f.sharedStringsReader()
|
||||
var textRuns []xlsxR
|
||||
totalCellChars := 0
|
||||
for _, textRun := range runs {
|
||||
totalCellChars += len(textRun.Text)
|
||||
if totalCellChars > TotalCellChars {
|
||||
return ErrCellCharsLength
|
||||
}
|
||||
run := xlsxR{T: &xlsxT{}}
|
||||
_, run.T.Val, run.T.Space = setCellStr(textRun.Text)
|
||||
fnt := textRun.Font
|
||||
if fnt != nil {
|
||||
run.RPr = newRpr(fnt)
|
||||
}
|
||||
textRuns = append(textRuns, run)
|
||||
si, sst := xlsxSI{}, f.sharedStringsReader()
|
||||
if si.R, err = setRichText(runs); err != nil {
|
||||
return err
|
||||
}
|
||||
si.R = textRuns
|
||||
for idx, strItem := range sst.SI {
|
||||
if reflect.DeepEqual(strItem, si) {
|
||||
c.T, c.V = "s", strconv.Itoa(idx)
|
||||
|
|
12
excelize.go
12
excelize.go
|
@ -444,12 +444,12 @@ func (f *File) UpdateLinkedValue() error {
|
|||
// AddVBAProject provides the method to add vbaProject.bin file which contains
|
||||
// functions and/or macros. The file extension should be .xlsm. For example:
|
||||
//
|
||||
// codeName := "Sheet1"
|
||||
// if err := f.SetSheetProps("Sheet1", &excelize.SheetPropsOptions{
|
||||
// CodeName: &codeName,
|
||||
// }); err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
// codeName := "Sheet1"
|
||||
// if err := f.SetSheetProps("Sheet1", &excelize.SheetPropsOptions{
|
||||
// CodeName: &codeName,
|
||||
// }); err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
// if err := f.AddVBAProject("vbaProject.bin"); err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
|
|
21
stream.go
21
stream.go
|
@ -56,7 +56,14 @@ type StreamWriter struct {
|
|||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
// if err := streamWriter.SetRow("A1", []interface{}{excelize.Cell{StyleID: styleID, Value: "Data"}},
|
||||
// if err := streamWriter.SetRow("A1",
|
||||
// []interface{}{
|
||||
// excelize.Cell{StyleID: styleID, Value: "Data"},
|
||||
// []excelize.RichTextRun{
|
||||
// {Text: "Rich ", Font: &excelize.Font{Color: "2354e8"}},
|
||||
// {Text: "Text", Font: &excelize.Font{Color: "e83723"}},
|
||||
// },
|
||||
// },
|
||||
// excelize.RowOpts{Height: 45, Hidden: false}); err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
|
@ -433,7 +440,8 @@ func setCellFormula(c *xlsxC, formula string) {
|
|||
}
|
||||
|
||||
// setCellValFunc provides a function to set value of a cell.
|
||||
func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) (err error) {
|
||||
func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) error {
|
||||
var err error
|
||||
switch val := val.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
err = setCellIntFunc(c, val)
|
||||
|
@ -462,6 +470,9 @@ func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) (err error) {
|
|||
c.T, c.V = setCellBool(val)
|
||||
case nil:
|
||||
c.T, c.V, c.XMLSpace = setCellStr("")
|
||||
case []RichTextRun:
|
||||
c.T, c.IS = "inlineStr", &xlsxSI{}
|
||||
c.IS.R, err = setRichText(val)
|
||||
default:
|
||||
c.T, c.V, c.XMLSpace = setCellStr(fmt.Sprint(val))
|
||||
}
|
||||
|
@ -519,6 +530,12 @@ func writeCell(buf *bufferedWriter, c xlsxC) {
|
|||
_ = xml.EscapeText(buf, []byte(c.V))
|
||||
_, _ = buf.WriteString(`</v>`)
|
||||
}
|
||||
if c.IS != nil {
|
||||
is, _ := xml.Marshal(c.IS.R)
|
||||
_, _ = buf.WriteString(`<is>`)
|
||||
_, _ = buf.Write(is)
|
||||
_, _ = buf.WriteString(`</is>`)
|
||||
}
|
||||
_, _ = buf.WriteString(`</c>`)
|
||||
}
|
||||
|
||||
|
|
|
@ -52,11 +52,14 @@ func TestStreamWriter(t *testing.T) {
|
|||
row[0] = []byte("Word")
|
||||
assert.NoError(t, streamWriter.SetRow("A3", row))
|
||||
|
||||
// Test set cell with style.
|
||||
// Test set cell with style and rich text.
|
||||
styleID, err := file.NewStyle(&Style{Font: &Font{Color: "#777777"}})
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, streamWriter.SetRow("A4", []interface{}{Cell{StyleID: styleID}, Cell{Formula: "SUM(A10,B10)"}}, RowOpts{Height: 45, StyleID: styleID}))
|
||||
assert.NoError(t, streamWriter.SetRow("A5", []interface{}{&Cell{StyleID: styleID, Value: "cell"}, &Cell{Formula: "SUM(A10,B10)"}}))
|
||||
assert.NoError(t, streamWriter.SetRow("A5", []interface{}{&Cell{StyleID: styleID, Value: "cell"}, &Cell{Formula: "SUM(A10,B10)"}, []RichTextRun{
|
||||
{Text: "Rich ", Font: &Font{Color: "2354e8"}},
|
||||
{Text: "Text", Font: &Font{Color: "e83723"}},
|
||||
}}))
|
||||
assert.NoError(t, streamWriter.SetRow("A6", []interface{}{time.Now()}))
|
||||
assert.NoError(t, streamWriter.SetRow("A7", nil, RowOpts{Height: 20, Hidden: true, StyleID: styleID}))
|
||||
assert.EqualError(t, streamWriter.SetRow("A7", nil, RowOpts{Height: MaxRowHeight + 1}), ErrMaxRowHeight.Error())
|
||||
|
@ -128,7 +131,7 @@ func TestStreamWriter(t *testing.T) {
|
|||
cells += len(row)
|
||||
}
|
||||
assert.NoError(t, rows.Close())
|
||||
assert.Equal(t, 2559558, cells)
|
||||
assert.Equal(t, 2559559, cells)
|
||||
// Save spreadsheet with password.
|
||||
assert.NoError(t, file.SaveAs(filepath.Join("test", "EncryptionTestStreamWriter.xlsx"), Options{Password: "password"}))
|
||||
assert.NoError(t, file.Close())
|
||||
|
|
|
@ -46,8 +46,9 @@ type xlsxSI struct {
|
|||
// properties are defined in the rPr element, and the text displayed to the
|
||||
// user is defined in the Text (t) element.
|
||||
type xlsxR struct {
|
||||
RPr *xlsxRPr `xml:"rPr"`
|
||||
T *xlsxT `xml:"t"`
|
||||
XMLName xml.Name `xml:"r"`
|
||||
RPr *xlsxRPr `xml:"rPr"`
|
||||
T *xlsxT `xml:"t"`
|
||||
}
|
||||
|
||||
// xlsxT directly maps the t element in the run properties.
|
||||
|
|
|
@ -466,15 +466,14 @@ type xlsxC struct {
|
|||
XMLName xml.Name `xml:"c"`
|
||||
XMLSpace xml.Attr `xml:"space,attr,omitempty"`
|
||||
R string `xml:"r,attr,omitempty"` // Cell ID, e.g. A1
|
||||
S int `xml:"s,attr,omitempty"` // Style reference.
|
||||
// Str string `xml:"str,attr,omitempty"` // Style reference.
|
||||
T string `xml:"t,attr,omitempty"` // Type.
|
||||
Cm *uint `xml:"cm,attr,omitempty"` //
|
||||
Vm *uint `xml:"vm,attr,omitempty"` //
|
||||
Ph *bool `xml:"ph,attr,omitempty"` //
|
||||
F *xlsxF `xml:"f,omitempty"` // Formula
|
||||
V string `xml:"v,omitempty"` // Value
|
||||
IS *xlsxSI `xml:"is"`
|
||||
S int `xml:"s,attr,omitempty"` // Style reference
|
||||
T string `xml:"t,attr,omitempty"` // Type
|
||||
Cm *uint `xml:"cm,attr"`
|
||||
Vm *uint `xml:"vm,attr"`
|
||||
Ph *bool `xml:"ph,attr"`
|
||||
F *xlsxF `xml:"f"` // Formula
|
||||
V string `xml:"v,omitempty"` // Value
|
||||
IS *xlsxSI `xml:"is"`
|
||||
}
|
||||
|
||||
// xlsxF represents a formula for the cell. The formula expression is
|
||||
|
|
Loading…
Reference in New Issue