|
63 | 63 | import gramps.gen.datehandler |
64 | 64 | from gramps.gen.display.place import displayer as place_displayer |
65 | 65 | from gramps.gen.constfunc import win |
| 66 | +from gramps.gen.config import config |
| 67 | +from gramps.gui.dialog import OptionDialog |
66 | 68 |
|
67 | 69 | if win(): |
68 | 70 | DETACHED_PROCESS = 8 |
@@ -132,10 +134,23 @@ def __init__(self, pdata, dbstate, uistate, nav_group=0): |
132 | 134 | 'interface.graphview-ancestor-generations') |
133 | 135 |
|
134 | 136 | self.dbstate = dbstate |
| 137 | + self.uistate = uistate |
135 | 138 | self.graph_widget = None |
136 | 139 | self.dbstate.connect('database-changed', self.change_db) |
137 | 140 |
|
138 | 141 | self.additional_uis.append(self.additional_ui()) |
| 142 | + self.define_print_actions() |
| 143 | + |
| 144 | + def define_print_actions(self): |
| 145 | + """ |
| 146 | + Associate the print button to the PrintView action. |
| 147 | + """ |
| 148 | + self._add_action('PrintView', 'document-print', _("_Print..."), |
| 149 | + accel="<PRIMARY>P", |
| 150 | + tip=_("Save the dot file for a later print.\n" |
| 151 | + "This will save a .gv file and a svg file.\n" |
| 152 | + "You must select a .gv file"), |
| 153 | + callback=self.printview) |
139 | 154 |
|
140 | 155 | def _connect_db_signals(self): |
141 | 156 | """ |
@@ -198,13 +213,21 @@ def additional_ui(self): |
198 | 213 | <separator/> |
199 | 214 | </placeholder> |
200 | 215 | </menu> |
| 216 | + <menu action="EditMenu"> |
| 217 | + <placeholder name="CommonEdit"> |
| 218 | + <menuitem action="PrintView"/> |
| 219 | + </placeholder> |
| 220 | + </menu> |
201 | 221 | </menubar> |
202 | 222 | <toolbar name="ToolBar"> |
203 | 223 | <placeholder name="CommonNavigation"> |
204 | 224 | <toolitem action="Back"/> |
205 | 225 | <toolitem action="Forward"/> |
206 | 226 | <toolitem action="HomePerson"/> |
207 | 227 | </placeholder> |
| 228 | + <placeholder name="CommonEdit"> |
| 229 | + <toolitem action="PrintView"/> |
| 230 | + </placeholder> |
208 | 231 | </toolbar> |
209 | 232 | </ui>''' |
210 | 233 |
|
@@ -368,6 +391,51 @@ def color_config_panel(self, configdialog): |
368 | 391 |
|
369 | 392 | return _('Colors'), grid |
370 | 393 |
|
| 394 | + #------------------------------------------------------------------------- |
| 395 | + # |
| 396 | + # Printing functionalities |
| 397 | + # |
| 398 | + #------------------------------------------------------------------------- |
| 399 | + def printview(self, obj): |
| 400 | + """ |
| 401 | + Save the dot file for a later printing with an appropriate tool. |
| 402 | + """ |
| 403 | + # Ask for the dot file name |
| 404 | + filter = Gtk.FileFilter() |
| 405 | + filter.add_pattern("*.gv") |
| 406 | + dot = Gtk.FileChooserDialog( |
| 407 | + _("Select a dot file name"), |
| 408 | + action=Gtk.FileChooserAction.OPEN, |
| 409 | + buttons=(_('_Cancel'), Gtk.ResponseType.CANCEL, |
| 410 | + _('_Apply'), Gtk.ResponseType.OK)) |
| 411 | + mpath = config.get('paths.report-directory') |
| 412 | + dot.set_current_folder(os.path.dirname(mpath)) |
| 413 | + dot.set_filter(filter) |
| 414 | + |
| 415 | + status = dot.run() |
| 416 | + if status == Gtk.ResponseType.OK: |
| 417 | + val = dot.get_filename() |
| 418 | + # selected path is an existing file and we need a file |
| 419 | + if os.path.isfile(val): |
| 420 | + aaa = OptionDialog(_('File already exists'), # parent-OK |
| 421 | + _('You can choose to either overwrite the ' |
| 422 | + 'file, or change the selected filename.'), |
| 423 | + _('_Overwrite'), None, |
| 424 | + _('_Change filename'), None, |
| 425 | + parent=self.uistate.window) |
| 426 | + |
| 427 | + if aaa.get_response() == Gtk.ResponseType.YES: |
| 428 | + dot.destroy() |
| 429 | + self.printview(obj) |
| 430 | + return |
| 431 | + svg = val.replace('.gv', '.svg') |
| 432 | + if val: |
| 433 | + with open(val,'w') as g,\ |
| 434 | + open(svg,'w') as s: |
| 435 | + g.write(self.graph_widget.dot_data.decode('utf-8')) |
| 436 | + s.write(self.graph_widget.svg_data.decode('utf-8')) |
| 437 | + dot.destroy() |
| 438 | + |
371 | 439 | #------------------------------------------------------------------------- |
372 | 440 | # |
373 | 441 | # GraphWidget |
@@ -420,18 +488,18 @@ def populate(self, active_person): |
420 | 488 | dot.build_graph(active_person) |
421 | 489 |
|
422 | 490 | # Build the rest of the widget by parsing SVG data from Graphviz |
423 | | - dot_data = dot.get_dot().encode('utf8') |
| 491 | + self.dot_data = dot.get_dot().encode('utf8') |
424 | 492 | if win(): |
425 | | - svg_data = Popen(['dot', '-Tsvg'], |
| 493 | + self.svg_data = Popen(['dot', '-Tsvg'], |
426 | 494 | creationflags=DETACHED_PROCESS, |
427 | 495 | stdin=PIPE, |
428 | 496 | stdout=PIPE, |
429 | | - stderr=PIPE).communicate(input=dot_data)[0] |
| 497 | + stderr=PIPE).communicate(input=self.dot_data)[0] |
430 | 498 | else: |
431 | | - svg_data = Popen(['dot', '-Tsvg'], |
432 | | - stdin=PIPE, stdout=PIPE).communicate(input=dot_data)[0] |
| 499 | + self.svg_data = Popen(['dot', '-Tsvg'], |
| 500 | + stdin=PIPE, stdout=PIPE).communicate(input=self.dot_data)[0] |
433 | 501 | parser = GraphvizSvgParser(self, self.view) |
434 | | - parser.parse(svg_data) |
| 502 | + parser.parse(self.svg_data) |
435 | 503 | window = self.canvas.get_parent() |
436 | 504 |
|
437 | 505 | # The scroll_to method will try and put the active person in the top |
|
0 commit comments