diff --git a/errors.go b/errors.go index ead386d601..5ac857f7ee 100644 --- a/errors.go +++ b/errors.go @@ -193,6 +193,12 @@ func (err ErrSheetNotExist) Error() string { return fmt.Sprintf("sheet %s does not exist", err.SheetName) } +// newAddCommentError defined the error message on the comment already exist in +// the cell. +func newAddCommentError(cell string) error { + return fmt.Errorf("comment already exist on cell %s", cell) +} + // newCellNameToCoordinatesError defined the error message on converts // alphanumeric cell name to coordinates. func newCellNameToCoordinatesError(cell string, err error) error { diff --git a/vml.go b/vml.go index 0c994a1403..c657793100 100644 --- a/vml.go +++ b/vml.go @@ -108,8 +108,9 @@ func (f *File) getSheetComments(sheetFile string) string { // AddComment provides the method to add comments in a sheet by giving the // worksheet name, cell reference, and format set (such as author and text). // Note that the maximum author name length is 255 and the max text length is -// 32512. For example, add a rich-text comment with a specified comments box -// size in Sheet1!A5: +// 32512, and each cell can only have one comment, an error will return if +// adding comment on a cell which already exist comment. For example, add a +// rich-text comment with a specified comments box size in Sheet1!A5: // // err := f.AddComment("Sheet1", excelize.Comment{ // Cell: "A5", @@ -169,10 +170,17 @@ func (f *File) DeleteComment(sheet, cell string) error { cmts.CommentList.Comment[:i], cmts.CommentList.Comment[i+1:]..., ) + if idx := inStrSlice(cmts.cells, cell, true); idx != -1 { + cmts.cells = append( + cmts.cells[:idx], + cmts.cells[idx+1:]..., + ) + } i-- continue } cmts.CommentList.Comment = nil + cmts.cells = nil } f.Comments[commentsXML] = cmts } @@ -272,6 +280,9 @@ func (f *File) addComment(commentsXML string, opts vmlOptions) error { if cmts == nil { cmts = &xlsxComments{Authors: xlsxAuthor{Author: []string{opts.Author}}} } + if inStrSlice(cmts.cells, opts.Comment.Cell, true) != -1 { + return newAddCommentError(opts.Comment.Cell) + } if inStrSlice(cmts.Authors.Author, opts.Author, true) == -1 { cmts.Authors.Author = append(cmts.Authors.Author, opts.Author) authorID = len(cmts.Authors.Author) - 1 @@ -320,6 +331,7 @@ func (f *File) addComment(commentsXML string, opts vmlOptions) error { cmt.Text.R = append(cmt.Text.R, r) } cmts.CommentList.Comment = append(cmts.CommentList.Comment, cmt) + cmts.cells = append(cmts.cells, cmt.Ref) f.Comments[commentsXML] = cmts return err } @@ -355,6 +367,12 @@ func (f *File) commentsReader(path string) (*xlsxComments, error) { } } } + if cmts := f.Comments[path]; cmts != nil && len(cmts.cells) == 0 { + for idx := 0; idx < len(cmts.CommentList.Comment); idx++ { + cmts.cells = append(cmts.cells, cmts.CommentList.Comment[idx].Ref) + } + f.Comments[path] = cmts + } return f.Comments[path], nil } diff --git a/vml_test.go b/vml_test.go index 226bf3a0c4..d55f2d60e1 100644 --- a/vml_test.go +++ b/vml_test.go @@ -32,6 +32,8 @@ func TestAddComment(t *testing.T) { assert.NoError(t, f.AddComment("Sheet1", Comment{Cell: "A30", Author: s, Text: s, Paragraph: []RichTextRun{{Text: s}, {Text: s}}})) assert.NoError(t, f.AddComment("Sheet2", Comment{Cell: "B7", Author: "Excelize", Text: s[:TotalCellChars-1], Paragraph: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment."}}})) + // Test add comment on a cell which already exists a comment + assert.Equal(t, f.AddComment("Sheet2", Comment{Cell: "B7", Author: s, Text: s}), newAddCommentError("B7")) // Test add comment on not exists worksheet assert.EqualError(t, f.AddComment("SheetN", Comment{Cell: "B7", Author: "Excelize", Paragraph: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment."}}}), "sheet SheetN does not exist") // Test add comment on with illegal cell reference @@ -90,15 +92,13 @@ func TestDeleteComment(t *testing.T) { assert.NoError(t, f.AddComment("Sheet2", Comment{Cell: "A40", Text: "Excelize: This is a comment1."})) assert.NoError(t, f.AddComment("Sheet2", Comment{Cell: "A41", Paragraph: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment2."}}})) assert.NoError(t, f.AddComment("Sheet2", Comment{Cell: "C41", Paragraph: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment3."}}})) - assert.NoError(t, f.AddComment("Sheet2", Comment{Cell: "C41", Paragraph: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment3-1."}}})) assert.NoError(t, f.AddComment("Sheet2", Comment{Cell: "C42", Paragraph: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment4."}}})) - assert.NoError(t, f.AddComment("Sheet2", Comment{Cell: "C41", Paragraph: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment2."}}})) assert.NoError(t, f.DeleteComment("Sheet2", "A40")) comments, err := f.GetComments("Sheet2") assert.NoError(t, err) - assert.Len(t, comments, 5) + assert.Len(t, comments, 3) comments, err = NewFile().GetComments("Sheet1") assert.NoError(t, err) diff --git a/xmlComments.go b/xmlComments.go index cb9610f6b3..7497df7c83 100644 --- a/xmlComments.go +++ b/xmlComments.go @@ -26,6 +26,7 @@ type xlsxComments struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main comments"` Authors xlsxAuthor `xml:"authors"` CommentList xlsxCommentList `xml:"commentList"` + cells []string } // xlsxAuthor directly maps the author element. This element holds a string