Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/xlsxwriter/vml.py: 15%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

303 statements  

1############################################################################### 

2# 

3# Vml - A class for writing the Excel XLSX Vml file. 

4# 

5# SPDX-License-Identifier: BSD-2-Clause 

6# Copyright 2013-2024, John McNamara, jmcnamara@cpan.org 

7# 

8 

9# Package imports. 

10from . import xmlwriter 

11 

12 

13class Vml(xmlwriter.XMLwriter): 

14 """ 

15 A class for writing the Excel XLSX Vml file. 

16 

17 

18 """ 

19 

20 ########################################################################### 

21 # 

22 # Public API. 

23 # 

24 ########################################################################### 

25 

26 def __init__(self): 

27 """ 

28 Constructor. 

29 

30 """ 

31 

32 super(Vml, self).__init__() 

33 

34 ########################################################################### 

35 # 

36 # Private API. 

37 # 

38 ########################################################################### 

39 def _assemble_xml_file( 

40 self, 

41 data_id, 

42 vml_shape_id, 

43 comments_data=None, 

44 buttons_data=None, 

45 header_images_data=None, 

46 ): 

47 # Assemble and write the XML file. 

48 z_index = 1 

49 

50 self._write_xml_namespace() 

51 

52 # Write the o:shapelayout element. 

53 self._write_shapelayout(data_id) 

54 

55 if buttons_data: 

56 # Write the v:shapetype element. 

57 self._write_button_shapetype() 

58 

59 for button in buttons_data: 

60 # Write the v:shape element. 

61 vml_shape_id += 1 

62 self._write_button_shape(vml_shape_id, z_index, button) 

63 z_index += 1 

64 

65 if comments_data: 

66 # Write the v:shapetype element. 

67 self._write_comment_shapetype() 

68 

69 for comment in comments_data: 

70 # Write the v:shape element. 

71 vml_shape_id += 1 

72 self._write_comment_shape(vml_shape_id, z_index, comment) 

73 z_index += 1 

74 

75 if header_images_data: 

76 # Write the v:shapetype element. 

77 self._write_image_shapetype() 

78 

79 index = 1 

80 for image in header_images_data: 

81 # Write the v:shape element. 

82 vml_shape_id += 1 

83 self._write_image_shape(vml_shape_id, index, image) 

84 index += 1 

85 

86 self._xml_end_tag("xml") 

87 

88 # Close the XML writer filehandle. 

89 self._xml_close() 

90 

91 def _pixels_to_points(self, vertices): 

92 # Convert comment vertices from pixels to points. 

93 

94 left, top, width, height = vertices[8:12] 

95 

96 # Scale to pixels. 

97 left *= 0.75 

98 top *= 0.75 

99 width *= 0.75 

100 height *= 0.75 

101 

102 return left, top, width, height 

103 

104 ########################################################################### 

105 # 

106 # XML methods. 

107 # 

108 ########################################################################### 

109 def _write_xml_namespace(self): 

110 # Write the <xml> element. This is the root element of VML. 

111 schema = "urn:schemas-microsoft-com:" 

112 xmlns = schema + "vml" 

113 xmlns_o = schema + "office:office" 

114 xmlns_x = schema + "office:excel" 

115 

116 attributes = [ 

117 ("xmlns:v", xmlns), 

118 ("xmlns:o", xmlns_o), 

119 ("xmlns:x", xmlns_x), 

120 ] 

121 

122 self._xml_start_tag("xml", attributes) 

123 

124 def _write_shapelayout(self, data_id): 

125 # Write the <o:shapelayout> element. 

126 attributes = [("v:ext", "edit")] 

127 

128 self._xml_start_tag("o:shapelayout", attributes) 

129 

130 # Write the o:idmap element. 

131 self._write_idmap(data_id) 

132 

133 self._xml_end_tag("o:shapelayout") 

134 

135 def _write_idmap(self, data_id): 

136 # Write the <o:idmap> element. 

137 attributes = [ 

138 ("v:ext", "edit"), 

139 ("data", data_id), 

140 ] 

141 

142 self._xml_empty_tag("o:idmap", attributes) 

143 

144 def _write_comment_shapetype(self): 

145 # Write the <v:shapetype> element. 

146 shape_id = "_x0000_t202" 

147 coordsize = "21600,21600" 

148 spt = 202 

149 path = "m,l,21600r21600,l21600,xe" 

150 

151 attributes = [ 

152 ("id", shape_id), 

153 ("coordsize", coordsize), 

154 ("o:spt", spt), 

155 ("path", path), 

156 ] 

