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

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 1f646618 was 1f646618, checked in by Piotr Rozyczko <rozyczko@…>, 6 years ago

Don't use 'directory' specifier for file save in order that the previous choice is remembered. SASVIEW-1007

  • 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 = self.getPictures(basename)
104
105        # self.data_html contains all images at the end of the report, in base64 form;
106        # replace them all with their saved on-disk filenames
107        cleanr = re.compile('<img src.*$', re.DOTALL)
108        replacement_name = ""
109        html = self.data_html
110        for picture in pictures:
111            replacement_name += '<img src="'+ picture + '"><p></p>'
112        replacement_name += '\n'
113        # <img src="data:image/png;.*>  => <img src=filename>
114        html = re.sub(cleanr, replacement_name, self.data_html)
115
116        if ext.lower() == ".txt":
117            txt_ascii = GuiUtils.replaceHTMLwithASCII(self.data_txt)
118            self.onTXTSave(txt_ascii, filename)
119        if ext.lower() == ".html":
120            self.onHTMLSave(html, filename)
121        if ext.lower() == ".pdf":
122            html_utf = GuiUtils.replaceHTMLwithUTF8(html)
123            pdf_success = self.HTML2PDF(html_utf, filename)
124            # delete images used to create the pdf
125            for pic_name in pictures:
126                os.remove(pic_name)
127            #open pdf viewer
128            if pdf_success == 0:
129                try:
130                    if os.name == 'nt':  # Windows
131                        os.startfile(filename)
132                    elif sys.platform == "darwin":  # Mac
133                        os.system("open %s" % filename)
134                except Exception as ex:
135                    # cannot open pdf.
136                    # We don't know what happened in os.* , so broad Exception is required
137                    logging.error(str(ex))
138
139    def getPictures(self, basename):
140        """
141        Returns list of saved MPL figures
142        """
143        # save figures
144        pictures = []
145        for num, image in enumerate(self.data_images):
146            pic_name = basename + '_img%s.png' % num
147            # save the image for use with pdf writer
148            image.savefig(pic_name)
149            pictures.append(pic_name)
150        return pictures
151
152    @staticmethod
153    def onTXTSave(data, filename):
154        """
155        Simple txt file serialization
156        """
157        with open(filename, 'w') as f:
158            f.write(data)
159
160    @staticmethod
161    def onHTMLSave(html, filename):
162        """
163        HTML file write
164        """
165        with open(filename, 'w') as f:
166            f.write(html)
167
168    @staticmethod
169    def HTML2PDF(data, filename):
170        """
171        Create a PDF file from html source string.
172        Returns True is the file creation was successful.
173        : data: html string
174        : filename: name of file to be saved
175        """
176        try:
177            # open output file for writing (truncated binary)
178            with open(filename, "w+b") as resultFile:
179                # convert HTML to PDF
180                pisaStatus = pisa.CreatePDF(data.encode("UTF-8"),
181                                            dest=resultFile,
182                                            encoding='UTF-8')
183                return pisaStatus.err
184        except Exception as ex:
185            # logging.error("Error creating pdf: " + str(ex))
186            logging.error("Error creating pdf: " + traceback.format_exc())
187        return False
188
189
Note: See TracBrowser for help on using the repository browser.