From cac02f36ccc69b81af8d22582384c37d072a08f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Charette?= Date: Mon, 9 Jun 2008 08:08:33 +0000 Subject: [PATCH] bug report 2214: fix for "Graphviz reports cause GRAMPS to hang for long periods of time" svn: r10796 --- src/ReportBase/_GraphvizReportDialog.py | 209 ++++++++++-------------- 1 file changed, 85 insertions(+), 124 deletions(-) diff --git a/src/ReportBase/_GraphvizReportDialog.py b/src/ReportBase/_GraphvizReportDialog.py index 3496b2e54..b38a197e1 100644 --- a/src/ReportBase/_GraphvizReportDialog.py +++ b/src/ReportBase/_GraphvizReportDialog.py @@ -28,6 +28,8 @@ import os from cStringIO import StringIO import tempfile +import thread +import threading from types import ClassType, InstanceType from gettext import gettext as _ @@ -213,7 +215,54 @@ class GVDocBase(BaseDoc.BaseDoc,BaseDoc.GVDoc): self.write( ' fontsize="%d";\n' % self.notesize ) self.write( '}\n\n' ) - + + def animate_progress_bar(self): + """ + The progress bar wont animate unless it is pulsed, + so a timer is created to regularly call this method. + """ + self.progress.pbar.pulse() + + # Schedule the next pulse + self.progress_timer = threading.Timer(1.0, self.animate_progress_bar) + self.progress_timer.start() + + def generate_output_file_from_dot_file(self, dotcommand, mimetype): + """ + We now have the entire content of the .dot file. Last thing + we need to do is to call dot (part of the Graphviz package) + to generate the .png, .gif, ...etc... output file. Note that + this can take a relatively long time for large or complicated + graphs, so this method is called on a 2nd thread to prevent + GRAMPS from appearing to have "hung". + """ + + self.progress = Utils.ProgressMeter(_('Processing File'), '') + self.progress.set_pass(self.filename, 0) + self.progress.pbar.set_pulse_step(0.1) + + # Start a timer to ensure the progress bar is animated + self.animate_progress_bar() + + # Create a temporary dot file + (handle, tmp_dot) = tempfile.mkstemp(".dot" ) + dotfile = os.fdopen(handle,"w") + dotfile.write(self.dot.getvalue()) + dotfile.close() + + # Use the temporary dot file to generate the final output file + os.system(dotcommand % (self.filename, tmp_dot)) + + # Delete the temporary dot file + os.remove(tmp_dot) + + if mimetype and self.print_req: + app = Mime.get_application(mimetype) + Utils.launch(app[0], self.filename) + + self.progress_timer.cancel() + self.progress.close() + def add_node(self, id, label, shape="", color="", style="", fillcolor="", url="", htmloutput=False ): """ @@ -342,21 +391,9 @@ class GVPsDoc(GVDocBase): if self.filename[-3:] != ".ps": self.filename += ".ps" - # Create a temporary dot file - (handle,tmp_dot) = tempfile.mkstemp(".dot" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self.dot.getvalue()) - dotfile.close() - - # Generate the PS file. - os.system( 'dot -Tps2 -o"%s" "%s"' % (self.filename,tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.print_req: - app = Mime.get_application("application/postscript") - Utils.launch(app[0], self.filename) + thread.start_new_thread( + self.generate_output_file_from_dot_file, + ('dot -Tps2 -o"%s" "%s"', "application/postscript")) #------------------------------------------------------------------------------- # @@ -379,21 +416,9 @@ class GVSvgDoc(GVDocBase): if self.filename[-4:] != ".svg": self.filename += ".svg" - # Create a temporary dot file - (handle,tmp_dot) = tempfile.mkstemp(".dot" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self.dot.getvalue()) - dotfile.close() - - # Generate the SVG file. - os.system( 'dot -Tsvg -o"%s" "%s"' % (self.filename,tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.print_req: - app = Mime.get_application("image/svg") - Utils.launch(app[0], self.filename) + thread.start_new_thread( + self.generate_output_file_from_dot_file, + ('dot -Tsvg -o"%s" "%s"', "image/svg")) #------------------------------------------------------------------------------- # @@ -416,21 +441,9 @@ class GVSvgzDoc(GVDocBase): if self.filename[-5:] != ".svgz": self.filename += ".svgz" - # Create a temporary dot file - (handle,tmp_dot) = tempfile.mkstemp(".dot" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self.dot.getvalue()) - dotfile.close() - - # Generate the SVGZ file. - os.system( 'dot -Tsvgz -o"%s" "%s"' % (self.filename,tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.print_req: - app = Mime.get_application("image/svgz") - Utils.launch(app[0], self.filename) + thread.start_new_thread( + self.generate_output_file_from_dot_file, + ('dot -Tsvgz -o"%s" "%s"', "image/svgz")) #------------------------------------------------------------------------------- # @@ -448,27 +461,15 @@ class GVPngDoc(GVDocBase): def close(self): GVDocBase.close(self) - + # Make sure the extension is correct if self.filename[-4:] != ".png": self.filename += ".png" - # Create a temporary dot file - (handle,tmp_dot) = tempfile.mkstemp(".dot" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self.dot.getvalue()) - dotfile.close() + thread.start_new_thread( + self.generate_output_file_from_dot_file, + ('dot -Tpng -o"%s" "%s"', "image/png")) - # Generate the PNG file. - os.system( 'dot -Tpng -o"%s" "%s"' % (self.filename,tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.print_req: - app = Mime.get_application("image/png") - Utils.launch(app[0], self.filename) - #------------------------------------------------------------------------------- # # GVJpegDoc @@ -490,22 +491,10 @@ class GVJpegDoc(GVDocBase): if self.filename[-4:] != ".jpg": self.filename += ".jpg" - # Create a temporary dot file - (handle,tmp_dot) = tempfile.mkstemp(".dot" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self.dot.getvalue()) - dotfile.close() + thread.start_new_thread( + self.generate_output_file_from_dot_file, + ('dot -Tjpg -o"%s" "%s"', "image/jpeg")) - # Generate the JPG file. - os.system( 'dot -Tjpg -o"%s" "%s"' % (self.filename,tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.print_req: - app = Mime.get_application("image/jpeg") - Utils.launch(app[0], self.filename) - #------------------------------------------------------------------------------- # # GVGifDoc @@ -527,21 +516,9 @@ class GVGifDoc(GVDocBase): if self.filename[-4:] != ".gif": self.filename += ".gif" - # Create a temporary dot file - (handle,tmp_dot) = tempfile.mkstemp(".dot" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self.dot.getvalue()) - dotfile.close() - - # Generate the GIF file. - os.system( 'dot -Tgif -o"%s" "%s"' % (self.filename,tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.print_req: - app = Mime.get_application("image/gif") - Utils.launch(app[0], self.filename) + thread.start_new_thread( + self.generate_output_file_from_dot_file, + ('dot -Tgif -o"%s" "%s"', "image/gif")) #------------------------------------------------------------------------------- # @@ -567,21 +544,9 @@ class GVPdfGvDoc(GVDocBase): if self.filename[-4:] != ".pdf": self.filename += ".pdf" - # Create a temporary dot file - (handle,tmp_dot) = tempfile.mkstemp(".dot" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self.dot.getvalue()) - dotfile.close() - - # Generate the PDF file. - os.system( 'dot -Tpdf -o"%s" "%s"' % (self.filename,tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.print_req: - app = Mime.get_application("application/pdf") - Utils.launch(app[0], self.filename) + thread.start_new_thread( + self.generate_output_file_from_dot_file, + ('dot -Tpdf -o"%s" "%s"', "application/pdf")) #------------------------------------------------------------------------------- # @@ -595,33 +560,30 @@ class GVPdfGsDoc(GVDocBase): # GV documentation says dpi is only for image formats. options.handler.options_dict['dpi'] = 72 GVDocBase.__init__(self, options, paper_style) - + def close(self): GVDocBase.close(self) + # First step is to create a temporary .ps file + original_name = self.filename + if self.filename[-3:] != ".ps": + self.filename += ".ps" + + self.generate_output_file_from_dot_file( + 'dot -Tps -o"%s" "%s"', None) + + tmp_ps = self.filename + # Make sure the extension is correct + self.filename = original_name if self.filename[-4:] != ".pdf": self.filename += ".pdf" - - # Create a temporary dot file - (handle,tmp_dot) = tempfile.mkstemp(".dot" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self.dot.getvalue()) - dotfile.close() - - # Create a temporary Postscript file - (handle,tmp_ps) = tempfile.mkstemp(".ps" ) - os.close( handle ) - - # Generate Postscript using dot - command = 'dot -Tps -o"%s" "%s"' % ( tmp_ps, tmp_dot ) - os.system(command) # Add .5 to remove rounding errors. paper_size = self.paper.get_size() width_pt = int( (paper_size.get_width_inches() * 72) + 0.5 ) height_pt = int( (paper_size.get_height_inches() * 72) + 0.5 ) - + # Convert to PDF using ghostscript command = '%s -q -sDEVICE=pdfwrite -dNOPAUSE -dDEVICEWIDTHPOINTS=%d' \ ' -dDEVICEHEIGHTPOINTS=%d -sOutputFile="%s" "%s" -c quit' \ @@ -629,7 +591,6 @@ class GVPdfGsDoc(GVDocBase): os.system(command) os.remove(tmp_ps) - os.remove(tmp_dot) if self.print_req: app = Mime.get_application("application/pdf")