157 

158 self._xml_start_tag("v:shapetype", attributes) 

159 

160 # Write the v:stroke element. 

161 self._write_stroke() 

162 

163 # Write the v:path element. 

164 self._write_comment_path("t", "rect") 

165 

166 self._xml_end_tag("v:shapetype") 

167 

168 def _write_button_shapetype(self): 

169 # Write the <v:shapetype> element. 

170 shape_id = "_x0000_t201" 

171 coordsize = "21600,21600" 

172 spt = 201 

173 path = "m,l,21600r21600,l21600,xe" 

174 

175 attributes = [ 

176 ("id", shape_id), 

177 ("coordsize", coordsize), 

178 ("o:spt", spt), 

179 ("path", path), 

180 ] 

181 

182 self._xml_start_tag("v:shapetype", attributes) 

183 

184 # Write the v:stroke element. 

185 self._write_stroke() 

186 

187 # Write the v:path element. 

188 self._write_button_path() 

189 

190 # Write the o:lock element. 

191 self._write_shapetype_lock() 

192 

193 self._xml_end_tag("v:shapetype") 

194 

195 def _write_image_shapetype(self): 

196 # Write the <v:shapetype> element. 

197 shape_id = "_x0000_t75" 

198 coordsize = "21600,21600" 

199 spt = 75 

200 o_preferrelative = "t" 

201 path = "m@4@5l@4@11@9@11@9@5xe" 

202 filled = "f" 

203 stroked = "f" 

204 

205 attributes = [ 

206 ("id", shape_id), 

207 ("coordsize", coordsize), 

208 ("o:spt", spt), 

209 ("o:preferrelative", o_preferrelative), 

210 ("path", path), 

211 ("filled", filled), 

212 ("stroked", stroked), 

213 ] 

214 

215 self._xml_start_tag("v:shapetype", attributes) 

216 

217 # Write the v:stroke element. 

218 self._write_stroke() 

219 

220 # Write the v:formulas element. 

221 self._write_formulas() 

222 

223 # Write the v:path element. 

224 self._write_image_path() 

225 

226 # Write the o:lock element. 

227 self._write_aspect_ratio_lock() 

228 

229 self._xml_end_tag("v:shapetype") 

230 

231 def _write_stroke(self): 

232 # Write the <v:stroke> element. 

233 joinstyle = "miter" 

234 

235 attributes = [("joinstyle", joinstyle)] 

236 

237 self._xml_empty_tag("v:stroke", attributes) 

238 

239 def _write_comment_path(self, gradientshapeok, connecttype): 

240 # Write the <v:path> element. 

241 attributes = [] 

242 

243 if gradientshapeok: 

244 attributes.append(("gradientshapeok", "t")) 

245 

246 attributes.append(("o:connecttype", connecttype)) 

247 

248 self._xml_empty_tag("v:path", attributes) 

249 

250 def _write_button_path(self): 

251 # Write the <v:path> element. 

252 shadowok = "f" 

253 extrusionok = "f" 

254 strokeok = "f" 

255 fillok = "f" 

256 connecttype = "rect" 

257 

258 attributes = [ 

259 ("shadowok", shadowok), 

260 ("o:extrusionok", extrusionok), 

261 ("strokeok", strokeok), 

262 ("fillok", fillok), 

263 ("o:connecttype", connecttype), 

264 ] 

265 

266 self._xml_empty_tag("v:path", attributes) 

267 

268 def _write_image_path(self): 

269 # Write the <v:path> element. 

270 extrusionok = "f" 

271 gradientshapeok = "t" 

272 connecttype = "rect" 

273 

274 attributes = [ 

275 ("o:extrusionok", extrusionok), 

276 ("gradientshapeok", gradientshapeok), 

277 ("o:connecttype", connecttype), 

278 ] 

279 

280 self._xml_empty_tag("v:path", attributes) 

281 

282 def _write_shapetype_lock(self): 

283 # Write the <o:lock> element. 

284 ext = "edit" 

285 shapetype = "t" 

286 

287 attributes = [ 

288 ("v:ext", ext), 

289 ("shapetype", shapetype), 

290 ] 

291 

292 self._xml_empty_tag("o:lock", attributes) 

293 

294 def _write_rotation_lock(self): 

295 # Write the <o:lock> element. 

296 ext = "edit" 

297 rotation = "t" 

298 

299 attributes = [ 

300 ("v:ext", ext), 

301 ("rotation", rotation), 

302 ] 

303 

