From e6befe67b93b495e4522535303c0489d35b4c23c Mon Sep 17 00:00:00 2001 From: Brian Matherly Date: Thu, 17 Mar 2011 03:02:36 +0000 Subject: [PATCH] Separate some general code from GUI specific code - particularly for graph generators so that graphs can be generated from the CLI. svn: r16838 --- po/POTFILES.in | 3 + src/cli/plug/__init__.py | 7 +- src/gen/plug/docgen/basedoc.py | 4 - src/gen/plug/docgen/graphdoc.py | 881 ++++++++++++++- src/gui/plug/report/_docreportdialog.py | 3 - src/gui/plug/report/_graphvizreportdialog.py | 1018 +----------------- src/gui/plug/report/_reportdialog.py | 58 +- src/plugins/BookReport.py | 7 +- src/plugins/docgen/AsciiDoc.py | 5 - src/plugins/docgen/HtmlDoc.py | 5 - src/plugins/docgen/LaTeXDoc.py | 3 - src/plugins/docgen/ODFDoc.py | 3 - src/plugins/docgen/PSDrawDoc.py | 3 - src/plugins/docgen/PdfDoc.py | 4 - src/plugins/docgen/RTFDoc.py | 4 - 15 files changed, 959 insertions(+), 1049 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 411fc34b8..cdac68e44 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -68,6 +68,9 @@ src/gen/plug/_pluginreg.py src/gen/plug/docbackend/docbackend.py src/gen/plug/utils.py +# gen docgen API +src/gen/plug/docgen/graphdoc.py + # plugin report base API (was ReportBase) src/gen/plug/report/_constants.py src/gen/plug/report/_paper.py diff --git a/src/cli/plug/__init__.py b/src/cli/plug/__init__.py index 120a4254d..1593d95bb 100644 --- a/src/cli/plug/__init__.py +++ b/src/cli/plug/__init__.py @@ -48,7 +48,7 @@ log = logging.getLogger(".") import Utils from gen.plug import BasePluginManager from gen.plug.docgen import (StyleSheet, StyleSheetList, PaperStyle, - PAPER_PORTRAIT, PAPER_LANDSCAPE) + PAPER_PORTRAIT, PAPER_LANDSCAPE, graphdoc) from gen.plug.menu import (FamilyOption, PersonOption, NoteOption, MediaOption, PersonListOption, NumberOption, BooleanOption, DestinationOption, StringOption, @@ -204,10 +204,9 @@ class CommandLineReport(object): self.options_help['off'][2].append( plugin.get_extension() + "\t" + plugin.get_description() ) elif self.category == CATEGORY_GRAPHVIZ: - from gui.plug.report._graphvizreportdialog import _FORMATS - for format in _FORMATS: + for graph_format in graphdoc.FORMATS: self.options_help['off'][2].append( - format["ext"] + "\t" + format["descr"] ) + graph_format["ext"] + "\t" + graph_format["descr"] ) else: self.options_help['off'][2] = "NA" diff --git a/src/gen/plug/docgen/basedoc.py b/src/gen/plug/docgen/basedoc.py index 4a6a2986c..eecb8f85e 100644 --- a/src/gen/plug/docgen/basedoc.py +++ b/src/gen/plug/docgen/basedoc.py @@ -75,15 +75,11 @@ class BaseDoc(object): self.paper = paper_style self._style_sheet = styles self._creator = "" - self.open_req = 0 self.init_called = False self.type = "standard" def init(self): self.init_called = True - - def open_requested(self): - self.open_req = 1 def set_creator(self, name): "Set the owner name" diff --git a/src/gen/plug/docgen/graphdoc.py b/src/gen/plug/docgen/graphdoc.py index fbddbc88b..716c0f6bf 100644 --- a/src/gen/plug/docgen/graphdoc.py +++ b/src/gen/plug/docgen/graphdoc.py @@ -24,13 +24,28 @@ # $Id$ - -#------------------------------------------------------------------------- +#------------------------------------------------------------------------ # -# standard python modules +# python modules # -#------------------------------------------------------------------------- +#------------------------------------------------------------------------ +import os +from cStringIO import StringIO +import tempfile +from subprocess import Popen, PIPE +import sys +#------------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------------- +from gen.ggettext import gettext as _ +import Utils +from gen.plug.docgen import BaseDoc +from gen.plug.menu import NumberOption, TextOption, EnumeratedListOption, \ + BooleanOption +import constfunc #------------------------------------------------------------------------- # @@ -40,6 +55,209 @@ import logging log = logging.getLogger(".graphdoc") +#------------------------------------------------------------------------------- +# +# Private Constants +# +#------------------------------------------------------------------------------- +_FONTS = [ { 'name' : _("Default"), 'value' : "" }, + { 'name' : _("PostScript / Helvetica"), 'value' : "Helvetica" }, + { 'name' : _("TrueType / FreeSans"), 'value' : "FreeSans" } ] + +_RANKDIR = [ { 'name' : _("Vertical (top to bottom)"), 'value' : "TB" }, + { 'name' : _("Vertical (bottom to top)"), 'value' : "BT" }, + { 'name' : _("Horizontal (left to right)"), 'value' : "LR" }, + { 'name' : _("Horizontal (right to left)"), 'value' : "RL" } ] + +_PAGEDIR = [ { 'name' : _("Bottom, left"), 'value' :"BL" }, + { 'name' : _("Bottom, right"), 'value' :"BR" }, + { 'name' : _("Top, left"), 'value' :"TL" }, + { 'name' : _("Top, Right"), 'value' :"TR" }, + { 'name' : _("Right, bottom"), 'value' :"RB" }, + { 'name' : _("Right, top"), 'value' :"RT" }, + { 'name' : _("Left, bottom"), 'value' :"LB" }, + { 'name' : _("Left, top"), 'value' :"LT" } ] + +_RATIO = [ { 'name' : _("Minimal size"), 'value': "compress" }, + { 'name' : _("Fill the given area"), 'value': "fill" }, + { 'name' : _("Use optimal number of pages"), 'value': "expand" } ] + +_NOTELOC = [ { 'name' : _("Top"), 'value' : "t" }, + { 'name' : _("Bottom"), 'value' : "b" }] + +if constfunc.win(): + _DOT_FOUND = Utils.search_for("dot.exe") + + if Utils.search_for("gswin32c.exe") == 1: + _GS_CMD = "gswin32c.exe" + elif Utils.search_for("gswin32.exe") == 1: + _GS_CMD = "gswin32.exe" + else: + _GS_CMD = "" +else: + _DOT_FOUND = Utils.search_for("dot") + + if Utils.search_for("gs") == 1: + _GS_CMD = "gs" + else: + _GS_CMD = "" + +#------------------------------------------------------------------------------- +# +# GVOptions +# +#------------------------------------------------------------------------------- +class GVOptions(): + """ + Defines all of the controls necessary + to configure the graph reports. + """ + def __init__(self): + self.h_pages = None + self.v_pages = None + self.page_dir = None + + def add_menu_options(self, menu): + """ + Add all graph related options to the menu. + + @param menu: The menu the options should be added to. + @type menu: gen.plug.menu.Menu() + @return: nothing + """ + ################################ + category = _("GraphViz Layout") + ################################ + font_family = EnumeratedListOption(_("Font family"), "") + for item in _FONTS: + font_family.add_item(item["value"], item["name"]) + font_family.set_help(_("Choose the font family. If international " + "characters don't show, use FreeSans font. " + "FreeSans is available from: " + "http://www.nongnu.org/freefont/")) + menu.add_option(category, "font_family", font_family) + + font_size = NumberOption(_("Font size"), 14, 8, 128) + font_size.set_help(_("The font size, in points.")) + menu.add_option(category, "font_size", font_size) + + rank_dir = EnumeratedListOption(_("Graph Direction"), "TB") + for item in _RANKDIR: + rank_dir.add_item(item["value"], item["name"]) + rank_dir.set_help(_("Whether graph goes from top to bottom " + "or left to right.")) + menu.add_option(category, "rank_dir", rank_dir) + + h_pages = NumberOption(_("Number of Horizontal Pages"), 1, 1, 25) + h_pages.set_help(_("GraphViz can create very large graphs by " + "spreading the graph across a rectangular " + "array of pages. This controls the number " + "pages in the array horizontally. " + "Only valid for dot and pdf via Ghostscript.")) + menu.add_option(category, "h_pages", h_pages) + + v_pages = NumberOption(_("Number of Vertical Pages"), 1, 1, 25) + v_pages.set_help(_("GraphViz can create very large graphs by " + "spreading the graph across a rectangular " + "array of pages. This controls the number " + "pages in the array vertically. " + "Only valid for dot and pdf via Ghostscript.")) + menu.add_option(category, "v_pages", v_pages) + + page_dir = EnumeratedListOption(_("Paging Direction"), "BL") + for item in _PAGEDIR: + page_dir.add_item(item["value"], item["name"]) + page_dir.set_help(_("The order in which the graph pages are output. " + "This option only applies if the horizontal pages " + "or vertical pages are greater than 1.")) + menu.add_option(category, "page_dir", page_dir) + + # the page direction option only makes sense when the + # number of horizontal and/or vertical pages is > 1, + # so we need to remember these 3 controls for later + self.h_pages = h_pages + self.v_pages = v_pages + self.page_dir = page_dir + + # the page direction option only makes sense when the + # number of horizontal and/or vertical pages is > 1 + self.h_pages.connect('value-changed', self.pages_changed) + self.v_pages.connect('value-changed', self.pages_changed) + + ################################ + category = _("GraphViz Options") + ################################ + + aspect_ratio = EnumeratedListOption(_("Aspect ratio"), "fill") + for item in _RATIO: + aspect_ratio.add_item(item["value"], item["name"]) + aspect_ratio.set_help(_("Affects greatly how the graph is layed out " + "on the page.")) + menu.add_option(category, "ratio", aspect_ratio) + + dpi = NumberOption(_("DPI"), 75, 20, 1200) + dpi.set_help(_( "Dots per inch. When creating images such as " + ".gif or .png files for the web, try numbers " + "such as 100 or 300 DPI. When creating PostScript " + "or PDF files, use 72 DPI.")) + menu.add_option(category, "dpi", dpi) + + nodesep = NumberOption(_("Node spacing"), 0.20, 0.01, 5.00, 0.01) + nodesep.set_help(_( "The minimum amount of free space, in inches, " + "between individual nodes. For vertical graphs, " + "this corresponds to spacing between columns. " + "For horizontal graphs, this corresponds to " + "spacing between rows.")) + menu.add_option(category, "nodesep", nodesep) + + ranksep = NumberOption(_("Rank spacing"), 0.20, 0.01, 5.00, 0.01) + ranksep.set_help(_( "The minimum amount of free space, in inches, " + "between ranks. For vertical graphs, this " + "corresponds to spacing between rows. For " + "horizontal graphs, this corresponds to spacing " + "between columns.")) + menu.add_option(category, "ranksep", ranksep) + + use_subgraphs = BooleanOption(_('Use subgraphs'), True) + use_subgraphs.set_help(_("Subgraphs can help GraphViz position " + "spouses together, but with non-trivial " + "graphs will result in longer lines and " + "larger graphs.")) + menu.add_option(category, "usesubgraphs", use_subgraphs) + + ################################ + category = _("Note") + ################################ + + note = TextOption(_("Note to add to the graph"), + [""] ) + note.set_help(_("This text will be added to the graph.")) + menu.add_option(category, "note", note) + + noteloc = EnumeratedListOption(_("Note location"), 't') + for i in range( 0, len(_NOTELOC) ): + noteloc.add_item(_NOTELOC[i]["value"], _NOTELOC[i]["name"]) + noteloc.set_help(_("Whether note will appear on top " + "or bottom of the page.")) + menu.add_option(category, "noteloc", noteloc) + + notesize = NumberOption(_("Note size"), 32, 8, 128) + notesize.set_help(_("The size of note text, in points.")) + menu.add_option(category, "notesize", notesize) + + def pages_changed(self): + """ + This method gets called every time the v_pages or h_pages + options are changed; when both vertical and horizontal + pages are set to "1", then the page_dir control needs to + be unavailable + """ + if self.v_pages.get_value() > 1 or \ + self.h_pages.get_value() > 1: + self.page_dir.set_available(True) + else: + self.page_dir.set_available(False) + #------------------------------------------------------------------------------- # # GVDoc @@ -128,3 +346,658 @@ class GVDoc(object): @return: nothing """ raise NotImplementedError + +#------------------------------------------------------------------------------- +# +# GVDocBase +# +#------------------------------------------------------------------------------- +class GVDocBase(BaseDoc, GVDoc): + """ + Base document generator for all Graphviz document generators. Classes that + inherit from this class will only need to implement the close function. + The close function will generate the actual file of the appropriate type. + """ + def __init__(self, options, paper_style): + BaseDoc.__init__(self, None, paper_style) + + self._filename = None + self._dot = StringIO() + self._paper = paper_style + + get_option_by_name = options.menu.get_option_by_name + get_value = lambda name: get_option_by_name(name).get_value() + + self.dpi = get_value('dpi') + self.fontfamily = get_value('font_family') + self.fontsize = get_value('font_size') + self.hpages = get_value('h_pages') + self.nodesep = get_value('nodesep') + self.noteloc = get_value('noteloc') + self.notesize = get_value('notesize') + self.note = get_value('note') + self.pagedir = get_value('page_dir') + self.rankdir = get_value('rank_dir') + self.ranksep = get_value('ranksep') + self.ratio = get_value('ratio') + self.vpages = get_value('v_pages') + self.usesubgraphs = get_value('usesubgraphs') + + paper_size = paper_style.get_size() + + # Subtract 0.01" from the drawing area to make some room between + # this area and the margin in order to compensate for different + # rounding errors internally in dot + sizew = ( paper_size.get_width() - + self._paper.get_left_margin() - + self._paper.get_right_margin() ) / 2.54 - 0.01 + sizeh = ( paper_size.get_height() - + self._paper.get_top_margin() - + self._paper.get_bottom_margin() ) / 2.54 - 0.01 + + pheight = paper_size.get_height_inches() + pwidth = paper_size.get_width_inches() + + xmargin = self._paper.get_left_margin() / 2.54 + ymargin = self._paper.get_top_margin() / 2.54 + + sizew *= self.hpages + sizeh *= self.vpages + + self.write( + 'digraph GRAMPS_graph\n' + '{\n' + ' bgcolor=white;\n' + ' center="true"; \n' + ' charset="utf8";\n' + ' concentrate="false";\n' + + ' dpi="%d";\n' % self.dpi + + ' graph [fontsize=%d];\n' % self.fontsize + + ' margin="%3.2f,%3.2f"; \n' % (xmargin, ymargin) + + ' mclimit="99";\n' + + ' nodesep="%.2f";\n' % self.nodesep + + ' outputorder="edgesfirst";\n' + + ('#' if self.hpages == self.vpages == 1 else '') + + # comment out "page=" if the graph is on 1 page (bug #2121) + ' page="%3.2f,%3.2f";\n' % (pwidth, pheight) + + ' pagedir="%s";\n' % self.pagedir + + ' rankdir="%s";\n' % self.rankdir + + ' ranksep="%.2f";\n' % self.ranksep + + ' ratio="%s";\n' % self.ratio + + ' searchsize="100";\n' + + ' size="%3.2f,%3.2f"; \n' % (sizew, sizeh) + + ' splines="true";\n' + + '\n' + + ' edge [len=0.5 style=solid fontsize=%d];\n' % self.fontsize + ) + if self.fontfamily: + self.write( ' node [style=filled fontname="%s" fontsize=%d];\n' + % ( self.fontfamily, self.fontsize ) ) + else: + self.write( ' node [style=filled fontsize=%d];\n' + % self.fontsize ) + self.write( '\n' ) + + def write(self, text): + """ Write text to the dot file """ + self._dot.write(text.encode('utf8', 'xmlcharrefreplace')) + + def open(self, filename): + """ Implement BaseDoc.open() """ + self._filename = os.path.normpath(os.path.abspath(filename)) + + def close(self): + """ + This isn't useful by itself. Other classes need to override this and + actually generate a file. + """ + if self.note: + # build up the label + label = u'' + for line in self.note: # for every line in the note... + line = line.strip() # ...strip whitespace from this line... + if line != '': # ...and if we still have a line... + if label != '': # ...see if we need to insert a newline... + label += '\\n' + label += line.replace('"', '\\\"') + + # after all that, see if we have a label to display + if label != '': + self.write( + '\n' + + ' label="%s";\n' % label + + ' labelloc="%s";\n' % self.noteloc + + ' fontsize="%d";\n' % self.notesize + ) + + self.write( '}\n\n' ) + + def add_node(self, node_id, label, shape="", color="", + style="", fillcolor="", url="", htmloutput=False): + """ + Add a node to this graph. Nodes can be different shapes like boxes and + circles. + + Implements GVDoc.add_node(). + """ + text = '[' + + if shape: + text += ' shape="%s"' % shape + + if color: + text += ' color="%s"' % color + + if fillcolor: + text += ' fillcolor="%s"' % fillcolor + + if style: + text += ' style="%s"' % style + + # note that we always output a label -- even if an empty string -- + # otherwise GraphViz uses the node ID as the label which is unlikely + # to be what the user wants to see in the graph + if label.startswith("<") or htmloutput: + text += ' label=<%s>' % label + else: + text += ' label="%s"' % label + + if url: + text += ' URL="%s"' % url + + text += " ]" + self.write(' %s %s;\n' % (node_id, text)) + + def add_link(self, id1, id2, style="", head="", tail="", comment=""): + """ + Add a link between two nodes. + + Implements GVDoc.add_link(). + """ + self.write(' %s -> %s' % (id1, id2)) + + if style or head or tail: + self.write(' [') + + if style: + self.write(' style=%s' % style) + if head: + self.write(' arrowhead=%s' % head) + if tail: + self.write(' arrowtail=%s' % tail) + if head: + if tail: + self.write(' dir=both') + else: + self.write(' dir=forward') + else: + if tail: + self.write(' dir=back') + else: + self.write(' dir=none') + self.write(' ]') + + self.write(';') + + if comment: + self.write(' // %s' % comment) + + self.write('\n') + + def add_comment(self, comment): + """ + Add a comment. + + Implements GVDoc.add_comment(). + """ + tmp = comment.split('\n') + for line in tmp: + text = line.strip() + if text == "": + self.write('\n') + elif text.startswith('#'): + self.write('%s\n' % text) + else: + self.write('# %s\n' % text) + + def start_subgraph(self, graph_id): + """ Implement GVDoc.start_subgraph() """ + self.write( + ' subgraph cluster_%s\n' % graph_id + + ' {\n' + + ' style="invis";\n' # no border around subgraph (#0002176) + ) + + def end_subgraph(self): + """ Implement GVDoc.end_subgraph() """ + self.write(' }\n') + +#------------------------------------------------------------------------------- +# +# GVDotDoc +# +#------------------------------------------------------------------------------- +class GVDotDoc(GVDocBase): + """ GVDoc implementation that generates a .gv text file. """ + + def close(self): + """ Implements GVDocBase.close() """ + GVDocBase.close(self) + + # Make sure the extension is correct + if self._filename[-3:] != ".gv": + self._filename += ".gv" + + dotfile = open(self._filename, "w") + dotfile.write(self._dot.getvalue()) + dotfile.close() + +#------------------------------------------------------------------------------- +# +# GVPsDoc +# +#------------------------------------------------------------------------------- +class GVPsDoc(GVDocBase): + """ GVDoc implementation that generates a .ps file using Graphviz. """ + + def __init__(self, options, paper_style): + # DPI must always be 72 for PDF. + # GV documentation says dpi is only for image formats. + options.menu.get_option_by_name('dpi').set_value(72) + GVDocBase.__init__(self, options, paper_style) + # GV documentation allow multiple pages only for ps format, + # But it does not work with -Tps:cairo in order to + # show Non Latin-1 letters. Force to only 1 page. + # See bug tracker issue 2815 + options.menu.get_option_by_name('v_pages').set_value(1) + options.menu.get_option_by_name('h_pages').set_value(1) + GVDocBase.__init__(self, options, paper_style) + + def close(self): + """ Implements GVDocBase.close() """ + GVDocBase.close(self) + + # Make sure the extension is correct + if self._filename[-3:] != ".ps": + self._filename += ".ps" + + # Create a temporary dot file + (handle, tmp_dot) = tempfile.mkstemp(".gv" ) + dotfile = os.fdopen(handle,"w") + dotfile.write(self._dot.getvalue()) + dotfile.close() + + # Generate the PS file. + # Reason for using -Tps:cairo. Needed for Non Latin-1 letters + # Some testing with Tps:cairo. Non Latin-1 letters are OK i all cases: + # Output format: ps PDF-GostScript PDF-GraphViz + # Single page OK OK OK + # Multip page 1 page, OK 1 page, + # corrupted set by gramps + # If I take a correct multip page PDF and convert it with pdf2ps I get + # multip pages, but the output is clipped, some margins have + # disappeared. I used 1 inch margins always. + # See bug tracker issue 2815 + # :cairo does not work with Graphviz 2.26.3 See issue 4164 + # Covert filename to str using file system encoding. + fname = self._filename.encode(sys.getfilesystemencoding()) + + command = 'dot -Tps:cairo -o"%s" "%s"' % (fname, tmp_dot) + dotversion = Popen(['dot', '-V'], stderr=PIPE).communicate(input=None)[1] + # Problem with dot 2.26.3 and multiple pages, which gives "cairo: out of + # memory" If the :cairo is skipped for these cases it gives acceptable + # result. + if dotversion.find('2.26.3') != -1 and (self.vpages * self.hpages) > 1: + command = command.replace(':cairo','') + os.system(command) + # Delete the temporary dot file + os.remove(tmp_dot) + +#------------------------------------------------------------------------------- +# +# GVSvgDoc +# +#------------------------------------------------------------------------------- +class GVSvgDoc(GVDocBase): + """ GVDoc implementation that generates a .svg file using Graphviz. """ + + def __init__(self, options, paper_style): + # GV documentation allow multiple pages only for ps format, + # which also includes pdf via ghostscript. + options.menu.get_option_by_name('v_pages').set_value(1) + options.menu.get_option_by_name('h_pages').set_value(1) + GVDocBase.__init__(self, options, paper_style) + + def close(self): + """ Implements GVDocBase.close() """ + GVDocBase.close(self) + + # Make sure the extension is correct + if self._filename[-4:] != ".svg": + self._filename += ".svg" + + # Create a temporary dot file + (handle, tmp_dot) = tempfile.mkstemp(".gv" ) + dotfile = os.fdopen(handle,"w") + dotfile.write(self._dot.getvalue()) + dotfile.close() + # Covert filename to str using file system encoding. + fname = self._filename.encode(sys.getfilesystemencoding()) + + # Generate the SVG file. + os.system( 'dot -Tsvg -o"%s" "%s"' % (fname, tmp_dot) ) + + # Delete the temporary dot file + os.remove(tmp_dot) + +#------------------------------------------------------------------------------- +# +# GVSvgzDoc +# +#------------------------------------------------------------------------------- +class GVSvgzDoc(GVDocBase): + """ GVDoc implementation that generates a .svg file using Graphviz. """ + + def __init__(self, options, paper_style): + # GV documentation allow multiple pages only for ps format, + # which also includes pdf via ghostscript. + options.menu.get_option_by_name('v_pages').set_value(1) + options.menu.get_option_by_name('h_pages').set_value(1) + GVDocBase.__init__(self, options, paper_style) + + def close(self): + """ Implements GVDocBase.close() """ + GVDocBase.close(self) + + # Make sure the extension is correct + if self._filename[-5:] != ".svgz": + self._filename += ".svgz" + + # Create a temporary dot file + (handle, tmp_dot) = tempfile.mkstemp(".gv" ) + dotfile = os.fdopen(handle,"w") + dotfile.write(self._dot.getvalue()) + dotfile.close() + # Covert filename to str using file system encoding. + fname = self._filename.encode(sys.getfilesystemencoding()) + + # Generate the SVGZ file. + os.system( 'dot -Tsvgz -o"%s" "%s"' % (fname, tmp_dot) ) + + # Delete the temporary dot file + os.remove(tmp_dot) + +#------------------------------------------------------------------------------- +# +# GVPngDoc +# +#------------------------------------------------------------------------------- +class GVPngDoc(GVDocBase): + """ GVDoc implementation that generates a .png file using Graphviz. """ + + def __init__(self, options, paper_style): + # GV documentation allow multiple pages only for ps format, + # which also includes pdf via ghostscript. + options.menu.get_option_by_name('v_pages').set_value(1) + options.menu.get_option_by_name('h_pages').set_value(1) + GVDocBase.__init__(self, options, paper_style) + + def close(self): + """ Implements GVDocBase.close() """ + 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(".gv" ) + dotfile = os.fdopen(handle,"w") + dotfile.write(self._dot.getvalue()) + dotfile.close() + # Covert filename to str using file system encoding. + fname = self._filename.encode(sys.getfilesystemencoding()) + + # Generate the PNG file. + os.system( 'dot -Tpng -o"%s" "%s"' % (fname, tmp_dot) ) + + # Delete the temporary dot file + os.remove(tmp_dot) + +#------------------------------------------------------------------------------- +# +# GVJpegDoc +# +#------------------------------------------------------------------------------- +class GVJpegDoc(GVDocBase): + """ GVDoc implementation that generates a .jpg file using Graphviz. """ + + def __init__(self, options, paper_style): + # GV documentation allow multiple pages only for ps format, + # which also includes pdf via ghostscript. + options.menu.get_option_by_name('v_pages').set_value(1) + options.menu.get_option_by_name('h_pages').set_value(1) + GVDocBase.__init__(self, options, paper_style) + + def close(self): + """ Implements GVDocBase.close() """ + GVDocBase.close(self) + + # Make sure the extension is correct + if self._filename[-4:] != ".jpg": + self._filename += ".jpg" + + # Create a temporary dot file + (handle, tmp_dot) = tempfile.mkstemp(".gv" ) + dotfile = os.fdopen(handle,"w") + dotfile.write(self._dot.getvalue()) + dotfile.close() + # Covert filename to str using file system encoding. + fname = self._filename.encode(sys.getfilesystemencoding()) + + # Generate the JPEG file. + os.system( 'dot -Tjpg -o"%s" "%s"' % (fname, tmp_dot) ) + + # Delete the temporary dot file + os.remove(tmp_dot) + +#------------------------------------------------------------------------------- +# +# GVGifDoc +# +#------------------------------------------------------------------------------- +class GVGifDoc(GVDocBase): + """ GVDoc implementation that generates a .gif file using Graphviz. """ + + def __init__(self, options, paper_style): + # GV documentation allow multiple pages only for ps format, + # which also includes pdf via ghostscript. + options.menu.get_option_by_name('v_pages').set_value(1) + options.menu.get_option_by_name('h_pages').set_value(1) + GVDocBase.__init__(self, options, paper_style) + + def close(self): + """ Implements GVDocBase.close() """ + GVDocBase.close(self) + + # Make sure the extension is correct + if self._filename[-4:] != ".gif": + self._filename += ".gif" + + # Create a temporary dot file + (handle, tmp_dot) = tempfile.mkstemp(".gv" ) + dotfile = os.fdopen(handle,"w") + dotfile.write(self._dot.getvalue()) + dotfile.close() + # Covert filename to str using file system encoding. + fname = self._filename.encode(sys.getfilesystemencoding()) + + # Generate the GIF file. + os.system( 'dot -Tgif -o"%s" "%s"' % (fname, tmp_dot) ) + + # Delete the temporary dot file + os.remove(tmp_dot) + +#------------------------------------------------------------------------------- +# +# GVPdfGvDoc +# +#------------------------------------------------------------------------------- +class GVPdfGvDoc(GVDocBase): + """ GVDoc implementation that generates a .pdf file using Graphviz. """ + + def __init__(self, options, paper_style): + # DPI must always be 72 for PDF. + # GV documentation says dpi is only for image formats. + options.menu.get_option_by_name('dpi').set_value(72) + # GV documentation allow multiple pages only for ps format, + # which also includes pdf via ghostscript. + options.menu.get_option_by_name('v_pages').set_value(1) + options.menu.get_option_by_name('h_pages').set_value(1) + GVDocBase.__init__(self, options, paper_style) + + def close(self): + """ Implements GVDocBase.close() """ + GVDocBase.close(self) + + # Make sure the extension is correct + if self._filename[-4:] != ".pdf": + self._filename += ".pdf" + + # Create a temporary dot file + (handle, tmp_dot) = tempfile.mkstemp(".gv" ) + dotfile = os.fdopen(handle,"w") + dotfile.write(self._dot.getvalue()) + dotfile.close() + # Covert filename to str using file system encoding. + fname = self._filename.encode(sys.getfilesystemencoding()) + + # Generate the PDF file. + os.system( 'dot -Tpdf -o"%s" "%s"' % (fname, tmp_dot) ) + + # Delete the temporary dot file + os.remove(tmp_dot) + +#------------------------------------------------------------------------------- +# +# GVPdfGsDoc +# +#------------------------------------------------------------------------------- +class GVPdfGsDoc(GVDocBase): + """ GVDoc implementation that generates a .pdf file using Ghostscript. """ + def __init__(self, options, paper_style): + # DPI must always be 72 for PDF. + # GV documentation says dpi is only for image formats. + options.menu.get_option_by_name('dpi').set_value(72) + GVDocBase.__init__(self, options, paper_style) + + def close(self): + """ Implements GVDocBase.close() """ + GVDocBase.close(self) + + # Make sure the extension is correct + if self._filename[-4:] != ".pdf": + self._filename += ".pdf" + + # Create a temporary dot file + (handle, tmp_dot) = tempfile.mkstemp(".gv" ) + 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 + # Reason for using -Tps:cairo. Needed for Non Latin-1 letters + # See bug tracker issue 2815 + # :cairo does not work with Graphviz 2.26.3 See issue 4164 + + command = 'dot -Tps:cairo -o"%s" "%s"' % ( tmp_ps, tmp_dot ) + dotversion = Popen(['dot', '-V'], stderr=PIPE).communicate(input=None)[1] + # Problem with dot 2.26.3 and multiple pages, which gives "cairo: out + # of memory". If the :cairo is skipped for these cases it gives + # acceptable result. + if dotversion.find('2.26.3') != -1 and (self.vpages * self.hpages) > 1: + command = command.replace(':cairo','') + 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 + fname = self._filename.encode(sys.getfilesystemencoding()) + command = '%s -q -sDEVICE=pdfwrite -dNOPAUSE -dDEVICEWIDTHPOINTS=%d' \ + ' -dDEVICEHEIGHTPOINTS=%d -sOutputFile="%s" "%s" -c quit' \ + % ( _GS_CMD, width_pt, height_pt, fname, tmp_ps ) + os.system(command) + + os.remove(tmp_ps) + os.remove(tmp_dot) + +#------------------------------------------------------------------------------- +# +# Various Graphviz formats. +# +#------------------------------------------------------------------------------- +FORMATS = [] + +if _DOT_FOUND: + + if _GS_CMD != "": + FORMATS += [{ 'type' : "gspdf", + 'ext' : "pdf", + 'descr': _("PDF (Ghostscript)"), + 'mime' : "application/pdf", + 'class': GVPdfGsDoc }] + + FORMATS += [{ 'type' : "gvpdf", + 'ext' : "pdf", + 'descr': _("PDF (Graphviz)"), + 'mime' : "application/pdf", + 'class': GVPdfGvDoc }] + + FORMATS += [{ 'type' : "ps", + 'ext' : "ps", + 'descr': _("PostScript"), + 'mime' : "application/postscript", + 'class': GVPsDoc }] + + FORMATS += [{ 'type' : "svg", + 'ext' : "svg", + 'descr': _("Structured Vector Graphics (SVG)"), + 'mime' : "image/svg", + 'class': GVSvgDoc }] + + FORMATS += [{ 'type' : "svgz", + 'ext' : "svgz", + 'descr': _("Compressed Structured Vector Graphs (SVGZ)"), + 'mime' : "image/svgz", + 'class': GVSvgzDoc }] + + FORMATS += [{ 'type' : "jpg", + 'ext' : "jpg", + 'descr': _("JPEG image"), + 'mime' : "image/jpeg", + 'class': GVJpegDoc }] + + FORMATS += [{ 'type' : "gif", + 'ext' : "gif", + 'descr': _("GIF image"), + 'mime' : "image/gif", + 'class': GVGifDoc }] + + FORMATS += [{ 'type' : "png", + 'ext' : "png", + 'descr': _("PNG image"), + 'mime' : "image/png", + 'class': GVPngDoc }] + +FORMATS += [{ 'type' : "dot", + 'ext' : "gv", + 'descr': _("Graphviz File"), + 'mime' : "text/x-graphviz", + 'class': GVDotDoc }] diff --git a/src/gui/plug/report/_docreportdialog.py b/src/gui/plug/report/_docreportdialog.py index b5e0a7e20..b66e2a6c0 100644 --- a/src/gui/plug/report/_docreportdialog.py +++ b/src/gui/plug/report/_docreportdialog.py @@ -101,9 +101,6 @@ class DocReportDialog(ReportDialog): self.options.set_document(self.doc) - if self.open_with_app.get_active(): - self.doc.open_requested() - def doc_type_changed(self, obj): """This routine is called when the user selects a new file formats for the report. It adjust the various dialog sections diff --git a/src/gui/plug/report/_graphvizreportdialog.py b/src/gui/plug/report/_graphvizreportdialog.py index 806699736..fa9be372a 100644 --- a/src/gui/plug/report/_graphvizreportdialog.py +++ b/src/gui/plug/report/_graphvizreportdialog.py @@ -29,14 +29,8 @@ # #------------------------------------------------------------------------ import os -from cStringIO import StringIO -import tempfile -import threading -import time -from types import ClassType, InstanceType +from types import ClassType from gen.ggettext import gettext as _ -from subprocess import Popen, PIPE -import sys #------------------------------------------------------------------------------- # @@ -51,851 +45,12 @@ import gobject # GRAMPS modules # #------------------------------------------------------------------------------- -import Utils -from gui.utils import ProgressMeter, open_file_with_default_application -from gen.plug.docgen import BaseDoc, GVDoc import config from gen.plug.report import CATEGORY_GRAPHVIZ from _reportdialog import ReportDialog from _papermenu import PaperFrame -from gen.plug.menu import NumberOption, TextOption, EnumeratedListOption, \ - BooleanOption -import constfunc - -#------------------------------------------------------------------------------- -# -# Private Constants -# -#------------------------------------------------------------------------------- -_FONTS = [ { 'name' : _("Default"), 'value' : "" }, - { 'name' : _("PostScript / Helvetica"), 'value' : "Helvetica" }, - { 'name' : _("TrueType / FreeSans"), 'value' : "FreeSans" } ] - -_RANKDIR = [ { 'name' : _("Vertical (top to bottom)"), 'value' : "TB" }, - { 'name' : _("Vertical (bottom to top)"), 'value' : "BT" }, - { 'name' : _("Horizontal (left to right)"), 'value' : "LR" }, - { 'name' : _("Horizontal (right to left)"), 'value' : "RL" } ] - -_PAGEDIR = [ { 'name' : _("Bottom, left"), 'value' :"BL" }, - { 'name' : _("Bottom, right"), 'value' :"BR" }, - { 'name' : _("Top, left"), 'value' :"TL" }, - { 'name' : _("Top, Right"), 'value' :"TR" }, - { 'name' : _("Right, bottom"), 'value' :"RB" }, - { 'name' : _("Right, top"), 'value' :"RT" }, - { 'name' : _("Left, bottom"), 'value' :"LB" }, - { 'name' : _("Left, top"), 'value' :"LT" } ] - -_RATIO = [ { 'name' : _("Minimal size"), 'value': "compress" }, - { 'name' : _("Fill the given area"), 'value': "fill" }, - { 'name' : _("Use optimal number of pages"), 'value': "expand" } ] - -_NOTELOC = [ { 'name' : _("Top"), 'value' : "t" }, - { 'name' : _("Bottom"), 'value' : "b" }] - -if constfunc.win(): - _DOT_FOUND = Utils.search_for("dot.exe") - - if Utils.search_for("gswin32c.exe") == 1: - _GS_CMD = "gswin32c.exe" - elif Utils.search_for("gswin32.exe") == 1: - _GS_CMD = "gswin32.exe" - else: - _GS_CMD = "" -else: - _DOT_FOUND = Utils.search_for("dot") - - if Utils.search_for("gs") == 1: - _GS_CMD = "gs" - else: - _GS_CMD = "" - -#------------------------------------------------------------------------------- -# -# Private Functions -# -#------------------------------------------------------------------------------- -def _run_long_process_in_thread(func, header): - """ - This function will spawn a new thread to execute the provided function. - While the function is running, a progress bar will be created. - The progress bar will show activity while the function executes. - - @param func: A function that will take an unknown amount of time to - complete. - @type category: callable - @param header: A header for the progress bar. - Example: "Updating Data" - @type name: string - @return: nothing - - """ - pbar = ProgressMeter(_('Processing File')) - pbar.set_pass(total=40, - mode=ProgressMeter.MODE_ACTIVITY, - header=header) - - sys_thread = threading.Thread(target=func) - sys_thread.start() - - while sys_thread.isAlive(): - # The loop runs 20 times per second until the thread completes. - # With the progress pass total set at 40, it should move across the bar - # every two seconds. - time.sleep(0.05) - pbar.step() - - pbar.close() - -#------------------------------------------------------------------------------- -# -# GVDocBase -# -#------------------------------------------------------------------------------- -class GVDocBase(BaseDoc, GVDoc): - """ - Base document generator for all Graphviz document generators. Classes that - inherit from this class will only need to implement the close function. - The close function will generate the actual file of the appropriate type. - """ - def __init__(self, options, paper_style): - BaseDoc.__init__(self, None, paper_style) - - self._filename = None - self._dot = StringIO() - self._paper = paper_style - - get_option_by_name = options.menu.get_option_by_name - get_value = lambda name: get_option_by_name(name).get_value() - - self.dpi = get_value('dpi') - self.fontfamily = get_value('font_family') - self.fontsize = get_value('font_size') - self.hpages = get_value('h_pages') - self.nodesep = get_value('nodesep') - self.noteloc = get_value('noteloc') - self.notesize = get_value('notesize') - self.note = get_value('note') - self.pagedir = get_value('page_dir') - self.rankdir = get_value('rank_dir') - self.ranksep = get_value('ranksep') - self.ratio = get_value('ratio') - self.vpages = get_value('v_pages') - self.usesubgraphs = get_value('usesubgraphs') - - paper_size = paper_style.get_size() - - # Subtract 0.01" from the drawing area to make some room between - # this area and the margin in order to compensate for different - # rounding errors internally in dot - sizew = ( paper_size.get_width() - - self._paper.get_left_margin() - - self._paper.get_right_margin() ) / 2.54 - 0.01 - sizeh = ( paper_size.get_height() - - self._paper.get_top_margin() - - self._paper.get_bottom_margin() ) / 2.54 - 0.01 - - pheight = paper_size.get_height_inches() - pwidth = paper_size.get_width_inches() - - xmargin = self._paper.get_left_margin() / 2.54 - ymargin = self._paper.get_top_margin() / 2.54 - - sizew *= self.hpages - sizeh *= self.vpages - - self.write( - 'digraph GRAMPS_graph\n' - '{\n' - ' bgcolor=white;\n' - ' center="true"; \n' - ' charset="utf8";\n' - ' concentrate="false";\n' + - ' dpi="%d";\n' % self.dpi + - ' graph [fontsize=%d];\n' % self.fontsize + - ' margin="%3.2f,%3.2f"; \n' % (xmargin, ymargin) + - ' mclimit="99";\n' + - ' nodesep="%.2f";\n' % self.nodesep + - ' outputorder="edgesfirst";\n' + - ('#' if self.hpages == self.vpages == 1 else '') + - # comment out "page=" if the graph is on 1 page (bug #2121) - ' page="%3.2f,%3.2f";\n' % (pwidth, pheight) + - ' pagedir="%s";\n' % self.pagedir + - ' rankdir="%s";\n' % self.rankdir + - ' ranksep="%.2f";\n' % self.ranksep + - ' ratio="%s";\n' % self.ratio + - ' searchsize="100";\n' + - ' size="%3.2f,%3.2f"; \n' % (sizew, sizeh) + - ' splines="true";\n' + - '\n' + - ' edge [len=0.5 style=solid fontsize=%d];\n' % self.fontsize - ) - if self.fontfamily: - self.write( ' node [style=filled fontname="%s" fontsize=%d];\n' - % ( self.fontfamily, self.fontsize ) ) - else: - self.write( ' node [style=filled fontsize=%d];\n' - % self.fontsize ) - self.write( '\n' ) - - def write(self, text): - """ Write text to the dot file """ - self._dot.write(text.encode('utf8', 'xmlcharrefreplace')) - - def open(self, filename): - """ Implement BaseDoc.open() """ - self._filename = os.path.normpath(os.path.abspath(filename)) - - def close(self): - """ - This isn't useful by itself. Other classes need to override this and - actually generate a file. - """ - if self.note: - # build up the label - label = u'' - for line in self.note: # for every line in the note... - line = line.strip() # ...strip whitespace from this line... - if line != '': # ...and if we still have a line... - if label != '': # ...see if we need to insert a newline... - label += '\\n' - label += line.replace('"', '\\\"') - - # after all that, see if we have a label to display - if label != '': - self.write( - '\n' + - ' label="%s";\n' % label + - ' labelloc="%s";\n' % self.noteloc + - ' fontsize="%d";\n' % self.notesize - ) - - self.write( '}\n\n' ) - - def add_node(self, node_id, label, shape="", color="", - style="", fillcolor="", url="", htmloutput=False): - """ - Add a node to this graph. Nodes can be different shapes like boxes and - circles. - - Implements GVDoc.add_node(). - """ - text = '[' - - if shape: - text += ' shape="%s"' % shape - - if color: - text += ' color="%s"' % color - - if fillcolor: - text += ' fillcolor="%s"' % fillcolor - - if style: - text += ' style="%s"' % style - - # note that we always output a label -- even if an empty string -- - # otherwise GraphViz uses the node ID as the label which is unlikely - # to be what the user wants to see in the graph - if label.startswith("<") or htmloutput: - text += ' label=<%s>' % label - else: - text += ' label="%s"' % label - - if url: - text += ' URL="%s"' % url - - text += " ]" - self.write(' %s %s;\n' % (node_id, text)) - - def add_link(self, id1, id2, style="", head="", tail="", comment=""): - """ - Add a link between two nodes. - - Implements GVDoc.add_link(). - """ - self.write(' %s -> %s' % (id1, id2)) - - if style or head or tail: - self.write(' [') - - if style: - self.write(' style=%s' % style) - if head: - self.write(' arrowhead=%s' % head) - if tail: - self.write(' arrowtail=%s' % tail) - if head: - if tail: - self.write(' dir=both') - else: - self.write(' dir=forward') - else: - if tail: - self.write(' dir=back') - else: - self.write(' dir=none') - self.write(' ]') - - self.write(';') - - if comment: - self.write(' // %s' % comment) - - self.write('\n') - - def add_comment(self, comment): - """ - Add a comment. - - Implements GVDoc.add_comment(). - """ - tmp = comment.split('\n') - for line in tmp: - text = line.strip() - if text == "": - self.write('\n') - elif text.startswith('#'): - self.write('%s\n' % text) - else: - self.write('# %s\n' % text) - - def start_subgraph(self, graph_id): - """ Implement GVDoc.start_subgraph() """ - self.write( - ' subgraph cluster_%s\n' % graph_id + - ' {\n' + - ' style="invis";\n' # no border around subgraph (#0002176) - ) - - def end_subgraph(self): - """ Implement GVDoc.end_subgraph() """ - self.write(' }\n') - -#------------------------------------------------------------------------------- -# -# GVDotDoc -# -#------------------------------------------------------------------------------- -class GVDotDoc(GVDocBase): - """ GVDoc implementation that generates a .gv text file. """ - - def close(self): - """ Implements GVDocBase.close() """ - GVDocBase.close(self) - - # Make sure the extension is correct - if self._filename[-3:] != ".gv": - self._filename += ".gv" - - _run_long_process_in_thread(self.__generate, self._filename) - - def __generate(self): - """ - This function will generate the actual file. - It is nice to run this function in the background so that the - application does not appear to hang. - """ - dotfile = open(self._filename, "w") - dotfile.write(self._dot.getvalue()) - dotfile.close() - - if self.open_req: - open_file_with_default_application(self._filename) - -#------------------------------------------------------------------------------- -# -# GVPsDoc -# -#------------------------------------------------------------------------------- -class GVPsDoc(GVDocBase): - """ GVDoc implementation that generates a .ps file using Graphviz. """ - - def __init__(self, options, paper_style): - # DPI must always be 72 for PDF. - # GV documentation says dpi is only for image formats. - options.menu.get_option_by_name('dpi').set_value(72) - GVDocBase.__init__(self, options, paper_style) - # GV documentation allow multiple pages only for ps format, - # But it does not work with -Tps:cairo in order to - # show Non Latin-1 letters. Force to only 1 page. - # See bug tracker issue 2815 - options.menu.get_option_by_name('v_pages').set_value(1) - options.menu.get_option_by_name('h_pages').set_value(1) - GVDocBase.__init__(self, options, paper_style) - - def close(self): - """ Implements GVDocBase.close() """ - GVDocBase.close(self) - - # Make sure the extension is correct - if self._filename[-3:] != ".ps": - self._filename += ".ps" - - _run_long_process_in_thread(self.__generate, self._filename) - - def __generate(self): - """ - This function will generate the actual file. - It is nice to run this function in the background so that the - application does not appear to hang. - """ - # Create a temporary dot file - (handle, tmp_dot) = tempfile.mkstemp(".gv" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self._dot.getvalue()) - dotfile.close() - - # Generate the PS file. - # Reason for using -Tps:cairo. Needed for Non Latin-1 letters - # Some testing with Tps:cairo. Non Latin-1 letters are OK i all cases: - # Output format: ps PDF-GostScript PDF-GraphViz - # Single page OK OK OK - # Multip page 1 page, OK 1 page, - # corrupted set by gramps - # If I take a correct multip page PDF and convert it with pdf2ps I get multip pages, - # but the output is clipped, some margins have disappeared. I used 1 inch margins always. - # See bug tracker issue 2815 - # :cairo does not work with Graphviz 2.26.3 See issue 4164 - # Covert filename to str using file system encoding. - fname = self._filename.encode(sys.getfilesystemencoding()) - - command = 'dot -Tps:cairo -o"%s" "%s"' % (fname, tmp_dot) - dotversion = Popen(['dot', '-V'], stderr=PIPE).communicate(input=None)[1] - # Problem with dot 2.26.3 and multiple pages, which gives "cairo: out of memory" - # If the :cairo is skipped for these cases it gives acceptable result. - if dotversion.find('2.26.3') != -1 and (self.vpages * self.hpages) > 1: - command=command.replace(':cairo','') - os.system(command) - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.open_req: - open_file_with_default_application(self._filename) - -#------------------------------------------------------------------------------- -# -# GVSvgDoc -# -#------------------------------------------------------------------------------- -class GVSvgDoc(GVDocBase): - """ GVDoc implementation that generates a .svg file using Graphviz. """ - - def __init__(self, options, paper_style): - # GV documentation allow multiple pages only for ps format, - # which also includes pdf via ghostscript. - options.menu.get_option_by_name('v_pages').set_value(1) - options.menu.get_option_by_name('h_pages').set_value(1) - GVDocBase.__init__(self, options, paper_style) - - def close(self): - """ Implements GVDocBase.close() """ - GVDocBase.close(self) - - # Make sure the extension is correct - if self._filename[-4:] != ".svg": - self._filename += ".svg" - - _run_long_process_in_thread(self.__generate, self._filename) - - def __generate(self): - """ - This function will generate the actual file. - It is nice to run this function in the background so that the - application does not appear to hang. - """ - # Create a temporary dot file - (handle, tmp_dot) = tempfile.mkstemp(".gv" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self._dot.getvalue()) - dotfile.close() - # Covert filename to str using file system encoding. - fname = self._filename.encode(sys.getfilesystemencoding()) - - # Generate the SVG file. - os.system( 'dot -Tsvg -o"%s" "%s"' % (fname, tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.open_req: - open_file_with_default_application(self._filename) - -#------------------------------------------------------------------------------- -# -# GVSvgzDoc -# -#------------------------------------------------------------------------------- -class GVSvgzDoc(GVDocBase): - """ GVDoc implementation that generates a .svg file using Graphviz. """ - - def __init__(self, options, paper_style): - # GV documentation allow multiple pages only for ps format, - # which also includes pdf via ghostscript. - options.menu.get_option_by_name('v_pages').set_value(1) - options.menu.get_option_by_name('h_pages').set_value(1) - GVDocBase.__init__(self, options, paper_style) - - def close(self): - """ Implements GVDocBase.close() """ - GVDocBase.close(self) - - # Make sure the extension is correct - if self._filename[-5:] != ".svgz": - self._filename += ".svgz" - - _run_long_process_in_thread(self.__generate, self._filename) - - def __generate(self): - """ - This function will generate the actual file. - It is nice to run this function in the background so that the - application does not appear to hang. - """ - # Create a temporary dot file - (handle, tmp_dot) = tempfile.mkstemp(".gv" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self._dot.getvalue()) - dotfile.close() - # Covert filename to str using file system encoding. - fname = self._filename.encode(sys.getfilesystemencoding()) - - # Generate the SVGZ file. - os.system( 'dot -Tsvgz -o"%s" "%s"' % (fname, tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.open_req: - open_file_with_default_application(self._filename) - -#------------------------------------------------------------------------------- -# -# GVPngDoc -# -#------------------------------------------------------------------------------- -class GVPngDoc(GVDocBase): - """ GVDoc implementation that generates a .png file using Graphviz. """ - - def __init__(self, options, paper_style): - # GV documentation allow multiple pages only for ps format, - # which also includes pdf via ghostscript. - options.menu.get_option_by_name('v_pages').set_value(1) - options.menu.get_option_by_name('h_pages').set_value(1) - GVDocBase.__init__(self, options, paper_style) - - def close(self): - """ Implements GVDocBase.close() """ - GVDocBase.close(self) - - # Make sure the extension is correct - if self._filename[-4:] != ".png": - self._filename += ".png" - - _run_long_process_in_thread(self.__generate, self._filename) - - def __generate(self): - """ - This function will generate the actual file. - It is nice to run this function in the background so that the - application does not appear to hang. - """ - # Create a temporary dot file - (handle, tmp_dot) = tempfile.mkstemp(".gv" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self._dot.getvalue()) - dotfile.close() - # Covert filename to str using file system encoding. - fname = self._filename.encode(sys.getfilesystemencoding()) - - # Generate the PNG file. - os.system( 'dot -Tpng -o"%s" "%s"' % (fname, tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.open_req: - open_file_with_default_application(self._filename) - -#------------------------------------------------------------------------------- -# -# GVJpegDoc -# -#------------------------------------------------------------------------------- -class GVJpegDoc(GVDocBase): - """ GVDoc implementation that generates a .jpg file using Graphviz. """ - - def __init__(self, options, paper_style): - # GV documentation allow multiple pages only for ps format, - # which also includes pdf via ghostscript. - options.menu.get_option_by_name('v_pages').set_value(1) - options.menu.get_option_by_name('h_pages').set_value(1) - GVDocBase.__init__(self, options, paper_style) - - def close(self): - """ Implements GVDocBase.close() """ - GVDocBase.close(self) - - # Make sure the extension is correct - if self._filename[-4:] != ".jpg": - self._filename += ".jpg" - - _run_long_process_in_thread(self.__generate, self._filename) - - def __generate(self): - """ - This function will generate the actual file. - It is nice to run this function in the background so that the - application does not appear to hang. - """ - # Create a temporary dot file - (handle, tmp_dot) = tempfile.mkstemp(".gv" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self._dot.getvalue()) - dotfile.close() - # Covert filename to str using file system encoding. - fname = self._filename.encode(sys.getfilesystemencoding()) - - # Generate the JPEG file. - os.system( 'dot -Tjpg -o"%s" "%s"' % (fname, tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.open_req: - open_file_with_default_application(self._filename) - -#------------------------------------------------------------------------------- -# -# GVGifDoc -# -#------------------------------------------------------------------------------- -class GVGifDoc(GVDocBase): - """ GVDoc implementation that generates a .gif file using Graphviz. """ - - def __init__(self, options, paper_style): - # GV documentation allow multiple pages only for ps format, - # which also includes pdf via ghostscript. - options.menu.get_option_by_name('v_pages').set_value(1) - options.menu.get_option_by_name('h_pages').set_value(1) - GVDocBase.__init__(self, options, paper_style) - - def close(self): - """ Implements GVDocBase.close() """ - GVDocBase.close(self) - - # Make sure the extension is correct - if self._filename[-4:] != ".gif": - self._filename += ".gif" - - _run_long_process_in_thread(self.__generate, self._filename) - - def __generate(self): - """ - This function will generate the actual file. - It is nice to run this function in the background so that the - application does not appear to hang. - """ - # Create a temporary dot file - (handle, tmp_dot) = tempfile.mkstemp(".gv" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self._dot.getvalue()) - dotfile.close() - # Covert filename to str using file system encoding. - fname = self._filename.encode(sys.getfilesystemencoding()) - - # Generate the GIF file. - os.system( 'dot -Tgif -o"%s" "%s"' % (fname, tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.open_req: - open_file_with_default_application(self._filename) - -#------------------------------------------------------------------------------- -# -# GVPdfGvDoc -# -#------------------------------------------------------------------------------- -class GVPdfGvDoc(GVDocBase): - """ GVDoc implementation that generates a .pdf file using Graphviz. """ - - def __init__(self, options, paper_style): - # DPI must always be 72 for PDF. - # GV documentation says dpi is only for image formats. - options.menu.get_option_by_name('dpi').set_value(72) - # GV documentation allow multiple pages only for ps format, - # which also includes pdf via ghostscript. - options.menu.get_option_by_name('v_pages').set_value(1) - options.menu.get_option_by_name('h_pages').set_value(1) - GVDocBase.__init__(self, options, paper_style) - - def close(self): - """ Implements GVDocBase.close() """ - GVDocBase.close(self) - - # Make sure the extension is correct - if self._filename[-4:] != ".pdf": - self._filename += ".pdf" - - _run_long_process_in_thread(self.__generate, self._filename) - - def __generate(self): - """ - This function will generate the actual file. - It is nice to run this function in the background so that the - application does not appear to hang. - """ - # Create a temporary dot file - (handle, tmp_dot) = tempfile.mkstemp(".gv" ) - dotfile = os.fdopen(handle,"w") - dotfile.write(self._dot.getvalue()) - dotfile.close() - # Covert filename to str using file system encoding. - fname = self._filename.encode(sys.getfilesystemencoding()) - - # Generate the PDF file. - os.system( 'dot -Tpdf -o"%s" "%s"' % (fname, tmp_dot) ) - - # Delete the temporary dot file - os.remove(tmp_dot) - - if self.open_req: - open_file_with_default_application(self._filename) - -#------------------------------------------------------------------------------- -# -# GVPdfGsDoc -# -#------------------------------------------------------------------------------- -class GVPdfGsDoc(GVDocBase): - """ GVDoc implementation that generates a .pdf file using Ghostscript. """ - def __init__(self, options, paper_style): - # DPI must always be 72 for PDF. - # GV documentation says dpi is only for image formats. - options.menu.get_option_by_name('dpi').set_value(72) - GVDocBase.__init__(self, options, paper_style) - - def close(self): - """ Implements GVDocBase.close() """ - GVDocBase.close(self) - - # Make sure the extension is correct - if self._filename[-4:] != ".pdf": - self._filename += ".pdf" - - _run_long_process_in_thread(self.__generate, self._filename) - - def __generate(self): - """ - This function will generate the actual file. - It is nice to run this function in the background so that the - application does not appear to hang. - """ - # Create a temporary dot file - (handle, tmp_dot) = tempfile.mkstemp(".gv" ) - 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 - # Reason for using -Tps:cairo. Needed for Non Latin-1 letters - # See bug tracker issue 2815 - # :cairo does not work with Graphviz 2.26.3 See issue 4164 - - command = 'dot -Tps:cairo -o"%s" "%s"' % ( tmp_ps, tmp_dot ) - dotversion = Popen(['dot', '-V'], stderr=PIPE).communicate(input=None)[1] - # Problem with dot 2.26.3 and multiple pages, which gives "cairo: out of memory" - # If the :cairo is skipped for these cases it gives acceptable result. - if dotversion.find('2.26.3') != -1 and (self.vpages * self.hpages) > 1: - command=command.replace(':cairo','') - 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 - fname = self._filename.encode(sys.getfilesystemencoding()) - command = '%s -q -sDEVICE=pdfwrite -dNOPAUSE -dDEVICEWIDTHPOINTS=%d' \ - ' -dDEVICEHEIGHTPOINTS=%d -sOutputFile="%s" "%s" -c quit' \ - % ( _GS_CMD, width_pt, height_pt, fname, tmp_ps ) - os.system(command) - - os.remove(tmp_ps) - os.remove(tmp_dot) - - if self.open_req: - open_file_with_default_application(self._filename) - -#------------------------------------------------------------------------------- -# -# Various Graphviz formats. -# -#------------------------------------------------------------------------------- -_FORMATS = [] - -if _DOT_FOUND: - - if _GS_CMD != "": - _FORMATS += [{ 'type' : "gspdf", - 'ext' : "pdf", - 'descr': _("PDF (Ghostscript)"), - 'mime' : "application/pdf", - 'class': GVPdfGsDoc }] - - _FORMATS += [{ 'type' : "gvpdf", - 'ext' : "pdf", - 'descr': _("PDF (Graphviz)"), - 'mime' : "application/pdf", - 'class': GVPdfGvDoc }] - - _FORMATS += [{ 'type' : "ps", - 'ext' : "ps", - 'descr': _("PostScript"), - 'mime' : "application/postscript", - 'class': GVPsDoc }] - - _FORMATS += [{ 'type' : "svg", - 'ext' : "svg", - 'descr': _("Structured Vector Graphics (SVG)"), - 'mime' : "image/svg", - 'class': GVSvgDoc }] - - _FORMATS += [{ 'type' : "svgz", - 'ext' : "svgz", - 'descr': _("Compressed Structured Vector Graphs (SVGZ)"), - 'mime' : "image/svgz", - 'class': GVSvgzDoc }] - - _FORMATS += [{ 'type' : "jpg", - 'ext' : "jpg", - 'descr': _("JPEG image"), - 'mime' : "image/jpeg", - 'class': GVJpegDoc }] - - _FORMATS += [{ 'type' : "gif", - 'ext' : "gif", - 'descr': _("GIF image"), - 'mime' : "image/gif", - 'class': GVGifDoc }] - - _FORMATS += [{ 'type' : "png", - 'ext' : "png", - 'descr': _("PNG image"), - 'mime' : "image/png", - 'class': GVPngDoc }] - -_FORMATS += [{ 'type' : "dot", - 'ext' : "gv", - 'descr': _("Graphviz File"), - 'mime' : "text/x-graphviz", - 'class': GVDotDoc }] +import gen.plug.docgen.graphdoc as graphdoc +import gen.plug #------------------------------------------------------------------------------- # @@ -915,7 +70,7 @@ class GraphvizFormatComboBox(gtk.ComboBox): index = 0 active_index = 0 - for item in _FORMATS: + for item in graphdoc.FORMATS: name = item["descr"] self.store.append(row=[name]) if item['type'] == active: @@ -924,10 +79,10 @@ class GraphvizFormatComboBox(gtk.ComboBox): self.set_active(active_index) def get_label(self): - return _FORMATS[self.get_active()]["descr"] + return graphdoc.FORMATS[self.get_active()]["descr"] def get_reference(self): - return _FORMATS[self.get_active()]["class"] + return graphdoc.FORMATS[self.get_active()]["class"] def get_paper(self): return 1 @@ -936,16 +91,16 @@ class GraphvizFormatComboBox(gtk.ComboBox): return 0 def get_ext(self): - return '.%s' % _FORMATS[self.get_active()]['ext'] + return '.%s' % graphdoc.FORMATS[self.get_active()]['ext'] def get_format_str(self): - return _FORMATS[self.get_active()]["type"] + return graphdoc.FORMATS[self.get_active()]["type"] def is_file_output(self): return True def get_clname(self): - return _FORMATS[self.get_active()]["type"] + return graphdoc.FORMATS[self.get_active()]["type"] #----------------------------------------------------------------------- # @@ -959,161 +114,29 @@ class GraphvizReportDialog(ReportDialog): for a graphviz report. See the ReportDialog class for more information.""" self.category = CATEGORY_GRAPHVIZ + self.__gvoptions = graphdoc.GVOptions() ReportDialog.__init__(self, dbstate, uistate, opt, name, translated_name) def init_options(self, option_class): try: if (issubclass(option_class, object) or # New-style class - isinstance(options_class, ClassType)): # Old-style class + isinstance(option_class, ClassType)): # Old-style class self.options = option_class(self.raw_name, self.dbstate.get_database()) except TypeError: - self.options = option_class - - ################################ - category = _("GraphViz Layout") - ################################ - font_family = EnumeratedListOption(_("Font family"), "") - index = 0 - for item in _FONTS: - font_family.add_item(item["value"], item["name"]) - index += 1 - font_family.set_help(_("Choose the font family. If international " - "characters don't show, use FreeSans font. " - "FreeSans is available from: " - "http://www.nongnu.org/freefont/")) - self.options.add_menu_option(category, "font_family", font_family) - - font_size = NumberOption(_("Font size"), 14, 8, 128) - font_size.set_help(_("The font size, in points.")) - self.options.add_menu_option(category, "font_size", font_size) + self.options = option_class + + menu = gen.plug.menu.Menu() + self.__gvoptions.add_menu_options(menu) - rank_dir = EnumeratedListOption(_("Graph Direction"), "TB") - index = 0 - for item in _RANKDIR: - rank_dir.add_item(item["value"], item["name"]) - index += 1 - rank_dir.set_help(_("Whether graph goes from top to bottom " - "or left to right.")) - self.options.add_menu_option(category, "rank_dir", rank_dir) - - h_pages = NumberOption(_("Number of Horizontal Pages"), 1, 1, 25) - h_pages.set_help(_("GraphViz can create very large graphs by " - "spreading the graph across a rectangular " - "array of pages. This controls the number " - "pages in the array horizontally. " - "Only valid for dot and pdf via Ghostscript.")) - self.options.add_menu_option(category, "h_pages", h_pages) + for category in menu.get_categories(): + for name in menu.get_option_names(category): + option = menu.get_option(category, name) + self.options.add_menu_option(category, name, option) - v_pages = NumberOption(_("Number of Vertical Pages"), 1, 1, 25) - v_pages.set_help(_("GraphViz can create very large graphs by " - "spreading the graph across a rectangular " - "array of pages. This controls the number " - "pages in the array vertically. " - "Only valid for dot and pdf via Ghostscript.")) - self.options.add_menu_option(category, "v_pages", v_pages) - - page_dir = EnumeratedListOption(_("Paging Direction"), "BL") - index = 0 - for item in _PAGEDIR: - page_dir.add_item(item["value"], item["name"]) - index += 1 - page_dir.set_help(_("The order in which the graph pages are output. " - "This option only applies if the horizontal pages " - "or vertical pages are greater than 1.")) - self.options.add_menu_option(category, "page_dir", page_dir) - - # the page direction option only makes sense when the - # number of horizontal and/or vertical pages is > 1, - # so we need to remember these 3 controls for later - self.h_pages = h_pages - self.v_pages = v_pages - self.page_dir = page_dir - - # the page direction option only makes sense when the - # number of horizontal and/or vertical pages is > 1 - self.h_pages.connect('value-changed', self.pages_changed) - self.v_pages.connect('value-changed', self.pages_changed) - - ################################ - category = _("GraphViz Options") - ################################ - - aspect_ratio = EnumeratedListOption(_("Aspect ratio"), "fill") - index = 0 - for item in _RATIO: - aspect_ratio.add_item(item["value"], item["name"]) - index += 1 - aspect_ratio.set_help(_("Affects greatly how the graph is layed out " - "on the page.")) - self.options.add_menu_option(category, "ratio", aspect_ratio) - - dpi = NumberOption(_("DPI"), 75, 20, 1200) - dpi.set_help(_( "Dots per inch. When creating images such as " - ".gif or .png files for the web, try numbers " - "such as 100 or 300 DPI. When creating PostScript " - "or PDF files, use 72 DPI.")) - self.options.add_menu_option(category, "dpi", dpi) - - nodesep = NumberOption(_("Node spacing"), 0.20, 0.01, 5.00, 0.01) - nodesep.set_help(_( "The minimum amount of free space, in inches, " - "between individual nodes. For vertical graphs, " - "this corresponds to spacing between columns. " - "For horizontal graphs, this corresponds to " - "spacing between rows.")) - self.options.add_menu_option(category, "nodesep", nodesep) - - ranksep = NumberOption(_("Rank spacing"), 0.20, 0.01, 5.00, 0.01) - ranksep.set_help(_( "The minimum amount of free space, in inches, " - "between ranks. For vertical graphs, this " - "corresponds to spacing between rows. For " - "horizontal graphs, this corresponds to spacing " - "between columns.")) - self.options.add_menu_option(category, "ranksep", ranksep) - - use_subgraphs = BooleanOption(_('Use subgraphs'), True) - use_subgraphs.set_help(_("Subgraphs can help GraphViz position " - "spouses together, but with non-trivial " - "graphs will result in longer lines and " - "larger graphs.")) - self.options.add_menu_option(category, "usesubgraphs", use_subgraphs) - - ################################ - category = _("Note") - ################################ - - note = TextOption(_("Note to add to the graph"), - [""] ) - note.set_help(_("This text will be added to the graph.")) - self.options.add_menu_option(category, "note", note) - - noteloc = EnumeratedListOption(_("Note location"), 't') - for i in range( 0, len(_NOTELOC) ): - noteloc.add_item(_NOTELOC[i]["value"], _NOTELOC[i]["name"]) - noteloc.set_help(_("Whether note will appear on top " - "or bottom of the page.")) - self.options.add_menu_option(category, "noteloc", noteloc) - - notesize = NumberOption(_("Note size"), 32, 8, 128) - notesize.set_help(_("The size of note text, in points.")) - self.options.add_menu_option(category, "notesize", notesize) - self.options.load_previous_values() - def pages_changed(self): - """ - This method gets called every time the v_pages or h_pages - options are changed; when both vertical and horizontal - pages are set to "1", then the page_dir control needs to - be unavailable - """ - if self.v_pages.get_value() > 1 or \ - self.h_pages.get_value() > 1: - self.page_dir.set_available(True) - else: - self.page_dir.set_available(False) - def init_interface(self): ReportDialog.init_interface(self) self.doc_type_changed(self.format_menu) @@ -1191,9 +214,6 @@ class GraphvizReportDialog(ReportDialog): self.doc = self.format(self.options, pstyle) self.options.set_document(self.doc) - - if self.open_with_app.get_active(): - self.doc.open_requested() def on_ok_clicked(self, obj): """The user is satisfied with the dialog choices. Validate diff --git a/src/gui/plug/report/_reportdialog.py b/src/gui/plug/report/_reportdialog.py index e3bc0dca1..73f854049 100644 --- a/src/gui/plug/report/_reportdialog.py +++ b/src/gui/plug/report/_reportdialog.py @@ -29,7 +29,8 @@ #------------------------------------------------------------------------- import os from types import ClassType -from gen.ggettext import gettext as _ +import threading +import time import logging LOG = logging.getLogger(".") @@ -46,8 +47,10 @@ import gtk # GRAMPS modules # #------------------------------------------------------------------------- +from gen.ggettext import gettext as _ import config import Errors +from gui.utils import ProgressMeter, open_file_with_default_application from QuestionDialog import ErrorDialog, OptionDialog from gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK, CATEGORY_CODE, CATEGORY_WEB, CATEGORY_GRAPHVIZ, @@ -66,6 +69,43 @@ import Utils #------------------------------------------------------------------------- URL_REPORT_PAGE = URL_MANUAL_PAGE + "_-_Reports" +#------------------------------------------------------------------------------- +# +# Private Functions +# +#------------------------------------------------------------------------------- +def _run_long_process_in_thread(func, header): + """ + This function will spawn a new thread to execute the provided function. + While the function is running, a progress bar will be created. + The progress bar will show activity while the function executes. + + @param func: A function that will take an unknown amount of time to + complete. + @type category: callable + @param header: A header for the progress bar. + Example: "Updating Data" + @type name: string + @return: nothing + + """ + pbar = ProgressMeter(_('Processing File')) + pbar.set_pass(total=40, + mode=ProgressMeter.MODE_ACTIVITY, + header=header) + + sys_thread = threading.Thread(target=func) + sys_thread.start() + + while sys_thread.isAlive(): + # The loop runs 20 times per second until the thread completes. + # With the progress pass total set at 40, it should move across the bar + # every two seconds. + time.sleep(0.05) + pbar.step() + + pbar.close() + #------------------------------------------------------------------------- # # ReportDialog class @@ -644,10 +684,18 @@ def report(dbstate, uistate, person, report_class, options_class, dialog.close() try: MyReport = report_class(dialog.db, dialog.options) - MyReport.doc.init() - MyReport.begin_report() - MyReport.write_report() - MyReport.end_report() + + def do_report(): + MyReport.doc.init() + MyReport.begin_report() + MyReport.write_report() + MyReport.end_report() + + _run_long_process_in_thread(do_report, dialog.raw_name) + + if dialog.open_with_app.get_active(): + open_file_with_default_application(dialog.options.get_output()) + except Errors.FilterError, msg: (m1, m2) = msg.messages() ErrorDialog(m1, m2) diff --git a/src/plugins/BookReport.py b/src/plugins/BookReport.py index 72a53bef9..e9484e5d1 100644 --- a/src/plugins/BookReport.py +++ b/src/plugins/BookReport.py @@ -76,6 +76,7 @@ from QuestionDialog import WarningDialog, ErrorDialog from gen.plug.menu import PersonOption, FilterOption, FamilyOption import ManagedWindow from glade import Glade +from gui.utils import open_file_with_default_application # Import from specific modules in ReportBase from gen.plug.report import CATEGORY_BOOK, book_categories @@ -1200,9 +1201,6 @@ class BookReportDialog(DocReportDialog): report_class, item.option_class) self.rptlist.append(obj) self.doc.open(self.target_path) - - if self.open_with_app.get_active(): - self.doc.open_requested() def make_report(self): """The actual book report. Start it out, then go through the item list @@ -1217,6 +1215,9 @@ class BookReportDialog(DocReportDialog): item.begin_report() item.write_report() self.doc.close() + + if self.open_with_app.get_active(): + open_file_with_default_application(self.target_path) #------------------------------------------------------------------------ # diff --git a/src/plugins/docgen/AsciiDoc.py b/src/plugins/docgen/AsciiDoc.py index 4f3879534..f6c30c646 100644 --- a/src/plugins/docgen/AsciiDoc.py +++ b/src/plugins/docgen/AsciiDoc.py @@ -35,11 +35,9 @@ from gen.ggettext import gettext as _ # Gramps modules # #------------------------------------------------------------------------ -from gui.utils import open_file_with_default_application from gen.plug.docgen import (BaseDoc, TextDoc, PARA_ALIGN_RIGHT, PARA_ALIGN_CENTER) import Errors -import Utils #------------------------------------------------------------------------ # @@ -165,9 +163,6 @@ class AsciiDoc(BaseDoc,TextDoc): def close(self): self.f.close() - if self.open_req: - open_file_with_default_application(self.filename) - def get_usable_width(self): return _WIDTH_IN_CHARS diff --git a/src/plugins/docgen/HtmlDoc.py b/src/plugins/docgen/HtmlDoc.py index cbf95beb3..3135ce0ad 100644 --- a/src/plugins/docgen/HtmlDoc.py +++ b/src/plugins/docgen/HtmlDoc.py @@ -45,7 +45,6 @@ from gen.ggettext import gettext as _ # GRAMPS modules # #------------------------------------------------------------------------ -from gui.utils import open_file_with_default_application import ImgManip import const from gen.plug.docgen import BaseDoc, TextDoc, FONT_SANS_SERIF @@ -239,10 +238,6 @@ class HtmlDoc(BaseDoc, TextDoc): self._backend.close() self.write_support_files() - if self.open_req: - import Utils - open_file_with_default_application(self._backend.getf()) - def copy_file(self, from_fname, to_fname, to_dir=''): """ Copy a file from a source to a (report) destination. diff --git a/src/plugins/docgen/LaTeXDoc.py b/src/plugins/docgen/LaTeXDoc.py index 4bb9c7fbc..3fdc0f2c4 100644 --- a/src/plugins/docgen/LaTeXDoc.py +++ b/src/plugins/docgen/LaTeXDoc.py @@ -41,7 +41,6 @@ from bisect import bisect # gramps modules # #------------------------------------------------------------------------ -from gui.utils import open_file_with_default_application from gen.plug.docgen import BaseDoc, TextDoc, PAPER_LANDSCAPE, FONT_SANS_SERIF from gen.plug.docbackend import DocBackend import ImgManip @@ -404,8 +403,6 @@ class LaTeXDoc(BaseDoc, TextDoc): self._backend.write('\\end{enumerate}\n') self._backend.write('\n\\end{document}\n') self._backend.close() - if self.open_req: - open_file_with_default_application(self._backend.filename) def end_page(self): """Issue a new page command""" diff --git a/src/plugins/docgen/ODFDoc.py b/src/plugins/docgen/ODFDoc.py index 90aa7ee3e..91ee81e4d 100644 --- a/src/plugins/docgen/ODFDoc.py +++ b/src/plugins/docgen/ODFDoc.py @@ -78,7 +78,6 @@ from xml.sax.saxutils import escape # Gramps modules # #------------------------------------------------------------------------- -from gui.utils import open_file_with_default_application from gen.plug.docgen import (BaseDoc, TextDoc, DrawDoc, graphicstyle, FONT_SANS_SERIF, SOLID, PAPER_PORTRAIT, INDEX_TYPE_TOC, PARA_ALIGN_CENTER, PARA_ALIGN_LEFT, @@ -809,8 +808,6 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc): self._write_meta_file() self._write_mimetype_file() self._write_zip() - if self.open_req: - open_file_with_default_application(self.filename) def add_styled_notes_fonts(self): """ diff --git a/src/plugins/docgen/PSDrawDoc.py b/src/plugins/docgen/PSDrawDoc.py index d1d09fe80..0c35b6e03 100644 --- a/src/plugins/docgen/PSDrawDoc.py +++ b/src/plugins/docgen/PSDrawDoc.py @@ -36,7 +36,6 @@ from gen.ggettext import gettext as _ #------------------------------------------------------------------------- #Gramps modules #------------------------------------------------------------------------- -from gui.utils import open_file_with_default_application from gen.plug.report import utils as ReportUtils from gen.plug.docgen import BaseDoc, DrawDoc, FONT_SERIF, PAPER_PORTRAIT, SOLID from gen.plug.utils import gformat @@ -147,8 +146,6 @@ class PSDrawDoc(BaseDoc, DrawDoc): '%%EOF\n' ) self.file.close() - if self.open_req: - open_file_with_default_application(self.filename) def write_text(self, text, mark=None): pass diff --git a/src/plugins/docgen/PdfDoc.py b/src/plugins/docgen/PdfDoc.py index 7e63d4801..ffb4ce054 100644 --- a/src/plugins/docgen/PdfDoc.py +++ b/src/plugins/docgen/PdfDoc.py @@ -37,7 +37,6 @@ import sys # Gramps modules # #------------------------------------------------------------------------ -from gui.utils import open_file_with_default_application import libcairodoc #------------------------------------------------------------------------ @@ -124,6 +123,3 @@ class PdfDoc(libcairodoc.CairoDoc): # if we don't restore the resolution. fontmap.set_resolution(saved_resolution) - # load the result into an external viewer - if self.open_req: - open_file_with_default_application(self._backend.filename) diff --git a/src/plugins/docgen/RTFDoc.py b/src/plugins/docgen/RTFDoc.py index 9ef91f443..381016ef0 100644 --- a/src/plugins/docgen/RTFDoc.py +++ b/src/plugins/docgen/RTFDoc.py @@ -35,7 +35,6 @@ from gen.ggettext import gettext as _ # Load the base BaseDoc class # #------------------------------------------------------------------------ -from gui.utils import open_file_with_default_application from gen.plug.docgen import (BaseDoc, TextDoc, FONT_SERIF, PARA_ALIGN_RIGHT, PARA_ALIGN_CENTER, PARA_ALIGN_JUSTIFY) import ImgManip @@ -134,9 +133,6 @@ class RTFDoc(BaseDoc,TextDoc): self.f.write('}\n') self.f.close() - if self.open_req: - open_file_with_default_application(self.filename) - #-------------------------------------------------------------------- # # Force a section page break