Source code for sas.qtgui.Utilities.ReportDialog

import os
import sys
import re
import logging
import traceback
from xhtml2pdf import pisa

from PyQt5 import QtWidgets, QtCore
from PyQt5 import QtPrintSupport

import sas.qtgui.Utilities.GuiUtils as GuiUtils
import sas.qtgui.Utilities.ObjectLibrary as ObjectLibrary

from sas.qtgui.Utilities.UI.ReportDialogUI import Ui_ReportDialogUI


[docs]class ReportDialog(QtWidgets.QDialog, Ui_ReportDialogUI): """ Class for stateless grid-like printout of model parameters for mutiple models """ def __init__(self, parent=None, report_list=None): super(ReportDialog, self).__init__(parent._parent) self.setupUi(self) # disable the context help icon self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint) assert isinstance(report_list, list) assert len(report_list) == 3 self.data_html, self.data_txt, self.data_images = report_list #self.save_location = None #if 'ReportDialog_directory' in ObjectLibrary.listObjects(): self.save_location = ObjectLibrary.getObject('ReportDialog_directory') # Fill in the table from input data self.setupDialog(self.data_html) # Command buttons self.cmdPrint.clicked.connect(self.onPrint) self.cmdSave.clicked.connect(self.onSave)
[docs] def setupDialog(self, output=None): """ Display the HTML content in the browser. """ if output is not None: self.txtBrowser.setHtml(output)
[docs] def onPrint(self): """ Display the print dialog and send the report to printer """ # Define the printer printer = QtPrintSupport.QPrinter() # Display the print dialog dialog = QtPrintSupport.QPrintDialog(printer) dialog.setModal(True) dialog.setWindowTitle("Print") if dialog.exec_() != QtWidgets.QDialog.Accepted: return document = self.txtBrowser.document() try: # pylint chokes on this line with syntax-error # pylint: disable=syntax-error doesn't seem to help document.print(printer) except Exception as ex: # Printing can return various exceptions, let's catch them all logging.error("Print report failed with: " + str(ex))
[docs] def onSave(self): """ Display the Save As... prompt and save the report if instructed so """ # Choose user's home directory if self.save_location is None: location = os.path.expanduser('~') else: location = self.save_location # Use a sensible filename default default_name = os.path.join(location, 'fit_report.pdf') kwargs = { 'parent' : self, 'caption' : 'Save Report', # don't use 'directory' in order to remember the previous user choice 'directory': default_name, 'filter' : 'PDF file (*.pdf);;HTML file (*.html);;Text file (*.txt)', 'options' : QtWidgets.QFileDialog.DontUseNativeDialog} # Query user for filename. filename_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs) filename = filename_tuple[0] if not filename: return extension = filename_tuple[1] self.save_location = os.path.dirname(filename) # lifetime of this widget is short - keep the reference elsewhere ObjectLibrary.addObject('ReportDialog_directory', self.save_location) try: # extract extension from filter # e.g. "PDF file (*.pdf)" -> ".pdf" ext = extension[extension.find("(")+2:extension.find(")")] except IndexError as ex: # (ext) not found... logging.error("Error while saving report. " + str(ex)) return basename, extension = os.path.splitext(filename) if not extension: filename = '.'.join((filename, ext)) # Create files with charts pictures = [] if self.data_images is not None: pictures = self.getPictures(basename) # self.data_html contains all images at the end of the report, in base64 form; # replace them all with their saved on-disk filenames cleanr = re.compile('<img src.*$', re.DOTALL) replacement_name = "" html = self.data_html for picture in pictures: replacement_name += '<img src="'+ picture + '"><p></p>' replacement_name += '\n' # <img src="data:image/png;.*> => <img src=filename> html = re.sub(cleanr, replacement_name, self.data_html) if ext.lower() == ".txt": txt_ascii = GuiUtils.replaceHTMLwithASCII(self.data_txt) self.onTXTSave(txt_ascii, filename) if ext.lower() == ".html": self.onHTMLSave(html, filename) if ext.lower() == ".pdf": html_utf = GuiUtils.replaceHTMLwithUTF8(html) pdf_success = self.HTML2PDF(html_utf, filename) # delete images used to create the pdf for pic_name in pictures: os.remove(pic_name) #open pdf viewer if pdf_success == 0: try: if os.name == 'nt': # Windows os.startfile(filename) elif sys.platform == "darwin": # Mac os.system("open %s" % filename) except Exception as ex: # cannot open pdf. # We don't know what happened in os.* , so broad Exception is required logging.error(str(ex))
[docs] def getPictures(self, basename): """ Returns list of saved MPL figures """ # save figures pictures = [] for num, image in enumerate(self.data_images): pic_name = basename + '_img%s.png' % num # save the image for use with pdf writer image.savefig(pic_name) pictures.append(pic_name) return pictures
[docs] @staticmethod def onTXTSave(data, filename): """ Simple txt file serialization """ with open(filename, 'w') as f: f.write(data)
[docs] @staticmethod def onHTMLSave(html, filename): """ HTML file write """ with open(filename, 'w') as f: f.write(html)
[docs] @staticmethod def HTML2PDF(data, filename): """ Create a PDF file from html source string. Returns True is the file creation was successful. : data: html string : filename: name of file to be saved """ try: # open output file for writing (truncated binary) with open(filename, "w+b") as resultFile: # convert HTML to PDF pisaStatus = pisa.CreatePDF(data.encode("UTF-8"), dest=resultFile, encoding='UTF-8') return pisaStatus.err except Exception as ex: # logging.error("Error creating pdf: " + str(ex)) logging.error("Error creating pdf: " + traceback.format_exc()) return False