304 self._xml_empty_tag("o:lock", attributes) 

305 

306 def _write_aspect_ratio_lock(self): 

307 # Write the <o:lock> element. 

308 ext = "edit" 

309 aspectratio = "t" 

310 

311 attributes = [ 

312 ("v:ext", ext), 

313 ("aspectratio", aspectratio), 

314 ] 

315 

316 self._xml_empty_tag("o:lock", attributes) 

317 

318 def _write_comment_shape(self, shape_id, z_index, comment): 

319 # Write the <v:shape> element. 

320 shape_type = "#_x0000_t202" 

321 insetmode = "auto" 

322 visibility = "hidden" 

323 

324 # Set the shape index. 

325 shape_id = "_x0000_s" + str(shape_id) 

326 

327 # Get the comment parameters 

328 row = comment[0] 

329 col = comment[1] 

330 visible = comment[4] 

331 fillcolor = comment[5] 

332 vertices = comment[9] 

333 

334 (left, top, width, height) = self._pixels_to_points(vertices) 

335 

336 # Set the visibility. 

337 if visible: 

338 visibility = "visible" 

339 

340 style = ( 

341 "position:absolute;" 

342 "margin-left:%.15gpt;" 

343 "margin-top:%.15gpt;" 

344 "width:%.15gpt;" 

345 "height:%.15gpt;" 

346 "z-index:%d;" 

347 "visibility:%s" % (left, top, width, height, z_index, visibility) 

348 ) 

349 

350 attributes = [ 

351 ("id", shape_id), 

352 ("type", shape_type), 

353 ("style", style), 

354 ("fillcolor", fillcolor), 

355 ("o:insetmode", insetmode), 

356 ] 

357 

358 self._xml_start_tag("v:shape", attributes) 

359 

360 # Write the v:fill element. 

361 self._write_comment_fill() 

362 

363 # Write the v:shadow element. 

364 self._write_shadow() 

365 

366 # Write the v:path element. 

367 self._write_comment_path(None, "none") 

368 

369 # Write the v:textbox element. 

370 self._write_comment_textbox() 

371 

372 # Write the x:ClientData element. 

373 self._write_comment_client_data(row, col, visible, vertices) 

374 

375 self._xml_end_tag("v:shape") 

376 

377 def _write_button_shape(self, shape_id, z_index, button): 

378 # Write the <v:shape> element. 

379 shape_type = "#_x0000_t201" 

380 

381 # Set the shape index. 

382 shape_id = "_x0000_s" + str(shape_id) 

383 

384 # Get the button parameters. 

385 # row = button["_row"] 

386 # col = button["_col"] 

387 vertices = button["vertices"] 

388 

389 (left, top, width, height) = self._pixels_to_points(vertices) 

390 

391 style = ( 

392 "position:absolute;" 

393 "margin-left:%.15gpt;" 

394 "margin-top:%.15gpt;" 

395 "width:%.15gpt;" 

396 "height:%.15gpt;" 

397 "z-index:%d;" 

398 "mso-wrap-style:tight" % (left, top, width, height, z_index) 

399 ) 

400 

401 attributes = [ 

402 ("id", shape_id), 

403 ("type", shape_type), 

404 ] 

405 

406 if button.get("description"): 

407 attributes.append(("alt", button["description"])) 

408 

409 attributes.append(("style", style)) 

410 attributes.append(("o:button", "t")) 

411 attributes.append(("fillcolor", "buttonFace [67]")) 

412 attributes.append(("strokecolor", "windowText [64]")) 

413 attributes.append(("o:insetmode", "auto")) 

414 

415 self._xml_start_tag("v:shape", attributes) 

416 

417 # Write the v:fill element. 

418 self._write_button_fill() 

419 

420 # Write the o:lock element. 

421 self._write_rotation_lock() 

422 

423 # Write the v:textbox element. 

424 self._write_button_textbox(button["font"]) 

425 

426 # Write the x:ClientData element. 

427 self._write_button_client_data(button) 

428 

429 self._xml_end_tag("v:shape") 

430 

431 def _write_image_shape(self, shape_id, z_index, image_data): 

432 # Write the <v:shape> element. 

433 shape_type = "#_x0000_t75" 

434 

435 # Set the shape index. 

436 shape_id = "_x0000_s" + str(shape_id) 

437 

438 # Get the image parameters 

439 width = image_data[0] 

440 height = image_data[1] 

441 name = image_data[2] 

442 position = image_data[3] 

443 x_dpi = image_data[4] 

444 y_dpi = image_data[5] 

