Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#@+leo-ver=5-thin 

2#@+node:ekr.20150419124739.1: * @file leoPrinting.py 

3""" 

4Support the commands in Leo's File:Print menu. 

5Adapted from printing plugin. 

6""" 

7from leo.core import leoGlobals as g 

8# 

9# Qt imports. May fail from the bridge. 

10try: # #1973 

11 from leo.core.leoQt import printsupport, QtGui 

12 from leo.core.leoQt import DialogCode 

13except Exception: 

14 printsupport = QtGui = None # type:ignore 

15 DialogCode = None # type:ignore 

16#@+others 

17#@+node:ekr.20150509035503.1: ** cmd (decorator) 

18def cmd(name): 

19 """Command decorator for the PrintingController class.""" 

20 return g.new_cmd_decorator(name, ['c', 'printingController',]) 

21#@+node:ekr.20150420120520.1: ** class PrintingController 

22class PrintingController: 

23 """A class supporting the commands in Leo's File:Print menu.""" 

24 #@+others 

25 #@+node:ekr.20150419124739.6: *3* pr.__init__ & helpers 

26 def __init__(self, c): 

27 """Ctor for PrintingController class.""" 

28 self.c = c 

29 self.reload_settings() 

30 

31 def reload_settings(self): 

32 c = self.c 

33 self.font_size = c.config.getString('printing-font-size') or '12' 

34 self.font_family = c.config.getString('printing-font-family') or 'DejaVu Sans Mono' 

35 self.stylesheet = self.construct_stylesheet() 

36 

37 reloadSettings = reload_settings 

38 #@+node:ekr.20150419124739.8: *4* pr.construct stylesheet 

39 def construct_stylesheet(self): 

40 """Return the Qt stylesheet to be used for printing.""" 

41 family, size = self.font_family, self.font_size 

42 table = ( 

43 # Clearer w/o f-strings. 

44 f"h1 {{font-family: {family}}}", 

45 f"pre {{font-family: {family}; font-size: {size}px}}", 

46 ) 

47 return '\n'.join(table) 

48 #@+node:ekr.20150420072955.1: *3* pr.Doc constructors 

49 #@+node:ekr.20150419124739.11: *4* pr.complex document 

50 def complex_document(self, nodes, heads=False): 

51 """Create a complex document.""" 

52 doc = QtGui.QTextDocument() 

53 doc.setDefaultStyleSheet(self.stylesheet) 

54 contents = '' 

55 for n in nodes: 

56 if heads: 

57 contents += f"<h1>{self.sanitize_html(n.h)}</h1>\n" 

58 contents += f"<pre>{self.sanitize_html(n.b)}</pre>\n" 

59 doc.setHtml(contents) 

60 return doc 

61 #@+node:ekr.20150419124739.9: *4* pr.document 

62 def document(self, text, head=None): 

63 """Create a Qt document.""" 

64 doc = QtGui.QTextDocument() 

65 doc.setDefaultStyleSheet(self.stylesheet) 

66 text = self.sanitize_html(text) 

67 if head: 

68 head = self.sanitize_html(head) 

69 contents = f"<h1>{head}</h1>\n<pre>{text}</pre>" 

70 else: 

71 contents = f"<pre>{text}<pre>" 

72 doc.setHtml(contents) 

73 return doc 

74 #@+node:ekr.20150419124739.10: *4* pr.html_document 

75 def html_document(self, text): 

76 """Create an HTML document.""" 

77 doc = QtGui.QTextDocument() 

78 doc.setDefaultStyleSheet(self.stylesheet) 

79 doc.setHtml(text) 

80 return doc 

81 #@+node:ekr.20150420073201.1: *3* pr.Helpers 

82 #@+node:peckj.20150421084046.1: *4* pr.expand 

83 def expand(self, p): 

84 """Return the entire script at node p.""" 

85 return p.script 

86 #@+node:ekr.20150419124739.15: *4* pr.getBodies 

87 def getBodies(self, p): 

88 """Return a concatenated version of the tree at p""" 

89 return '\n'.join([p2.b for p2 in p.self_and_subtree(copy=False)]) 

90 #@+node:ekr.20150420085602.1: *4* pr.getNodes 

91 def getNodes(self, p): 

92 """Return the entire script at node p.""" 

93 result = [p.b] 

94 for p in p.subtree(): 

95 result.extend(['', f"Node: {p.h}", '']) 

96 result.append(p.b) 

97 return '\n'.join(result) 

98 #@+node:ekr.20150419124739.14: *4* pr.sanitize html 

99 def sanitize_html(self, html): 

100 """Generate html escapes.""" 

101 return html.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;') 

102 #@+node:ekr.20150420081215.1: *3* pr.Preview 

