Skip to content

Commit 9b07898

Browse files
authored
This closes #1789, delete VML shape on delete comment (#1790)
- Improve delete cell comment shape compatibility with KingSoft WPS - Update unit test
1 parent 5399572 commit 9b07898

File tree

2 files changed

+86
-68
lines changed

2 files changed

+86
-68
lines changed

vml.go

Lines changed: 82 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,14 @@ func (f *File) AddComment(sheet string, opts Comment) error {
130130
//
131131
// err := f.DeleteComment("Sheet1", "A30")
132132
func (f *File) DeleteComment(sheet, cell string) error {
133-
if err := checkSheetName(sheet); err != nil {
133+
ws, err := f.workSheetReader(sheet)
134+
if err != nil {
134135
return err
135136
}
136-
sheetXMLPath, ok := f.getSheetXMLPath(sheet)
137-
if !ok {
138-
return ErrSheetNotExist{sheet}
137+
if ws.LegacyDrawing == nil {
138+
return err
139139
}
140+
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
140141
commentsXML := f.getSheetComments(filepath.Base(sheetXMLPath))
141142
if !strings.HasPrefix(commentsXML, "/") {
142143
commentsXML = "xl" + strings.TrimPrefix(commentsXML, "..")
@@ -164,6 +165,82 @@ func (f *File) DeleteComment(sheet, cell string) error {
164165
}
165166
f.Comments[commentsXML] = cmts
166167
}
168+
sheetRelationshipsDrawingVML := f.getSheetRelationshipsTargetByID(sheet, ws.LegacyDrawing.RID)
169+
return f.deleteFormControl(sheetRelationshipsDrawingVML, cell, true)
170+
}
171+
172+
// deleteFormControl provides the method to delete shape from
173+
// xl/drawings/vmlDrawing%d.xml by giving path, cell and shape type.
174+
func (f *File) deleteFormControl(sheetRelationshipsDrawingVML, cell string, isComment bool) error {
175+
col, row, err := CellNameToCoordinates(cell)
176+
if err != nil {
177+
return err
178+
}
179+
vmlID, _ := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingVML, "../drawings/vmlDrawing"), ".vml"))
180+
drawingVML := strings.ReplaceAll(sheetRelationshipsDrawingVML, "..", "xl")
181+
vml := f.VMLDrawing[drawingVML]
182+
if vml == nil {
183+
vml = &vmlDrawing{
184+
XMLNSv: "urn:schemas-microsoft-com:vml",
185+
XMLNSo: "urn:schemas-microsoft-com:office:office",
186+
XMLNSx: "urn:schemas-microsoft-com:office:excel",
187+
XMLNSmv: "http://macVmlSchemaUri",
188+
ShapeLayout: &xlsxShapeLayout{
189+
Ext: "edit", IDmap: &xlsxIDmap{Ext: "edit", Data: vmlID},
190+
},
191+
ShapeType: &xlsxShapeType{
192+
Stroke: &xlsxStroke{JoinStyle: "miter"},
193+
VPath: &vPath{GradientShapeOK: "t", ConnectType: "rect"},
194+
},
195+
}
196+
// Load exist VML shapes from xl/drawings/vmlDrawing%d.vml
197+
d, err := f.decodeVMLDrawingReader(drawingVML)
198+
if err != nil {
199+
return err
200+
}
201+
if d != nil {
202+
vml.ShapeType.ID = d.ShapeType.ID
203+
vml.ShapeType.CoordSize = d.ShapeType.CoordSize
204+
vml.ShapeType.Spt = d.ShapeType.Spt
205+
vml.ShapeType.Path = d.ShapeType.Path
206+
for _, v := range d.Shape {
207+
s := xlsxShape{
208+
ID: v.ID,
209+
Type: v.Type,
210+
Style: v.Style,
211+
Button: v.Button,
212+
Filled: v.Filled,
213+
FillColor: v.FillColor,
214+
InsetMode: v.InsetMode,
215+
Stroked: v.Stroked,
216+
StrokeColor: v.StrokeColor,
217+
Val: v.Val,
218+
}
219+
vml.Shape = append(vml.Shape, s)
220+
}
221+
}
222+
}
223+
cond := func(objectType string) bool {
224+
if isComment {
225+
return objectType == "Note"
226+
}
227+
return objectType != "Note"
228+
}
229+
for i, sp := range vml.Shape {
230+
var shapeVal decodeShapeVal
231+
if err = xml.Unmarshal([]byte(fmt.Sprintf("<shape>%s</shape>", sp.Val)), &shapeVal); err == nil &&
232+
cond(shapeVal.ClientData.ObjectType) && shapeVal.ClientData.Anchor != "" {
233+
leftCol, topRow, err := extractAnchorCell(shapeVal.ClientData.Anchor)
234+
if err != nil {
235+
return err
236+
}
237+
if leftCol == col-1 && topRow == row-1 {
238+
vml.Shape = append(vml.Shape[:i], vml.Shape[i+1:]...)
239+
break
240+
}
241+
}
242+
}
243+
f.VMLDrawing[drawingVML] = vml
167244
return err
168245
}
169246

