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

ESS_GUIESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since f2e199e was 859d960, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 6 years ago

Directory/file load location is now separate from save report and from
save/load project SASVIEW-1186

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