103 #@+node:ekr.20150419124739.21: *4* pr.preview_body 

104 @cmd('preview-body') 

105 def preview_body(self, event=None): 

106 """Preview the body of the selected node.""" 

107 doc = self.document(self.c.p.b) 

108 self.preview_doc(doc) 

109 #@+node:ekr.20150419124739.19: *4* pr.preview_html 

110 @cmd('preview-html') 

111 def preview_html(self, event=None): 

112 """ 

113 Preview the body of the selected text as html. The body must be valid 

114 html, including <html> and <body> elements. 

115 """ 

116 doc = self.html_document(self.c.p.b) 

117 self.preview_doc(doc) 

118 #@+node:peckj.20150421084706.1: *4* pr.preview_expanded_body 

119 @cmd('preview-expanded-body') 

120 def preview_expanded_body(self, event=None): 

121 """Preview the selected node's body, expanded""" 

122 doc = self.document(self.expand(self.c.p)) 

123 self.preview_doc(doc) 

124 #@+node:peckj.20150421084719.1: *4* pr.preview_expanded_html 

125 @cmd('preview-expanded-html') 

126 def preview_expanded_html(self, event=None): 

127 """ 

128 Preview all the expanded bodies of the selected node as html. The 

129 expanded text must be valid html, including <html> and <body> elements. 

130 """ 

131 doc = self.html_document(self.expand(self.c.p)) 

132 self.preview_doc(doc) 

133 #@+node:ekr.20150419124739.31: *4* pr.preview_marked_bodies 

134 @cmd('preview-marked-bodies') 

135 def preview_marked_bodies(self, event=None): 

136 """Preview the bodies of the marked nodes.""" 

137 nodes = [p.v for p in self.c.all_positions() if p.isMarked()] 

138 doc = self.complex_document(nodes) 

139 self.preview_doc(doc) 

140 #@+node:ekr.20150420081906.1: *4* pr.preview_marked_html 

141 @cmd('preview-marked-html') 

142 def preview_marked_html(self, event=None): 

143 """ 

144 Preview the concatenated bodies of the marked nodes. The concatenated 

145 bodies must be valid html, including <html> and <body> elements. 

146 """ 

147 nodes = [p.v for p in self.c.all_positions() if p.isMarked()] 

148 s = '\n'.join([z.b for z in nodes]) 

149 doc = self.html_document(s) 

150 self.preview_doc(doc) 

151 #@+node:ekr.20150419124739.33: *4* pr.preview_marked_nodes 

152 @cmd('preview-marked-nodes') 

153 def preview_marked_nodes(self, event=None): 

154 """Preview the marked nodes.""" 

155 nodes = [p.v for p in self.c.all_positions() if p.isMarked()] 

156 doc = self.complex_document(nodes, heads=True) 

157 self.preview_doc(doc) 

158 #@+node:ekr.20150419124739.23: *4* pr.preview_node 

159 @cmd('preview-node') 

160 def preview_node(self, event=None): 

161 """Preview the selected node.""" 

162 p = self.c.p 

163 doc = self.document(p.b, head=p.h) 

164 self.preview_doc(doc) 

165 #@+node:ekr.20150419124739.26: *4* pr.preview_tree_bodies 

166 @cmd('preview-tree-bodies') 

167 def preview_tree_bodies(self, event=None): 

168 """Preview the bodies in the selected tree.""" 

169 doc = self.document(self.getBodies(self.c.p)) 

170 self.preview_doc(doc) 

171 #@+node:ekr.20150419124739.28: *4* pr.preview_tree_nodes 

172 @cmd('preview-tree-nodes') 

173 def preview_tree_nodes(self, event=None): 

174 """Preview the entire tree.""" 

175 p = self.c.p 

176 doc = self.document(self.getNodes(p), head=p.h) 

177 self.preview_doc(doc) 

178 #@+node:ekr.20150420081923.1: *4* pr_preview_tree_html 

179 @cmd('preview-tree-html') 

180 def preview_tree_html(self, event=None): 

181 """ 

182 Preview all the bodies of the selected node as html. The concatenated 

183 bodies must valid html, including <html> and <body> elements. 

184 """ 

185 doc = self.html_document(self.getBodies(self.c.p)) 

186 self.preview_doc(doc) 

187 #@+node:ekr.20150420073128.1: *3* pr.Print 

188 #@+node:ekr.20150419124739.20: *4* pr.print_body 

189 @cmd('print-body') 

190 def print_body(self, event=None): 

191 """Print the selected node's body""" 

192 doc = self.document(self.c.p.b) 

193 self.print_doc(doc) 

194 #@+node:ekr.20150419124739.18: *4* pr.print_html 

195 @cmd('print-html') 

196 def print_html(self, event=None): 

