source: sasview/src/sas/qtgui/Utilities/ReportDialog.py @ cb90b65

ESS_GUIESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since cb90b65 was cb90b65, checked in by Piotr Rozyczko <rozyczko@…>, 6 years ago

Make sure we get meaningful reports for theories.

  • Property mode set to 100644
File size: 6.4 KB
Line 
1import os
2import sys
3import re
4import logging
5import traceback
6from xhtml2pdf import pisa
7
8from PyQt5 import QtWidgets
9from PyQt5 import QtPrintSupport
10
11import sas.qtgui.Utilities.GuiUtils as GuiUtils
12
13from sas.qtgui.Utilities.UI.ReportDialogUI import Ui_ReportDialogUI
14
15
16class ReportDialog(QtWidgets.QDialog, Ui_ReportDialogUI):
17    """
18    Class for stateless grid-like printout of model parameters for mutiple models
19    """
20    def __init__(self, parent=None, report_list=None):
21
22        super(ReportDialog, self).__init__(parent._parent)
23        self.setupUi(self)
24
25        assert isinstance(report_list, list)
26        assert len(report_list) == 3
27
28        self.data_html, self.data_txt, self.data_images = report_list
29
30        # Fill in the table from input data
31        self.setupDialog(self.data_html)
32
33        # Command buttons
34        self.cmdPrint.clicked.connect(self.onPrint)
35        self.cmdSave.clicked.connect(self.onSave)
36
37    def setupDialog(self, output=None):
38        """
39        Display the HTML content in the browser.
40        """
41        if output is not None:
42            self.txtBrowser.setHtml(output)
43
44    def onPrint(self):
45        """
46        Display the print dialog and send the report to printer
47        """
48        # Define the printer
49        printer = QtPrintSupport.QPrinter()
50
51        # Display the print dialog
52        dialog = QtPrintSupport.QPrintDialog(printer)
53        dialog.setModal(True)
54        dialog.setWindowTitle("Print")
55        if dialog.exec_() != QtWidgets.QDialog.Accepted:
56            return
57
58        document = self.txtBrowser.document()
59        try:
60            # pylint chokes on this line with syntax-error
61            # pylint: disable=syntax-error doesn't seem to help
62            document.print(printer)
63        except Exception as ex:
64            # Printing can return various exceptions, let's catch them all
65            logging.error("Print report failed with: " + str(ex))
66
67    def onSave(self):
68        """
69        Display the Save As... prompt and save the report if instructed so
70        """
71        # Choose user's home directory
72        location = os.path.expanduser('~')
73        # Use a sensible filename default
74        default_name = os.path.join(location, 'fit_report.pdf')
75
76        kwargs = {
77            'parent'   : self,
78            'caption'  : 'Save Report',
79            # don't use 'directory' in order to remember the previous user choice
80            #'directory': default_name,
81            'filter'   : 'PDF file (*.pdf);;HTML file (*.html);;Text file (*.txt)',
82            'options'  : QtWidgets.QFileDialog.DontUseNativeDialog}
83        # Query user for filename.
84        filename_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs)
85        filename = filename_tuple[0]
86        if not filename:
87            return
88        extension = filename_tuple[1]
89
90        try:
91            # extract extension from filter
92            # e.g. "PDF file (*.pdf)" -> ".pdf"
93            ext = extension[extension.find("(")+2:extension.find(")")]
94        except IndexError as ex:
95            # (ext) not found...
96            logging.error("Error while saving report. " + str(ex))
97            return
98        basename, extension = os.path.splitext(filename)
99        if not extension:
100            filename = '.'.join((filename, ext))
101
102        # Create files with charts
103        pictures = []
104        if self.data_images is not None:
105            pictures = self.getPictures(basename)
106
107        # self.data_html contains all images at the end of the report, in base64 form;
108        # replace them all with their saved on-disk filenames
109        cleanr = re.compile('<img src.*$', re.DOTALL)
110        replacement_name = ""
111        html = self.data_html
112        for picture in pictures:
113            replacement_name += '<img src="'+ picture + '"><p></p>'
114        replacement_name += '\n'
115        # <img src="data:image/png;.*>  => <img src=filename>
116        html = re.sub(cleanr, replacement_name, self.data_html)
117
118        if ext.lower() == ".txt":
119            txt_ascii = GuiUtils.replaceHTMLwithASCII(self.data_txt)
120            self.onTXTSave(txt_ascii, filename)
121        if ext.lower() == ".html":
122            self.onHTMLSave(html, filename)
123        if ext.lower() == ".pdf":
124            html_utf = GuiUtils.replaceHTMLwithUTF8(html)
125            pdf_success = self.HTML2PDF(html_utf, filename)
126            # delete images used to create the pdf
127            for pic_name in pictures:
128                os.remove(pic_name)
129            #open pdf viewer
130            if pdf_success == 0:
131                try:
132                    if os.name == 'nt':  # Windows
133                        os.startfile(filename)
134                    elif sys.platform == "darwin":  # Mac
135                        os.system("open %s" % filename)
136                except Exception as ex:
137                    # cannot open pdf.
138                    # We don't know what happened in os.* , so broad Exception is required
139                    logging.error(str(ex))
140
141    def getPictures(self, basename):
142        """
143        Returns list of saved MPL figures
144        """
145        # save figures
146        pictures = []
147        for num, image in enumerate(self.data_images):
148            pic_name = basename + '_img%s.png' % num
149            # save the image for use with pdf writer
150            image.savefig(pic_name)
151            pictures.append(pic_name)
152        return pictures
153
154    @staticmethod
155    def onTXTSave(data, filename):
156        """
157        Simple txt file serialization
158        """
159        with open(filename, 'w') as f:
160            f.write(data)
161
162    @staticmethod
163    def onHTMLSave(html, filename):
164        """
165        HTML file write
166        """
167        with open(filename, 'w') as f:
168            f.write(html)
169
170    @staticmethod
171    def HTML2PDF(data, filename):
172        """
173        Create a PDF file from html source string.
174        Returns True is the file creation was successful.
175        : data: html string
176        : filename: name of file to be saved
177        """
178        try:
179            # open output file for writing (truncated binary)
180            with open(filename, "w+b") as resultFile:
181                # convert HTML to PDF
182                pisaStatus = pisa.CreatePDF(data.encode("UTF-8"),
183                                            dest=resultFile,
184                                            encoding='UTF-8')
185                return pisaStatus.err
186        except Exception as ex:
187            # logging.error("Error creating pdf: " + str(ex))
188            logging.error("Error creating pdf: " + traceback.format_exc())
189        return False
190
191
Note: See TracBrowser for help on using the repository browser.