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

ESS_GUIESS_GUI_opencl
Last change on this file since c7e73e7 was 33c0561, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 6 years ago

Replace Apply button menu driven functionality with additional button.
Removed Cancel.
Removed the window system context help button from all affected widgets.
SASVIEW-1239

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