@@ -375,74 +452,11 @@ func (f *File) DeleteFormControl(sheet, cell string) error {
375452
if err != nil {
376453
return err
377454
}
378-
col, row, err := CellNameToCoordinates(cell)
379-
if err != nil {
380-
return err
381-
}
382455
if ws.LegacyDrawing == nil {
383456
return err
384457
}
385458
sheetRelationshipsDrawingVML := f.getSheetRelationshipsTargetByID(sheet, ws.LegacyDrawing.RID)
386-
vmlID, _ := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingVML, "../drawings/vmlDrawing"), ".vml"))
387-
drawingVML := strings.ReplaceAll(sheetRelationshipsDrawingVML, "..", "xl")
388-
vml := f.VMLDrawing[drawingVML]
389-
if vml == nil {
390-
vml = &vmlDrawing{
391-
XMLNSv: "urn:schemas-microsoft-com:vml",
392-
XMLNSo: "urn:schemas-microsoft-com:office:office",
393-
XMLNSx: "urn:schemas-microsoft-com:office:excel",
394-
XMLNSmv: "http://macVmlSchemaUri",
395-
ShapeLayout: &xlsxShapeLayout{
396-
Ext: "edit", IDmap: &xlsxIDmap{Ext: "edit", Data: vmlID},
397-
},
398-
ShapeType: &xlsxShapeType{
399-
Stroke: &xlsxStroke{JoinStyle: "miter"},
400-
VPath: &vPath{GradientShapeOK: "t", ConnectType: "rect"},
401-
},
402-
}
403-
// Load exist VML shapes from xl/drawings/vmlDrawing%d.vml
404-
d, err := f.decodeVMLDrawingReader(drawingVML)
405-
if err != nil {
406-
return err
407-
}
408-
if d != nil {
409-
vml.ShapeType.ID = d.ShapeType.ID
410-
vml.ShapeType.CoordSize = d.ShapeType.CoordSize
411-
vml.ShapeType.Spt = d.ShapeType.Spt
412-
vml.ShapeType.Path = d.ShapeType.Path
413-
for _, v := range d.Shape {
414-
s := xlsxShape{
415-
ID: v.ID,
416-
Type: v.Type,
417-
Style: v.Style,
418-
Button: v.Button,
419-
Filled: v.Filled,
420-
FillColor: v.FillColor,
421-
InsetMode: v.InsetMode,
422-
Stroked: v.Stroked,
423-
StrokeColor: v.StrokeColor,
424-
Val: v.Val,
425-
}
426-
vml.Shape = append(vml.Shape, s)
427-
}
428-
}
429-
}
430-
for i, sp := range vml.Shape {
431-
var shapeVal decodeShapeVal
432-
if err = xml.Unmarshal([]byte(fmt.Sprintf("<shape>%s</shape>", sp.Val)), &shapeVal); err == nil &&
433-
shapeVal.ClientData.ObjectType != "Note" && shapeVal.ClientData.Anchor != "" {
434-
leftCol, topRow, err := extractAnchorCell(shapeVal.ClientData.Anchor)
435-
if err != nil {
436-
return err
437-
}
438-
if leftCol == col-1 && topRow == row-1 {
439-
vml.Shape = append(vml.Shape[:i], vml.Shape[i+1:]...)
440-
break
441-
}
442-
}
443-
}
444-
f.VMLDrawing[drawingVML] = vml
445-
return err
459+
return f.deleteFormControl(sheetRelationshipsDrawingVML, cell, false)
446460
}
447461

448462
// countVMLDrawing provides a function to get VML drawing files count storage

vml_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ func TestDeleteComment(t *testing.T) {
122122
f.Comments["xl/comments2.xml"] = nil
123123
f.Pkg.Store("xl/comments2.xml", MacintoshCyrillicCharset)
124124
assert.EqualError(t, f.DeleteComment("Sheet2", "A41"), "XML syntax error on line 1: invalid UTF-8")
125+
126+
f = NewFile()
127+
// Test delete comment on a no comments worksheet
128+
assert.NoError(t, f.DeleteComment("Sheet1", "A1"))
125129
}
126130

127131
func TestDecodeVMLDrawingReader(t *testing.T) {

0 commit comments

Comments
 (0)