##// END OF EJS Templates
HTML/XML export now single menu entry...
MinRK -
Show More
@@ -161,10 +161,34 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
161 self._reading_callback = None
161 self._reading_callback = None
162 self._tab_width = 8
162 self._tab_width = 8
163 self._text_completing_pos = 0
163 self._text_completing_pos = 0
164 self._filename = os.path.join(os.curdir, 'ipython.html')
164
165
165 # Set a monospaced font.
166 # Set a monospaced font.
166 self.reset_font()
167 self.reset_font()
167
168
169 # Configure actions.
170 action = QtGui.QAction('Print', None)
171 action.setEnabled(True)
172 action.setShortcut(QtGui.QKeySequence.Print)
173 action.triggered.connect(self.print_)
174 self.addAction(action)
175 self._print_action = action
176
177 action = QtGui.QAction('Save as HTML/XML', None)
178 action.setEnabled(self.can_export())
179 action.setShortcut(QtGui.QKeySequence.Save)
180 action.triggered.connect(self.export)
181 self.addAction(action)
182 self._export_action = action
183
184 action = QtGui.QAction('Select All', None)
185 action.setEnabled(True)
186 action.setShortcut(QtGui.QKeySequence.SelectAll)
187 action.triggered.connect(self.select_all)
188 self.addAction(action)
189 self._select_all_action = action
190
191
168 def eventFilter(self, obj, event):
192 def eventFilter(self, obj, event):
169 """ Reimplemented to ensure a console-like behavior in the underlying
193 """ Reimplemented to ensure a console-like behavior in the underlying
170 text widgets.
194 text widgets.
@@ -301,6 +325,12 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
301 return not QtGui.QApplication.clipboard().text().isEmpty()
325 return not QtGui.QApplication.clipboard().text().isEmpty()
302 return False
326 return False
303
327
328 def can_export(self):
329 """Returns whether we can export. Currently only rich widgets
330 can export html.
331 """
332 return self.kind == "rich"
333
304 def clear(self, keep_input=True):
334 def clear(self, keep_input=True):
305 """ Clear the console.
335 """ Clear the console.
306
336
@@ -502,96 +532,111 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
502 def print_(self, printer = None):
532 def print_(self, printer = None):
503 """ Print the contents of the ConsoleWidget to the specified QPrinter.
533 """ Print the contents of the ConsoleWidget to the specified QPrinter.
504 """
534 """
505 if(printer is None):
535 if (not printer):
506 printer = QtGui.QPrinter()
536 printer = QtGui.QPrinter()
507 if(QtGui.QPrintDialog(printer).exec_() != QtGui.QDialog.Accepted):
537 if(QtGui.QPrintDialog(printer).exec_() != QtGui.QDialog.Accepted):
508 return
538 return
509 self._control.print_(printer)
539 self._control.print_(printer)
510
540
511 def export_html_inline(self, parent = None):
541 def export(self, parent = None):
512 """ Export the contents of the ConsoleWidget as HTML with inline PNGs.
542 """Export HTML/XML in various modes from one Dialog."""
513 """
543 parent = parent or None # sometimes parent is False
514 self.export_html(parent, inline = True)
544 dialog = QtGui.QFileDialog(parent, 'Save Console as...')
515
545 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
516 def export_html(self, parent = None, inline = False):
546 filters = [
547 'HTML with inline PNGs (*.html *.htm)',
548 'HTML with external PNGs (*.html *.htm)',
549 'XHTML with inline SVGs (*.xhtml *.xml)'
550 ]
551 dialog.setNameFilters(filters)
552 if self._filename:
553 dialog.selectFile(self._filename)
554 root,ext = os.path.splitext(self._filename)
555 if ext.lower() in ('.xml', '.xhtml'):
556 dialog.selectNameFilter(filters[-1])
557 if dialog.exec_():
558 filename = str(dialog.selectedFiles()[0])
559 self._filename = filename
560 choice = str(dialog.selectedNameFilter())
561
562 if choice.startswith('XHTML'):
563 exporter = self.export_xhtml
564 else:
565 exporter = lambda filename: self.export_html(filename, 'inline' in choice)
566
567 try:
568 return exporter(filename)
569 except Exception, e:
570 title = self.window().windowTitle()
571 msg = "Error while saving to: %s\n"%filename+str(e)
572 reply = QtGui.QMessageBox.warning(self, title, msg,
573 QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ok)
574 return None
575
576 def export_html(self, filename, inline=False):
517 """ Export the contents of the ConsoleWidget as HTML.
577 """ Export the contents of the ConsoleWidget as HTML.
518
578
519 Parameters:
579 Parameters:
520 -----------
580 -----------
581 filename : str
582 The file to be saved.
521 inline : bool, optional [default True]
583 inline : bool, optional [default True]
522
523 If True, include images as inline PNGs. Otherwise,
584 If True, include images as inline PNGs. Otherwise,
524 include them as links to external PNG files, mimicking
585 include them as links to external PNG files, mimicking
525 Firefox's "Web Page, complete" behavior.
586 web browsers' "Web Page, Complete" behavior.
526 """
587 """
527 dialog = QtGui.QFileDialog(parent, 'Save HTML Document')
588 if(inline):
528 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
589 path = None
529 dialog.setDefaultSuffix('html')
590 else:
530 dialog.setNameFilter('HTML Document (*.htm *.html *)')
591 root,ext = os.path.splitext(filename)
531 if dialog.exec_():
592 path = root+"_files"
532 filename = str(dialog.selectedFiles()[0])
593 if os.path.isfile(path):
533 if(inline):
594 raise OSError("%s exists, but is not a directory."%path)
534 path = None
595
535 else:
596 f = open(filename, 'w')
536 offset = filename.rfind(".")
597 try:
537 if(offset > 0):
598 # N.B. this is overly restrictive, but Qt's output is
538 path = filename[:offset]+"_files"
599 # predictable...
539 else:
600 img_re = re.compile(r'<img src="(?P<name>[\d]+)" />')
540 path = filename+"_files"
601 html = self.fix_html_encoding(
541 if os.path.isfile(path):
602 str(self._control.toHtml().toUtf8()))
542 raise OSError("%s exists, but is not a dir"%path)
603 f.write(img_re.sub(
543 # don't mkdir unless there are images
604 lambda x: self.image_tag(x, path = path, format = "png"),
544 # try:
605 html))
545 # os.mkdir(path)
606 except Exception, e:
546 # except OSError:
607 f.close()
547 # # TODO: check that this is an "already exists" error
608 raise e
548 # pass
609 else:
549
610 f.close()
550 f = open(filename, 'w')
611 return filename
551 try:
612
552 # N.B. this is overly restrictive, but Qt's output is
553 # predictable...
554 img_re = re.compile(r'<img src="(?P<name>[\d]+)" />')
555 html = self.fix_html_encoding(
556 str(self._control.toHtml().toUtf8()))
557 f.write(img_re.sub(
558 lambda x: self.image_tag(x, path = path, format = "png"),
559 html))
560 finally:
561 f.close()
562 return filename
563 return None
564
613
565 def export_xhtml(self, parent = None):
614 def export_xhtml(self, filename):
566 """ Export the contents of the ConsoleWidget as XHTML with inline SVGs.
615 """ Export the contents of the ConsoleWidget as XHTML with inline SVGs.
567 """
616 """
568 dialog = QtGui.QFileDialog(parent, 'Save XHTML Document')
617 f = open(filename, 'w')
569 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
618 try:
570 dialog.setDefaultSuffix('xml')
619 # N.B. this is overly restrictive, but Qt's output is
571 dialog.setNameFilter('XHTML document (*.xml *.xhtml *)')
620 # predictable...
572 if dialog.exec_():
621 img_re = re.compile(r'<img src="(?P<name>[\d]+)" />')
573 filename = str(dialog.selectedFiles()[0])
622 html = str(self._control.toHtml().toUtf8())
574 f = open(filename, 'w')
623 # Hack to make xhtml header -- note that we are not doing
575 try:
624 # any check for valid xml
576 # N.B. this is overly restrictive, but Qt's output is
625 offset = html.find("<html>")
577 # predictable...
626 assert(offset > -1)
578 img_re = re.compile(r'<img src="(?P<name>[\d]+)" />')
627 html = ('<html xmlns="http://www.w3.org/1999/xhtml">\n'+
579 html = str(self._control.toHtml().toUtf8())
628 html[offset+6:])
580 # Hack to make xhtml header -- note that we are not doing
629 # And now declare UTF-8 encoding
581 # any check for valid xml
630 html = self.fix_html_encoding(html)
582 offset = html.find("<html>")
631 f.write(img_re.sub(
583 assert(offset > -1)
632 lambda x: self.image_tag(x, path = None, format = "svg"),
584 html = ('<html xmlns="http://www.w3.org/1999/xhtml">\n'+
633 html))
585 html[offset+6:])
634 except Exception, e:
586 # And now declare UTF-8 encoding
635 f.close()
587 html = self.fix_html_encoding(html)
636 raise e
588 f.write(img_re.sub(
637 else:
589 lambda x: self.image_tag(x, path = None, format = "svg"),
638 f.close()
590 html))
639 return filename
591 finally:
592 f.close()
593 return filename
594 return None
595
640
596 def fix_html_encoding(self, html):
641 def fix_html_encoding(self, html):
597 """ Return html string, with a UTF-8 declaration added to <HEAD>.
642 """ Return html string, with a UTF-8 declaration added to <HEAD>.
@@ -857,7 +902,7 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
857 def _context_menu_make(self, pos):
902 def _context_menu_make(self, pos):
858 """ Creates a context menu for the given QPoint (in widget coordinates).
903 """ Creates a context menu for the given QPoint (in widget coordinates).
859 """
904 """
860 menu = QtGui.QMenu()
905 menu = QtGui.QMenu(self)
861
906
862 cut_action = menu.addAction('Cut', self.cut)
907 cut_action = menu.addAction('Cut', self.cut)
863 cut_action.setEnabled(self.can_cut())
908 cut_action.setEnabled(self.can_cut())
@@ -872,22 +917,12 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
872 paste_action.setShortcut(QtGui.QKeySequence.Paste)
917 paste_action.setShortcut(QtGui.QKeySequence.Paste)
873
918
874 menu.addSeparator()
919 menu.addSeparator()
875 menu.addAction('Select All', self.select_all)
920 menu.addAction(self._select_all_action)
876
921
877 if self.kind == 'rich':
922 menu.addSeparator()
878 # only the rich frontend can export html/xml
923 menu.addAction(self._export_action)
879 menu.addSeparator()
924 menu.addAction(self._print_action)
880 print_action = menu.addAction('Print', self.print_)
925
881 print_action.setEnabled(True)
882 html_action = menu.addAction('Export HTML (external PNGs)',
883 self.export_html)
884 html_action.setEnabled(True)
885 html_inline_action = menu.addAction('Export HTML (inline PNGs)',
886 self.export_html_inline)
887 html_inline_action.setEnabled(True)
888 xhtml_action = menu.addAction('Export XHTML (inline SVGs)',
889 self.export_xhtml)
890 xhtml_action.setEnabled(True)
891 return menu
926 return menu
892
927
893 def _control_key_down(self, modifiers, include_command=True):
928 def _control_key_down(self, modifiers, include_command=True):
General Comments 0
You need to be logged in to leave comments. Login now