197 """ 

198 Print the body of the selected text as html. The body must be valid 

199 html, including <html> and <body> elements. 

200 """ 

201 doc = self.html_document(self.c.p.b) 

202 self.print_doc(doc) 

203 #@+node:peckj.20150421084548.1: *4* pr.print_expanded_body 

204 @cmd('print-expanded-body') 

205 def print_expanded_body(self, event=None): 

206 """Print the selected node's body, expanded""" 

207 doc = self.document(self.expand(self.c.p)) 

208 self.print_doc(doc) 

209 #@+node:peckj.20150421084636.1: *4* pr.print_expanded_html 

210 @cmd('print-expanded-html') 

211 def print_expanded_html(self, event=None): 

212 """ 

213 Preview all the expanded bodies of the selected node as html. The 

214 expanded text must be valid html, including <html> and <body> elements. 

215 """ 

216 doc = self.html_document(self.expand(self.c.p)) 

217 self.print_doc(doc) 

218 #@+node:ekr.20150419124739.30: *4* pr.print_marked_bodies 

219 @cmd('print-marked-bodies') 

220 def print_marked_bodies(self, event=None): 

221 """Print the body text of marked nodes.""" 

222 nodes = [p.v for p in self.c.all_positions() if p.isMarked()] 

223 doc = self.complex_document(nodes) 

224 self.print_doc(doc) 

225 #@+node:ekr.20150420085054.1: *4* pr.print_marked_html 

226 @cmd('print-marked-html') 

227 def print_marked_html(self, event=None): 

228 """ 

229 Print the concatenated bodies of the marked nodes. The concatenated 

230 bodies must be valid html, including <html> and <body> elements. 

231 """ 

232 nodes = [p.v for p in self.c.all_positions() if p.isMarked()] 

233 s = '\n'.join([z.b for z in nodes]) 

234 doc = self.html_document(s) 

235 self.print_doc(doc) 

236 #@+node:ekr.20150419124739.32: *4* pr.print_marked_nodes 

237 @cmd('print-marked-nodes') 

238 def print_marked_nodes(self, event=None): 

239 """Print all the marked nodes""" 

240 nodes = [p.v for p in self.c.all_positions() if p.isMarked()] 

241 doc = self.complex_document(nodes, heads=True) 

242 self.print_doc(doc) 

243 #@+node:ekr.20150419124739.22: *4* pr.print_node 

244 @cmd('print-node') 

245 def print_node(self, event=None): 

246 """Print the selected node """ 

247 doc = self.document(self.c.p.b, head=self.c.p.h) 

248 self.print_doc(doc) 

249 #@+node:ekr.20150419124739.25: *4* pr.print_tree_bodies 

250 @cmd('print-tree-bodies') 

251 def print_tree_bodies(self, event=None): 

252 """Print all the bodies in the selected tree.""" 

253 doc = self.document(self.getBodies(self.c.p)) 

254 self.print_doc(doc) 

255 #@+node:ekr.20150420084948.1: *4* pr.print_tree_html 

256 @cmd('print-tree-html') 

257 def print_tree_html(self, event=None): 

258 """ 

259 Print all the bodies of the selected node as html. The concatenated 

260 bodies must valid html, including <html> and <body> elements. 

261 """ 

262 doc = self.html_document(self.getBodies(self.c.p)) 

263 self.print_doc(doc) 

264 #@+node:ekr.20150419124739.27: *4* pr.print_tree_nodes 

265 @cmd('print-tree-nodes') 

266 def print_tree_nodes(self, event=None): 

267 """Print all the nodes of the selected tree.""" 

268 doc = self.document(self.getNodes(self.c.p), head=self.c.p.h) 

269 self.print_doc(doc) 

270 #@+node:ekr.20150419124739.7: *3* pr.Top level 

271 #@+node:ekr.20150419124739.12: *4* pr.print_doc 

272 def print_doc(self, doc): 

273 """Print the document.""" 

274 if not printsupport: 

275 g.trace('Qt.printsupport not found.') 

276 return 

277 # pylint: disable=no-member 

278 dialog = printsupport.QPrintDialog() 

279 result = dialog.exec_() 

280 if result == DialogCode.Accepted: 

281 doc.print_(dialog.printer()) 

282 #@+node:ekr.20150419124739.13: *4* pr.preview_doc 

283 def preview_doc(self, doc): 

284 """Preview the document.""" 

285 # pylint: disable=no-member 

286 dialog = printsupport.QPrintPreviewDialog() 

287 dialog.setSizeGripEnabled(True) 

288 dialog.paintRequested.connect(doc.print) 

289 dialog.exec_() 

290 #@-others 

291#@-others 

292#@@language python 

293#@@tabwidth -4 

294#@-leo