445 ref_id = image_data[6] 

446 

447 # Scale the height/width by the resolution, relative to 72dpi. 

448 width = width * 72.0 / x_dpi 

449 height = height * 72.0 / y_dpi 

450 

451 # Excel uses a rounding based around 72 and 96 dpi. 

452 width = 72.0 / 96 * int(width * 96.0 / 72 + 0.25) 

453 height = 72.0 / 96 * int(height * 96.0 / 72 + 0.25) 

454 

455 style = ( 

456 "position:absolute;" 

457 "margin-left:0;" 

458 "margin-top:0;" 

459 "width:%.15gpt;" 

460 "height:%.15gpt;" 

461 "z-index:%d" % (width, height, z_index) 

462 ) 

463 

464 attributes = [ 

465 ("id", position), 

466 ("o:spid", shape_id), 

467 ("type", shape_type), 

468 ("style", style), 

469 ] 

470 

471 self._xml_start_tag("v:shape", attributes) 

472 

473 # Write the v:imagedata element. 

474 self._write_imagedata(ref_id, name) 

475 

476 # Write the o:lock element. 

477 self._write_rotation_lock() 

478 

479 self._xml_end_tag("v:shape") 

480 

481 def _write_comment_fill(self): 

482 # Write the <v:fill> element. 

483 color_2 = "#ffffe1" 

484 

485 attributes = [("color2", color_2)] 

486 

487 self._xml_empty_tag("v:fill", attributes) 

488 

489 def _write_button_fill(self): 

490 # Write the <v:fill> element. 

491 color_2 = "buttonFace [67]" 

492 detectmouseclick = "t" 

493 

494 attributes = [ 

495 ("color2", color_2), 

496 ("o:detectmouseclick", detectmouseclick), 

497 ] 

498 

499 self._xml_empty_tag("v:fill", attributes) 

500 

501 def _write_shadow(self): 

502 # Write the <v:shadow> element. 

503 on = "t" 

504 color = "black" 

505 obscured = "t" 

506 

507 attributes = [ 

508 ("on", on), 

509 ("color", color), 

510 ("obscured", obscured), 

511 ] 

512 

513 self._xml_empty_tag("v:shadow", attributes) 

514 

515 def _write_comment_textbox(self): 

516 # Write the <v:textbox> element. 

517 style = "mso-direction-alt:auto" 

518 

519 attributes = [("style", style)] 

520 

521 self._xml_start_tag("v:textbox", attributes) 

522 

523 # Write the div element. 

524 self._write_div("left") 

525 

526 self._xml_end_tag("v:textbox") 

527 

528 def _write_button_textbox(self, font): 

529 # Write the <v:textbox> element. 

530 style = "mso-direction-alt:auto" 

531 

532 attributes = [("style", style), ("o:singleclick", "f")] 

533 

534 self._xml_start_tag("v:textbox", attributes) 

535 

536 # Write the div element. 

537 self._write_div("center", font) 

538 

539 self._xml_end_tag("v:textbox") 

540 

541 def _write_div(self, align, font=None): 

542 # Write the <div> element. 

543 

544 style = "text-align:" + align 

545 

546 attributes = [("style", style)] 

547 

548 self._xml_start_tag("div", attributes) 

549 

550 if font: 

551 # Write the font element. 

552 self._write_font(font) 

553 

554 self._xml_end_tag("div") 

555 

556 def _write_font(self, font): 

557 # Write the <font> element. 

558 caption = font["caption"] 

559 face = "Calibri" 

560 size = 220 

561 color = "#000000" 

562 

563 attributes = [ 

564 ("face", face), 

565 ("size", size), 

566 ("color", color), 

567 ] 

568 

569 self._xml_data_element("font", caption, attributes) 

570 

571 def _write_comment_client_data(self, row, col, visible, vertices): 

572 # Write the <x:ClientData> element. 

573 object_type = "Note" 

574 

575 attributes = [("ObjectType", object_type)] 

576 

577 self._xml_start_tag("x:ClientData", attributes) 

578 

579 # Write the x:MoveWithCells element. 

580 self._write_move_with_cells() 

581 

582 # Write the x:SizeWithCells element. 

583 self._write_size_with_cells() 

584 

585 # Write the x:Anchor element. 

586 self._write_anchor(vertices) 

587 

588 # Write the x:AutoFill element. 

589 self._write_auto_fill() 

590 

591 # Write the x:Row element. 

592 self._write_row(row) 

593 

594 # Write the x:Column element. 

595 self._write_column(col) 

596 

