##// END OF EJS Templates
fix InlineBackend config message...
MinRK -
Show More
@@ -1,339 +1,341 b''
1 #-----------------------------------------------------------------------------
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2010, IPython Development Team.
2 # Copyright (c) 2010, IPython Development Team.
3 #
3 #
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5 #
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 # Standard libary imports.
9 # Standard libary imports.
10 from base64 import decodestring
10 from base64 import decodestring
11 import os
11 import os
12 import re
12 import re
13
13
14 # System libary imports.
14 # System libary imports.
15 from IPython.external.qt import QtCore, QtGui
15 from IPython.external.qt import QtCore, QtGui
16
16
17 # Local imports
17 # Local imports
18 from IPython.utils.traitlets import Bool
18 from IPython.utils.traitlets import Bool
19 from IPython.qt.svg import save_svg, svg_to_clipboard, svg_to_image
19 from IPython.qt.svg import save_svg, svg_to_clipboard, svg_to_image
20 from ipython_widget import IPythonWidget
20 from ipython_widget import IPythonWidget
21
21
22
22
23 class RichIPythonWidget(IPythonWidget):
23 class RichIPythonWidget(IPythonWidget):
24 """ An IPythonWidget that supports rich text, including lists, images, and
24 """ An IPythonWidget that supports rich text, including lists, images, and
25 tables. Note that raw performance will be reduced compared to the plain
25 tables. Note that raw performance will be reduced compared to the plain
26 text version.
26 text version.
27 """
27 """
28
28
29 # RichIPythonWidget protected class variables.
29 # RichIPythonWidget protected class variables.
30 _payload_source_plot = 'IPython.kernel.zmq.pylab.backend_payload.add_plot_payload'
30 _payload_source_plot = 'IPython.kernel.zmq.pylab.backend_payload.add_plot_payload'
31 _jpg_supported = Bool(False)
31 _jpg_supported = Bool(False)
32
32
33 # Used to determine whether a given html export attempt has already
33 # Used to determine whether a given html export attempt has already
34 # displayed a warning about being unable to convert a png to svg.
34 # displayed a warning about being unable to convert a png to svg.
35 _svg_warning_displayed = False
35 _svg_warning_displayed = False
36
36
37 #---------------------------------------------------------------------------
37 #---------------------------------------------------------------------------
38 # 'object' interface
38 # 'object' interface
39 #---------------------------------------------------------------------------
39 #---------------------------------------------------------------------------
40
40
41 def __init__(self, *args, **kw):
41 def __init__(self, *args, **kw):
42 """ Create a RichIPythonWidget.
42 """ Create a RichIPythonWidget.
43 """
43 """
44 kw['kind'] = 'rich'
44 kw['kind'] = 'rich'
45 super(RichIPythonWidget, self).__init__(*args, **kw)
45 super(RichIPythonWidget, self).__init__(*args, **kw)
46
46
47 # Configure the ConsoleWidget HTML exporter for our formats.
47 # Configure the ConsoleWidget HTML exporter for our formats.
48 self._html_exporter.image_tag = self._get_image_tag
48 self._html_exporter.image_tag = self._get_image_tag
49
49
50 # Dictionary for resolving document resource names to SVG data.
50 # Dictionary for resolving document resource names to SVG data.
51 self._name_to_svg_map = {}
51 self._name_to_svg_map = {}
52
52
53 # Do we support jpg ?
53 # Do we support jpg ?
54 # it seems that sometime jpg support is a plugin of QT, so try to assume
54 # it seems that sometime jpg support is a plugin of QT, so try to assume
55 # it is not always supported.
55 # it is not always supported.
56 _supported_format = map(str, QtGui.QImageReader.supportedImageFormats())
56 _supported_format = map(str, QtGui.QImageReader.supportedImageFormats())
57 self._jpg_supported = 'jpeg' in _supported_format
57 self._jpg_supported = 'jpeg' in _supported_format
58
58
59
59
60 #---------------------------------------------------------------------------
60 #---------------------------------------------------------------------------
61 # 'ConsoleWidget' public interface overides
61 # 'ConsoleWidget' public interface overides
62 #---------------------------------------------------------------------------
62 #---------------------------------------------------------------------------
63
63
64 def export_html(self):
64 def export_html(self):
65 """ Shows a dialog to export HTML/XML in various formats.
65 """ Shows a dialog to export HTML/XML in various formats.
66
66
67 Overridden in order to reset the _svg_warning_displayed flag prior
67 Overridden in order to reset the _svg_warning_displayed flag prior
68 to the export running.
68 to the export running.
69 """
69 """
70 self._svg_warning_displayed = False
70 self._svg_warning_displayed = False
71 super(RichIPythonWidget, self).export_html()
71 super(RichIPythonWidget, self).export_html()
72
72
73
73
74 #---------------------------------------------------------------------------
74 #---------------------------------------------------------------------------
75 # 'ConsoleWidget' protected interface
75 # 'ConsoleWidget' protected interface
76 #---------------------------------------------------------------------------
76 #---------------------------------------------------------------------------
77
77
78 def _context_menu_make(self, pos):
78 def _context_menu_make(self, pos):
79 """ Reimplemented to return a custom context menu for images.
79 """ Reimplemented to return a custom context menu for images.
80 """
80 """
81 format = self._control.cursorForPosition(pos).charFormat()
81 format = self._control.cursorForPosition(pos).charFormat()
82 name = format.stringProperty(QtGui.QTextFormat.ImageName)
82 name = format.stringProperty(QtGui.QTextFormat.ImageName)
83 if name:
83 if name:
84 menu = QtGui.QMenu()
84 menu = QtGui.QMenu()
85
85
86 menu.addAction('Copy Image', lambda: self._copy_image(name))
86 menu.addAction('Copy Image', lambda: self._copy_image(name))
87 menu.addAction('Save Image As...', lambda: self._save_image(name))
87 menu.addAction('Save Image As...', lambda: self._save_image(name))
88 menu.addSeparator()
88 menu.addSeparator()
89
89
90 svg = self._name_to_svg_map.get(name, None)
90 svg = self._name_to_svg_map.get(name, None)
91 if svg is not None:
91 if svg is not None:
92 menu.addSeparator()
92 menu.addSeparator()
93 menu.addAction('Copy SVG', lambda: svg_to_clipboard(svg))
93 menu.addAction('Copy SVG', lambda: svg_to_clipboard(svg))
94 menu.addAction('Save SVG As...',
94 menu.addAction('Save SVG As...',
95 lambda: save_svg(svg, self._control))
95 lambda: save_svg(svg, self._control))
96 else:
96 else:
97 menu = super(RichIPythonWidget, self)._context_menu_make(pos)
97 menu = super(RichIPythonWidget, self)._context_menu_make(pos)
98 return menu
98 return menu
99
99
100 #---------------------------------------------------------------------------
100 #---------------------------------------------------------------------------
101 # 'BaseFrontendMixin' abstract interface
101 # 'BaseFrontendMixin' abstract interface
102 #---------------------------------------------------------------------------
102 #---------------------------------------------------------------------------
103 def _pre_image_append(self, msg, prompt_number):
103 def _pre_image_append(self, msg, prompt_number):
104 """ Append the Out[] prompt and make the output nicer
104 """ Append the Out[] prompt and make the output nicer
105
105
106 Shared code for some the following if statement
106 Shared code for some the following if statement
107 """
107 """
108 self.log.debug("pyout: %s", msg.get('content', ''))
108 self.log.debug("pyout: %s", msg.get('content', ''))
109 self._append_plain_text(self.output_sep, True)
109 self._append_plain_text(self.output_sep, True)
110 self._append_html(self._make_out_prompt(prompt_number), True)
110 self._append_html(self._make_out_prompt(prompt_number), True)
111 self._append_plain_text('\n', True)
111 self._append_plain_text('\n', True)
112
112
113 def _handle_pyout(self, msg):
113 def _handle_pyout(self, msg):
114 """ Overridden to handle rich data types, like SVG.
114 """ Overridden to handle rich data types, like SVG.
115 """
115 """
116 if not self._hidden and self._is_from_this_session(msg):
116 if not self._hidden and self._is_from_this_session(msg):
117 content = msg['content']
117 content = msg['content']
118 prompt_number = content.get('execution_count', 0)
118 prompt_number = content.get('execution_count', 0)
119 data = content['data']
119 data = content['data']
120 metadata = msg['content']['metadata']
120 metadata = msg['content']['metadata']
121 if 'image/svg+xml' in data:
121 if 'image/svg+xml' in data:
122 self._pre_image_append(msg, prompt_number)
122 self._pre_image_append(msg, prompt_number)
123 self._append_svg(data['image/svg+xml'], True)
123 self._append_svg(data['image/svg+xml'], True)
124 self._append_html(self.output_sep2, True)
124 self._append_html(self.output_sep2, True)
125 elif 'image/png' in data:
125 elif 'image/png' in data:
126 self._pre_image_append(msg, prompt_number)
126 self._pre_image_append(msg, prompt_number)
127 png = decodestring(data['image/png'].encode('ascii'))
127 png = decodestring(data['image/png'].encode('ascii'))
128 self._append_png(png, True, metadata=metadata.get('image/png', None))
128 self._append_png(png, True, metadata=metadata.get('image/png', None))
129 self._append_html(self.output_sep2, True)
129 self._append_html(self.output_sep2, True)
130 elif 'image/jpeg' in data and self._jpg_supported:
130 elif 'image/jpeg' in data and self._jpg_supported:
131 self._pre_image_append(msg, prompt_number)
131 self._pre_image_append(msg, prompt_number)
132 jpg = decodestring(data['image/jpeg'].encode('ascii'))
132 jpg = decodestring(data['image/jpeg'].encode('ascii'))
133 self._append_jpg(jpg, True, metadata=metadata.get('image/jpeg', None))
133 self._append_jpg(jpg, True, metadata=metadata.get('image/jpeg', None))
134 self._append_html(self.output_sep2, True)
134 self._append_html(self.output_sep2, True)
135 else:
135 else:
136 # Default back to the plain text representation.
136 # Default back to the plain text representation.
137 return super(RichIPythonWidget, self)._handle_pyout(msg)
137 return super(RichIPythonWidget, self)._handle_pyout(msg)
138
138
139 def _handle_display_data(self, msg):
139 def _handle_display_data(self, msg):
140 """ Overridden to handle rich data types, like SVG.
140 """ Overridden to handle rich data types, like SVG.
141 """
141 """
142 if not self._hidden and self._is_from_this_session(msg):
142 if not self._hidden and self._is_from_this_session(msg):
143 source = msg['content']['source']
143 source = msg['content']['source']
144 data = msg['content']['data']
144 data = msg['content']['data']
145 metadata = msg['content']['metadata']
145 metadata = msg['content']['metadata']
146 # Try to use the svg or html representations.
146 # Try to use the svg or html representations.
147 # FIXME: Is this the right ordering of things to try?
147 # FIXME: Is this the right ordering of things to try?
148 if 'image/svg+xml' in data:
148 if 'image/svg+xml' in data:
149 self.log.debug("display: %s", msg.get('content', ''))
149 self.log.debug("display: %s", msg.get('content', ''))
150 svg = data['image/svg+xml']
150 svg = data['image/svg+xml']
151 self._append_svg(svg, True)
151 self._append_svg(svg, True)
152 elif 'image/png' in data:
152 elif 'image/png' in data:
153 self.log.debug("display: %s", msg.get('content', ''))
153 self.log.debug("display: %s", msg.get('content', ''))
154 # PNG data is base64 encoded as it passes over the network
154 # PNG data is base64 encoded as it passes over the network
155 # in a JSON structure so we decode it.
155 # in a JSON structure so we decode it.
156 png = decodestring(data['image/png'].encode('ascii'))
156 png = decodestring(data['image/png'].encode('ascii'))
157 self._append_png(png, True, metadata=metadata.get('image/png', None))
157 self._append_png(png, True, metadata=metadata.get('image/png', None))
158 elif 'image/jpeg' in data and self._jpg_supported:
158 elif 'image/jpeg' in data and self._jpg_supported:
159 self.log.debug("display: %s", msg.get('content', ''))
159 self.log.debug("display: %s", msg.get('content', ''))
160 jpg = decodestring(data['image/jpeg'].encode('ascii'))
160 jpg = decodestring(data['image/jpeg'].encode('ascii'))
161 self._append_jpg(jpg, True, metadata=metadata.get('image/jpeg', None))
161 self._append_jpg(jpg, True, metadata=metadata.get('image/jpeg', None))
162 else:
162 else:
163 # Default back to the plain text representation.
163 # Default back to the plain text representation.
164 return super(RichIPythonWidget, self)._handle_display_data(msg)
164 return super(RichIPythonWidget, self)._handle_display_data(msg)
165
165
166 #---------------------------------------------------------------------------
166 #---------------------------------------------------------------------------
167 # 'RichIPythonWidget' protected interface
167 # 'RichIPythonWidget' protected interface
168 #---------------------------------------------------------------------------
168 #---------------------------------------------------------------------------
169
169
170 def _append_jpg(self, jpg, before_prompt=False, metadata=None):
170 def _append_jpg(self, jpg, before_prompt=False, metadata=None):
171 """ Append raw JPG data to the widget."""
171 """ Append raw JPG data to the widget."""
172 self._append_custom(self._insert_jpg, jpg, before_prompt, metadata=metadata)
172 self._append_custom(self._insert_jpg, jpg, before_prompt, metadata=metadata)
173
173
174 def _append_png(self, png, before_prompt=False, metadata=None):
174 def _append_png(self, png, before_prompt=False, metadata=None):
175 """ Append raw PNG data to the widget.
175 """ Append raw PNG data to the widget.
176 """
176 """
177 self._append_custom(self._insert_png, png, before_prompt, metadata=metadata)
177 self._append_custom(self._insert_png, png, before_prompt, metadata=metadata)
178
178
179 def _append_svg(self, svg, before_prompt=False):
179 def _append_svg(self, svg, before_prompt=False):
180 """ Append raw SVG data to the widget.
180 """ Append raw SVG data to the widget.
181 """
181 """
182 self._append_custom(self._insert_svg, svg, before_prompt)
182 self._append_custom(self._insert_svg, svg, before_prompt)
183
183
184 def _add_image(self, image):
184 def _add_image(self, image):
185 """ Adds the specified QImage to the document and returns a
185 """ Adds the specified QImage to the document and returns a
186 QTextImageFormat that references it.
186 QTextImageFormat that references it.
187 """
187 """
188 document = self._control.document()
188 document = self._control.document()
189 name = str(image.cacheKey())
189 name = str(image.cacheKey())
190 document.addResource(QtGui.QTextDocument.ImageResource,
190 document.addResource(QtGui.QTextDocument.ImageResource,
191 QtCore.QUrl(name), image)
191 QtCore.QUrl(name), image)
192 format = QtGui.QTextImageFormat()
192 format = QtGui.QTextImageFormat()
193 format.setName(name)
193 format.setName(name)
194 return format
194 return format
195
195
196 def _copy_image(self, name):
196 def _copy_image(self, name):
197 """ Copies the ImageResource with 'name' to the clipboard.
197 """ Copies the ImageResource with 'name' to the clipboard.
198 """
198 """
199 image = self._get_image(name)
199 image = self._get_image(name)
200 QtGui.QApplication.clipboard().setImage(image)
200 QtGui.QApplication.clipboard().setImage(image)
201
201
202 def _get_image(self, name):
202 def _get_image(self, name):
203 """ Returns the QImage stored as the ImageResource with 'name'.
203 """ Returns the QImage stored as the ImageResource with 'name'.
204 """
204 """
205 document = self._control.document()
205 document = self._control.document()
206 image = document.resource(QtGui.QTextDocument.ImageResource,
206 image = document.resource(QtGui.QTextDocument.ImageResource,
207 QtCore.QUrl(name))
207 QtCore.QUrl(name))
208 return image
208 return image
209
209
210 def _get_image_tag(self, match, path = None, format = "png"):
210 def _get_image_tag(self, match, path = None, format = "png"):
211 """ Return (X)HTML mark-up for the image-tag given by match.
211 """ Return (X)HTML mark-up for the image-tag given by match.
212
212
213 Parameters
213 Parameters
214 ----------
214 ----------
215 match : re.SRE_Match
215 match : re.SRE_Match
216 A match to an HTML image tag as exported by Qt, with
216 A match to an HTML image tag as exported by Qt, with
217 match.group("Name") containing the matched image ID.
217 match.group("Name") containing the matched image ID.
218
218
219 path : string|None, optional [default None]
219 path : string|None, optional [default None]
220 If not None, specifies a path to which supporting files may be
220 If not None, specifies a path to which supporting files may be
221 written (e.g., for linked images). If None, all images are to be
221 written (e.g., for linked images). If None, all images are to be
222 included inline.
222 included inline.
223
223
224 format : "png"|"svg"|"jpg", optional [default "png"]
224 format : "png"|"svg"|"jpg", optional [default "png"]
225 Format for returned or referenced images.
225 Format for returned or referenced images.
226 """
226 """
227 if format in ("png","jpg"):
227 if format in ("png","jpg"):
228 try:
228 try:
229 image = self._get_image(match.group("name"))
229 image = self._get_image(match.group("name"))
230 except KeyError:
230 except KeyError:
231 return "<b>Couldn't find image %s</b>" % match.group("name")
231 return "<b>Couldn't find image %s</b>" % match.group("name")
232
232
233 if path is not None:
233 if path is not None:
234 if not os.path.exists(path):
234 if not os.path.exists(path):
235 os.mkdir(path)
235 os.mkdir(path)
236 relpath = os.path.basename(path)
236 relpath = os.path.basename(path)
237 if image.save("%s/qt_img%s.%s" % (path, match.group("name"), format),
237 if image.save("%s/qt_img%s.%s" % (path, match.group("name"), format),
238 "PNG"):
238 "PNG"):
239 return '<img src="%s/qt_img%s.%s">' % (relpath,
239 return '<img src="%s/qt_img%s.%s">' % (relpath,
240 match.group("name"),format)
240 match.group("name"),format)
241 else:
241 else:
242 return "<b>Couldn't save image!</b>"
242 return "<b>Couldn't save image!</b>"
243 else:
243 else:
244 ba = QtCore.QByteArray()
244 ba = QtCore.QByteArray()
245 buffer_ = QtCore.QBuffer(ba)
245 buffer_ = QtCore.QBuffer(ba)
246 buffer_.open(QtCore.QIODevice.WriteOnly)
246 buffer_.open(QtCore.QIODevice.WriteOnly)
247 image.save(buffer_, format.upper())
247 image.save(buffer_, format.upper())
248 buffer_.close()
248 buffer_.close()
249 return '<img src="data:image/%s;base64,\n%s\n" />' % (
249 return '<img src="data:image/%s;base64,\n%s\n" />' % (
250 format,re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
250 format,re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
251
251
252 elif format == "svg":
252 elif format == "svg":
253 try:
253 try:
254 svg = str(self._name_to_svg_map[match.group("name")])
254 svg = str(self._name_to_svg_map[match.group("name")])
255 except KeyError:
255 except KeyError:
256 if not self._svg_warning_displayed:
256 if not self._svg_warning_displayed:
257 QtGui.QMessageBox.warning(self, 'Error converting PNG to SVG.',
257 QtGui.QMessageBox.warning(self, 'Error converting PNG to SVG.',
258 'Cannot convert a PNG to SVG. To fix this, add this '
258 'Cannot convert PNG images to SVG, export with PNG figures instead. '
259 'If you want to export with SVG figures, add '
259 'to your ipython config:\n\n'
260 'to your ipython config:\n\n'
260 '\tc.InlineBackendConfig.figure_format = \'svg\'\n\n'
261 '\tc.InlineBackend.figure_format = \'svg\'\n\n'
261 'And regenerate the figures.',
262 'And regenerate the figures.',
262 QtGui.QMessageBox.Ok)
263 QtGui.QMessageBox.Ok)
263 self._svg_warning_displayed = True
264 self._svg_warning_displayed = True
264 return ("<b>Cannot convert a PNG to SVG.</b> "
265 return ("<b>Cannot convert PNG images to SVG.</b> "
265 "To fix this, add this to your config: "
266 "You must export this session with PNG images. "
266 "<span>c.InlineBackendConfig.figure_format = 'svg'</span> "
267 "If you want to export with SVG figures, add to your config "
268 "<span>c.InlineBackend.figure_format = 'svg'</span> "
267 "and regenerate the figures.")
269 "and regenerate the figures.")
268
270
269 # Not currently checking path, because it's tricky to find a
271 # Not currently checking path, because it's tricky to find a
270 # cross-browser way to embed external SVG images (e.g., via
272 # cross-browser way to embed external SVG images (e.g., via
271 # object or embed tags).
273 # object or embed tags).
272
274
273 # Chop stand-alone header from matplotlib SVG
275 # Chop stand-alone header from matplotlib SVG
274 offset = svg.find("<svg")
276 offset = svg.find("<svg")
275 assert(offset > -1)
277 assert(offset > -1)
276
278
277 return svg[offset:]
279 return svg[offset:]
278
280
279 else:
281 else:
280 return '<b>Unrecognized image format</b>'
282 return '<b>Unrecognized image format</b>'
281
283
282 def _insert_jpg(self, cursor, jpg, metadata=None):
284 def _insert_jpg(self, cursor, jpg, metadata=None):
283 """ Insert raw PNG data into the widget."""
285 """ Insert raw PNG data into the widget."""
284 self._insert_img(cursor, jpg, 'jpg', metadata=metadata)
286 self._insert_img(cursor, jpg, 'jpg', metadata=metadata)
285
287
286 def _insert_png(self, cursor, png, metadata=None):
288 def _insert_png(self, cursor, png, metadata=None):
287 """ Insert raw PNG data into the widget.
289 """ Insert raw PNG data into the widget.
288 """
290 """
289 self._insert_img(cursor, png, 'png', metadata=metadata)
291 self._insert_img(cursor, png, 'png', metadata=metadata)
290
292
291 def _insert_img(self, cursor, img, fmt, metadata=None):
293 def _insert_img(self, cursor, img, fmt, metadata=None):
292 """ insert a raw image, jpg or png """
294 """ insert a raw image, jpg or png """
293 if metadata:
295 if metadata:
294 width = metadata.get('width', None)
296 width = metadata.get('width', None)
295 height = metadata.get('height', None)
297 height = metadata.get('height', None)
296 else:
298 else:
297 width = height = None
299 width = height = None
298 try:
300 try:
299 image = QtGui.QImage()
301 image = QtGui.QImage()
300 image.loadFromData(img, fmt.upper())
302 image.loadFromData(img, fmt.upper())
301 if width and height:
303 if width and height:
302 image = image.scaled(width, height, transformMode=QtCore.Qt.SmoothTransformation)
304 image = image.scaled(width, height, transformMode=QtCore.Qt.SmoothTransformation)
303 elif width and not height:
305 elif width and not height:
304 image = image.scaledToWidth(width, transformMode=QtCore.Qt.SmoothTransformation)
306 image = image.scaledToWidth(width, transformMode=QtCore.Qt.SmoothTransformation)
305 elif height and not width:
307 elif height and not width:
306 image = image.scaledToHeight(height, transformMode=QtCore.Qt.SmoothTransformation)
308 image = image.scaledToHeight(height, transformMode=QtCore.Qt.SmoothTransformation)
307 except ValueError:
309 except ValueError:
308 self._insert_plain_text(cursor, 'Received invalid %s data.'%fmt)
310 self._insert_plain_text(cursor, 'Received invalid %s data.'%fmt)
309 else:
311 else:
310 format = self._add_image(image)
312 format = self._add_image(image)
311 cursor.insertBlock()
313 cursor.insertBlock()
312 cursor.insertImage(format)
314 cursor.insertImage(format)
313 cursor.insertBlock()
315 cursor.insertBlock()
314
316
315 def _insert_svg(self, cursor, svg):
317 def _insert_svg(self, cursor, svg):
316 """ Insert raw SVG data into the widet.
318 """ Insert raw SVG data into the widet.
317 """
319 """
318 try:
320 try:
319 image = svg_to_image(svg)
321 image = svg_to_image(svg)
320 except ValueError:
322 except ValueError:
321 self._insert_plain_text(cursor, 'Received invalid SVG data.')
323 self._insert_plain_text(cursor, 'Received invalid SVG data.')
322 else:
324 else:
323 format = self._add_image(image)
325 format = self._add_image(image)
324 self._name_to_svg_map[format.name()] = svg
326 self._name_to_svg_map[format.name()] = svg
325 cursor.insertBlock()
327 cursor.insertBlock()
326 cursor.insertImage(format)
328 cursor.insertImage(format)
327 cursor.insertBlock()
329 cursor.insertBlock()
328
330
329 def _save_image(self, name, format='PNG'):
331 def _save_image(self, name, format='PNG'):
330 """ Shows a save dialog for the ImageResource with 'name'.
332 """ Shows a save dialog for the ImageResource with 'name'.
331 """
333 """
332 dialog = QtGui.QFileDialog(self._control, 'Save Image')
334 dialog = QtGui.QFileDialog(self._control, 'Save Image')
333 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
335 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
334 dialog.setDefaultSuffix(format.lower())
336 dialog.setDefaultSuffix(format.lower())
335 dialog.setNameFilter('%s file (*.%s)' % (format, format.lower()))
337 dialog.setNameFilter('%s file (*.%s)' % (format, format.lower()))
336 if dialog.exec_():
338 if dialog.exec_():
337 filename = dialog.selectedFiles()[0]
339 filename = dialog.selectedFiles()[0]
338 image = self._get_image(name)
340 image = self._get_image(name)
339 image.save(filename, format)
341 image.save(filename, format)
General Comments 0
You need to be logged in to leave comments. Login now