597 # Write the x:Visible element. 

598 if visible: 

599 self._write_visible() 

600 

601 self._xml_end_tag("x:ClientData") 

602 

603 def _write_button_client_data(self, button): 

604 # Write the <x:ClientData> element. 

605 macro = button["macro"] 

606 vertices = button["vertices"] 

607 

608 object_type = "Button" 

609 

610 attributes = [("ObjectType", object_type)] 

611 

612 self._xml_start_tag("x:ClientData", attributes) 

613 

614 # Write the x:Anchor element. 

615 self._write_anchor(vertices) 

616 

617 # Write the x:PrintObject element. 

618 self._write_print_object() 

619 

620 # Write the x:AutoFill element. 

621 self._write_auto_fill() 

622 

623 # Write the x:FmlaMacro element. 

624 self._write_fmla_macro(macro) 

625 

626 # Write the x:TextHAlign element. 

627 self._write_text_halign() 

628 

629 # Write the x:TextVAlign element. 

630 self._write_text_valign() 

631 

632 self._xml_end_tag("x:ClientData") 

633 

634 def _write_move_with_cells(self): 

635 # Write the <x:MoveWithCells> element. 

636 self._xml_empty_tag("x:MoveWithCells") 

637 

638 def _write_size_with_cells(self): 

639 # Write the <x:SizeWithCells> element. 

640 self._xml_empty_tag("x:SizeWithCells") 

641 

642 def _write_visible(self): 

643 # Write the <x:Visible> element. 

644 self._xml_empty_tag("x:Visible") 

645 

646 def _write_anchor(self, vertices): 

647 # Write the <x:Anchor> element. 

648 (col_start, row_start, x1, y1, col_end, row_end, x2, y2) = vertices[:8] 

649 

650 strings = [col_start, x1, row_start, y1, col_end, x2, row_end, y2] 

651 strings = [str(i) for i in strings] 

652 

653 data = ", ".join(strings) 

654 

655 self._xml_data_element("x:Anchor", data) 

656 

657 def _write_auto_fill(self): 

658 # Write the <x:AutoFill> element. 

659 data = "False" 

660 

661 self._xml_data_element("x:AutoFill", data) 

662 

663 def _write_row(self, data): 

664 # Write the <x:Row> element. 

665 self._xml_data_element("x:Row", data) 

666 

667 def _write_column(self, data): 

668 # Write the <x:Column> element. 

669 self._xml_data_element("x:Column", data) 

670 

671 def _write_print_object(self): 

672 # Write the <x:PrintObject> element. 

673 self._xml_data_element("x:PrintObject", "False") 

674 

675 def _write_text_halign(self): 

676 # Write the <x:TextHAlign> element. 

677 self._xml_data_element("x:TextHAlign", "Center") 

678 

679 def _write_text_valign(self): 

680 # Write the <x:TextVAlign> element. 

681 self._xml_data_element("x:TextVAlign", "Center") 

682 

683 def _write_fmla_macro(self, data): 

684 # Write the <x:FmlaMacro> element. 

685 self._xml_data_element("x:FmlaMacro", data) 

686 

687 def _write_imagedata(self, ref_id, o_title): 

688 # Write the <v:imagedata> element. 

689 attributes = [ 

690 ("o:relid", "rId" + str(ref_id)), 

691 ("o:title", o_title), 

692 ] 

693 

694 self._xml_empty_tag("v:imagedata", attributes) 

695 

696 def _write_formulas(self): 

697 # Write the <v:formulas> element. 

698 self._xml_start_tag("v:formulas") 

699 

700 # Write the v:f elements. 

701 self._write_formula("if lineDrawn pixelLineWidth 0") 

702 self._write_formula("sum @0 1 0") 

703 self._write_formula("sum 0 0 @1") 

704 self._write_formula("prod @2 1 2") 

705 self._write_formula("prod @3 21600 pixelWidth") 

706 self._write_formula("prod @3 21600 pixelHeight") 

707 self._write_formula("sum @0 0 1") 

708 self._write_formula("prod @6 1 2") 

709 self._write_formula("prod @7 21600 pixelWidth") 

710 self._write_formula("sum @8 21600 0") 

711 self._write_formula("prod @7 21600 pixelHeight") 

712 self._write_formula("sum @10 21600 0") 

713 

714 self._xml_end_tag("v:formulas") 

715 

716 def _write_formula(self, eqn): 

717 # Write the <v:f> element. 

718 attributes = [("eqn", eqn)] 

719 

720 self._xml_empty_tag("v:f", attributes)