add_comment() and work in progress for the new GraphViz framework
svn: r9679
This commit is contained in:
		
							
								
								
									
										10
									
								
								ChangeLog
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								ChangeLog
									
									
									
									
									
								
							| @@ -1,3 +1,13 @@ | ||||
| 2008-01-02  Stéphane Charette <stephanecharette@gmail.com> | ||||
| 	* src/BaseDoc.py: definition of add_comment() | ||||
| 	* src/ReportBase/_GraphvizReportDialog.py: implement add_comment() | ||||
| 	* src/plugins/GVFamilyLines.py: | ||||
| 	* src/PluginUtils/__init__.py: | ||||
| 	* src/PluginUtils/_MenuOptions.py: work in progress to migrate the | ||||
| 	FamilyLines plugin to the new GraphViz framework; new menu option | ||||
| 	widget called "SurnameColourOption" (which is actually quite specific | ||||
| 	to the FamilyLines plugin) | ||||
|  | ||||
| 2008-01-01  Peter Landgren <peter.talken@telia.com> | ||||
|     * src/plugins/rel_sv.py: Added some comments | ||||
|  | ||||
|   | ||||
| @@ -1587,7 +1587,7 @@ class GVDoc: | ||||
|         @return: nothing | ||||
|         """ | ||||
|         raise NotImplementedError | ||||
|          | ||||
|  | ||||
|     def add_link(self, id1, id2, style="", head="", tail="", comment=""): | ||||
|         """ | ||||
|         Add a link between two nodes. | ||||
| @@ -1604,7 +1604,18 @@ class GVDoc: | ||||
|         @return: nothing | ||||
|         """ | ||||
|         raise NotImplementedError | ||||
|      | ||||
|  | ||||
|     def add_comment(self, comment): | ||||
|         """ | ||||
|         Add a comment to the source file. | ||||
|  | ||||
|         @param comment: A text string to add as a comment. | ||||
|             Example: "Next comes the individuals." | ||||
|         @type comment: string | ||||
|         @return: nothing | ||||
|         """ | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     def start_subgraph(self,id): | ||||
|         """ | ||||
|         Start a subgraph in this graph. | ||||
| @@ -1615,7 +1626,7 @@ class GVDoc: | ||||
|         @return: nothing | ||||
|         """ | ||||
|         raise NotImplementedError | ||||
|      | ||||
|  | ||||
|     def end_subgraph(self): | ||||
|         """ | ||||
|         End a subgraph that was previously started in this graph. | ||||
|   | ||||
| @@ -27,12 +27,103 @@ Abstracted option handling. | ||||
| # gramps modules | ||||
| # | ||||
| #------------------------------------------------------------------------- | ||||
| import gtk | ||||
| import gobject | ||||
| import Utils | ||||
| import _Tool as Tool | ||||
| import GrampsWidgets | ||||
| import ManagedWindow | ||||
| from Selectors import selector_factory | ||||
| from BasicUtils import name_displayer as _nd | ||||
|  | ||||
| #------------------------------------------------------------------------ | ||||
| # | ||||
| # Dialog window used to select a surname | ||||
| # | ||||
| #------------------------------------------------------------------------ | ||||
| class LastNameDialog(ManagedWindow.ManagedWindow): | ||||
|  | ||||
|     def __init__(self, database, uistate, track, surnames, skipList=set()): | ||||
|  | ||||
|         self.title = _('Select surname') | ||||
|         ManagedWindow.ManagedWindow.__init__(self, uistate, track, self) | ||||
|         self.dlg = gtk.Dialog( | ||||
|             None, | ||||
|             uistate.window, | ||||
|             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, | ||||
|             (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) | ||||
|         self.dlg.set_position(gtk.WIN_POS_CENTER_ON_PARENT) | ||||
|         self.set_window(self.dlg, None, self.title) | ||||
|         self.window.set_default_size(400,400) | ||||
|  | ||||
|         # build up a container to display all of the people of interest | ||||
|         self.model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT) | ||||
|         self.treeView = gtk.TreeView(self.model) | ||||
|         col1 = gtk.TreeViewColumn(_('Surname'), gtk.CellRendererText(), text=0) | ||||
|         col2 = gtk.TreeViewColumn(_('Count'), gtk.CellRendererText(), text=1) | ||||
|         col1.set_resizable(True) | ||||
|         col2.set_resizable(True) | ||||
|         col1.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) | ||||
|         col2.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) | ||||
|         col1.set_sort_column_id(0) | ||||
|         col2.set_sort_column_id(1) | ||||
|         self.treeView.append_column(col1) | ||||
|         self.treeView.append_column(col2) | ||||
|         self.scrolledWindow = gtk.ScrolledWindow() | ||||
|         self.scrolledWindow.add(self.treeView) | ||||
|         self.scrolledWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | ||||
|         self.scrolledWindow.set_shadow_type(gtk.SHADOW_OUT) | ||||
|         self.dlg.vbox.pack_start(self.scrolledWindow, expand=True, fill=True) | ||||
|         self.scrolledWindow.show_all() | ||||
|  | ||||
|         if len(surnames) == 0: | ||||
|             # we could use database.get_surname_list(), but if we do that | ||||
|             # all we get is a list of names without a count...therefore | ||||
|             # we'll traverse the entire database ourself and build up a | ||||
|             # list that we can use | ||||
| #            for name in database.get_surname_list(): | ||||
| #                self.model.append([name, 0]) | ||||
|  | ||||
|             # build up the list of surnames, keeping track of the count for each name | ||||
|             # (this can be a lengthy process, so by passing in the dictionary we can | ||||
|             # be certain we only do this once) | ||||
|             progress = Utils.ProgressMeter(_('Finding surnames')) | ||||
|             progress.set_pass(_('Finding surnames'), database.get_number_of_people()) | ||||
|             for personHandle in database.get_person_handles(False): | ||||
|                 progress.step() | ||||
|                 person = database.get_person_from_handle(personHandle) | ||||
|                 key = person.get_primary_name().get_surname() | ||||
|                 count = 0 | ||||
|                 if key in surnames: | ||||
|                     count = surnames[key] | ||||
|                 surnames[key] = count + 1 | ||||
|             progress.close() | ||||
|  | ||||
|         # insert the names and count into the model | ||||
|         for key in surnames: | ||||
|             if key.encode('iso-8859-1','xmlcharrefreplace') not in skipList: | ||||
|                 self.model.append([key, surnames[key]]) | ||||
|  | ||||
|         # keep the list sorted starting with the most popular last name | ||||
|         self.model.set_sort_column_id(1, gtk.SORT_DESCENDING) | ||||
|  | ||||
|         # the "OK" button should be enabled/disabled based on the selection of a row | ||||
|         self.treeSelection = self.treeView.get_selection() | ||||
|         self.treeSelection.set_mode(gtk.SELECTION_MULTIPLE) | ||||
|         self.treeSelection.select_path(0) | ||||
|  | ||||
|     def run(self): | ||||
|         response = self.dlg.run() | ||||
|         surnameSet = set() | ||||
|         if response == gtk.RESPONSE_ACCEPT: | ||||
|             (mode, paths) = self.treeSelection.get_selected_rows() | ||||
|             for path in paths: | ||||
|                 iter = self.model.get_iter(path) | ||||
|                 surname = self.model.get_value(iter, 0) | ||||
|                 surnameSet.add(surname) | ||||
|         self.dlg.destroy() | ||||
|         return surnameSet | ||||
|  | ||||
| #------------------------------------------------------------------------- | ||||
| # | ||||
| # Option class | ||||
| @@ -690,7 +781,7 @@ class PersonListOption(Option): | ||||
|         @type label: string | ||||
|         @param value: A set of GIDs as initial values for this option. | ||||
|             Example: "111 222 333 444" | ||||
|         @type value: set() | ||||
|         @type value: string | ||||
|         @return: nothing | ||||
|         """ | ||||
|         self.db = dbstate.get_database() | ||||
| @@ -775,6 +866,9 @@ class PersonListOption(Option): | ||||
|  | ||||
|             # if this person has a spouse, ask if we should include the spouse | ||||
|             # in the list of "people of interest" | ||||
|             # | ||||
|             # NOTE: we may want to make this an optional thing, determined | ||||
|             # by the use of a parameter at the time this class is instatiated | ||||
|             familyList = person.get_family_handle_list() | ||||
|             if familyList: | ||||
|                 for familyHandle in familyList: | ||||
| @@ -807,6 +901,131 @@ class PersonListOption(Option): | ||||
|             iter = self.model.get_iter(path) | ||||
|             self.model.remove(iter) | ||||
|  | ||||
| #------------------------------------------------------------------------- | ||||
| # | ||||
| # SurnameColourOption class | ||||
| # | ||||
| #------------------------------------------------------------------------- | ||||
| class SurnameColourOption(Option): | ||||
|     """ | ||||
|     This class describes a widget that allows multiple surnames to be | ||||
|     selected from the database, and to assign a colour (not necessarily | ||||
|     unique) to each one. | ||||
|     """ | ||||
|     def __init__(self, label, value, dbstate): | ||||
|         """ | ||||
|         @param label: A friendly label to be applied to this option. | ||||
|             Example: "Family lines" | ||||
|         @type label: string | ||||
|         @param value: A set of surnames and colours. | ||||
|             Example: "surname1 colour1 surname2 colour2" | ||||
|         @type value: string | ||||
|         @return: nothing | ||||
|         """ | ||||
|         self.db = dbstate.get_database() | ||||
|         self.dbstate = dbstate | ||||
|         Option.__init__(self,label,value) | ||||
|  | ||||
|     def make_gui_obj(self, gtk, dialog): | ||||
|         """ | ||||
|         Add a "surname-colour" widget to the dialog. | ||||
|         """ | ||||
|         self.dialog = dialog | ||||
|         self.surnames = {}  # list of surnames and count | ||||
|          | ||||
|         self.model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) | ||||
|         self.treeView = gtk.TreeView(self.model) | ||||
|         self.treeView.set_size_request(150, 150) | ||||
|         self.treeView.connect('row-activated', self.clicked) | ||||
|         col1 = gtk.TreeViewColumn(_('Surname'), gtk.CellRendererText(), text=0) | ||||
|         col2 = gtk.TreeViewColumn(_('Colour'), gtk.CellRendererText(), text=1) | ||||
|         col1.set_resizable(True) | ||||
|         col2.set_resizable(True) | ||||
|         col1.set_sort_column_id(0) | ||||
|         col1.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) | ||||
|         col2.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) | ||||
|         self.treeView.append_column(col1) | ||||
|         self.treeView.append_column(col2) | ||||
|         self.scrolledWindow = gtk.ScrolledWindow() | ||||
|         self.scrolledWindow.add(self.treeView) | ||||
|         self.scrolledWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | ||||
|         self.scrolledWindow.set_shadow_type(gtk.SHADOW_OUT) | ||||
|         self.hbox = gtk.HBox() | ||||
|         self.hbox.pack_start(self.scrolledWindow, expand=True, fill=True) | ||||
|  | ||||
|         self.addSurname = GrampsWidgets.SimpleButton(gtk.STOCK_ADD, self.addSurnameClicked) | ||||
|         self.delSurname = GrampsWidgets.SimpleButton(gtk.STOCK_REMOVE, self.delSurnameClicked) | ||||
|         self.vbbox = gtk.VButtonBox() | ||||
|         self.vbbox.add(self.addSurname) | ||||
|         self.vbbox.add(self.delSurname) | ||||
|         self.vbbox.set_layout(gtk.BUTTONBOX_SPREAD) | ||||
|         self.hbox.pack_end(self.vbbox, expand=False) | ||||
|  | ||||
|         # populate the surname/colour treeview | ||||
|         tmp = self.get_value().split() | ||||
|         while len(tmp) > 1: | ||||
|             surname = tmp.pop(0) | ||||
|             colour = tmp.pop(0) | ||||
|             self.model.append([surname, colour]) | ||||
|  | ||||
|         # parent expects the widget as "self.gobj" | ||||
|         self.gobj = self.hbox | ||||
|  | ||||
|     def parse(self): | ||||
|         """ | ||||
|         Parse the object and return. | ||||
|         """ | ||||
|         surnameColours = '' | ||||
|         iter = self.model.get_iter_first() | ||||
|         while (iter): | ||||
|             surname = self.model.get_value(iter, 0) # .encode('iso-8859-1','xmlcharrefreplace') | ||||
|             colour = self.model.get_value(iter, 1) | ||||
|             # tried to use a dictionary, and tried to save it as a tuple, | ||||
|             # but coulnd't get this to work right -- this is lame, but now | ||||
|             # the surnames and colours are saved as a plain text string | ||||
|             surnameColours += surname + ' ' + colour + ' ' | ||||
|             iter = self.model.iter_next(iter) | ||||
|         return surnameColours | ||||
|  | ||||
|     def clicked(self, treeview, path, column): | ||||
|         # get the surname and colour value for this family | ||||
|         iter = self.model.get_iter(path) | ||||
|         surname = self.model.get_value(iter, 0) | ||||
|         colour = gtk.gdk.color_parse(self.model.get_value(iter, 1)) | ||||
|  | ||||
|         colourDialog = gtk.ColorSelectionDialog('Select colour for %s' % surname) | ||||
|         colourDialog.colorsel.set_current_color(colour) | ||||
|         response = colourDialog.run() | ||||
|  | ||||
|         if response == gtk.RESPONSE_OK: | ||||
|             colour = colourDialog.colorsel.get_current_color() | ||||
|             colourName = '#%02x%02x%02x' % ( | ||||
|                 int(colour.red  *256/65536), | ||||
|                 int(colour.green*256/65536), | ||||
|                 int(colour.blue *256/65536)) | ||||
|             self.model.set_value(iter, 1, colourName) | ||||
|  | ||||
|         colourDialog.destroy() | ||||
|  | ||||
|     def addSurnameClicked(self, obj): | ||||
|         skipList = set() | ||||
|         iter = self.model.get_iter_first() | ||||
|         while (iter): | ||||
|             surname = self.model.get_value(iter, 0) | ||||
|             skipList.add(surname.encode('iso-8859-1','xmlcharrefreplace')) | ||||
|             iter = self.model.iter_next(iter) | ||||
|  | ||||
|         ln = LastNameDialog(self.db, self.dialog.uistate, self.dialog.track, self.surnames, skipList) | ||||
|         surnameSet = ln.run() | ||||
|         for surname in surnameSet: | ||||
|             self.model.append([surname, '#ffffff']) | ||||
|  | ||||
|     def delSurnameClicked(self, obj): | ||||
|         (path, column) = self.treeView.get_cursor() | ||||
|         if (path): | ||||
|             iter = self.model.get_iter(path) | ||||
|             self.model.remove(iter) | ||||
|  | ||||
| #------------------------------------------------------------------------- | ||||
| # | ||||
| # Menu class | ||||
|   | ||||
| @@ -30,7 +30,7 @@ | ||||
| from _MenuOptions import MenuOptions, \ | ||||
|     NumberOption, FloatOption, BooleanOption, TextOption, \ | ||||
|     EnumeratedListOption, FilterListOption, StringOption, ColourButtonOption, \ | ||||
|     PersonOption, PersonListOption | ||||
|     PersonOption, PersonListOption, SurnameColourOption | ||||
| from _PluginMgr import \ | ||||
|      register_export, register_import, \ | ||||
|      register_tool, register_report, \ | ||||
|   | ||||
| @@ -270,6 +270,23 @@ class GVDocBase(BaseDoc.BaseDoc,BaseDoc.GVDoc): | ||||
|  | ||||
|         self.write('\n') | ||||
|  | ||||
|     def add_comment(self, comment): | ||||
|         """ | ||||
|         Add a comment. | ||||
|          | ||||
|         Implementes BaseDoc.GVDoc.add_comment(). | ||||
|         """ | ||||
|         tmp = comment.split('\n') | ||||
|         for line in tmp: | ||||
|             text = line.strip() | ||||
|             print 'text="%s"\n' % text | ||||
|             if text == "": | ||||
|                 self.write('\n') | ||||
|             elif text.startswith('#'): | ||||
|                 self.write('%s\n' % text) | ||||
|             else: | ||||
|                 self.write('# %s\n' % text) | ||||
|  | ||||
|     def start_subgraph(self,id): | ||||
|         self.write('  subgraph cluster_%s\n' % id) | ||||
|         self.write('  {\n') | ||||
|   | ||||
| @@ -67,7 +67,7 @@ from PluginUtils import register_report | ||||
| from ReportBase import Report, ReportUtils, ReportOptions, CATEGORY_CODE, MODE_GUI, MODE_CLI | ||||
| from ReportBase import Report, MenuReportOptions, MODE_GUI, MODE_CLI, CATEGORY_GRAPHVIZ | ||||
| from ReportBase._ReportDialog import ReportDialog | ||||
| from PluginUtils import register_report, FilterListOption, EnumeratedListOption, BooleanOption, NumberOption, ColourButtonOption, PersonListOption | ||||
| from PluginUtils import register_report, FilterListOption, EnumeratedListOption, BooleanOption, NumberOption, ColourButtonOption, PersonListOption, SurnameColourOption | ||||
| from QuestionDialog import ErrorDialog, WarningDialog | ||||
| from BasicUtils import name_displayer as _nd | ||||
| from DateHandler import displayer as _dd | ||||
| @@ -109,8 +109,8 @@ class FamilyLinesOptions(MenuReportOptions): | ||||
|         category = _('People of Interest') | ||||
|         # -------------------------------- | ||||
|  | ||||
|         personList = PersonListOption(  _('People of interest'), '', dbstate) | ||||
|         personList.set_help(              _('People of interest are used as a starting point when determining \"family lines\".')) | ||||
|         personList = PersonListOption(      _('People of interest'), '', dbstate) | ||||
|         personList.set_help(                _('People of interest are used as a starting point when determining \"family lines\".')) | ||||
|         menu.add_option(category, 'FLgidlist', personList) | ||||
|  | ||||
|         followParents = BooleanOption(      _('Follow parents to determine family lines'), True) | ||||
| @@ -129,7 +129,9 @@ class FamilyLinesOptions(MenuReportOptions): | ||||
|         category = _('Family Colours') | ||||
|         # ---------------------------- | ||||
|  | ||||
|         # todo, family colours | ||||
|         surnameColour = SurnameColourOption(_('Family colours'), '', dbstate) | ||||
|         surnameColour.set_help(             _('Colours to use for various family lines.')) | ||||
|         menu.add_option(category, 'FLsurnameColours', surnameColour) | ||||
|  | ||||
|         # ------------------------- | ||||
|         category = _('Individuals') | ||||
| @@ -270,7 +272,7 @@ class FamilyLinesReport(Report): | ||||
|  | ||||
|         # convert the 'surnameColours' string to a dictionary of names and colours | ||||
|         self.surnameColours = {} | ||||
|         tmp = '' # TODO, FIXME options.handler.options_dict['FLsurnameColours'].split() | ||||
|         tmp = options.handler.options_dict['FLsurnameColours'].split() | ||||
|         while len(tmp) > 1: | ||||
|             surname = tmp.pop(0).encode('iso-8859-1','xmlcharrefreplace') | ||||
|             colour = tmp.pop(0) | ||||
| @@ -316,19 +318,19 @@ class FamilyLinesReport(Report): | ||||
|         # now that begin_report() has done the work, output what we've | ||||
|         # obtained into whatever file or format the user expects to use | ||||
|  | ||||
|         self.doc.write('# Number of people in database:    %d\n' % self.db.get_number_of_people()) | ||||
|         self.doc.write('# Number of people of interest:    %d\n' % len(self.peopleToOutput)) | ||||
|         self.doc.write('# Number of families in database:  %d\n' % self.db.get_number_of_families()) | ||||
|         self.doc.write('# Number of families of interest:  %d\n' % len(self.familiesToOutput)) | ||||
|         self.doc.add_comment('# Number of people in database:    %d' % self.db.get_number_of_people()) | ||||
|         self.doc.add_comment('# Number of people of interest:    %d' % len(self.peopleToOutput)) | ||||
|         self.doc.add_comment('# Number of families in database:  %d' % self.db.get_number_of_families()) | ||||
|         self.doc.add_comment('# Number of families of interest:  %d' % len(self.familiesToOutput)) | ||||
|         if self.removeExtraPeople: | ||||
|             self.doc.write('# Additional people removed:       %d\n' % self.deletedPeople) | ||||
|             self.doc.write('# Additional families removed:     %d\n' % self.deletedFamilies) | ||||
|         self.doc.write('# Initial list of people of interest:\n') | ||||
|             self.doc.add_comment('# Additional people removed:       %d' % self.deletedPeople) | ||||
|             self.doc.add_comment('# Additional families removed:     %d' % self.deletedFamilies) | ||||
|         self.doc.add_comment('# Initial list of people of interest:') | ||||
|         for handle in self.interestSet: | ||||
|             person = self.db.get_person_from_handle(handle) | ||||
|             gid = person.get_gramps_id() | ||||
|             name = person.get_primary_name().get_regular_name() | ||||
|             self.doc.write('# -> %s, %s\n' % (gid, name)) | ||||
|             self.doc.add_comment('# -> %s, %s' % (gid, name)) | ||||
|  | ||||
|         self.writePeople() | ||||
|         self.writeFamilies() | ||||
| @@ -609,7 +611,7 @@ class FamilyLinesReport(Report): | ||||
|  | ||||
|     def writePeople(self): | ||||
|  | ||||
|         self.doc.write('\n') | ||||
|         self.doc.add_comment('') | ||||
|  | ||||
|         # if we're going to attempt to include images, then use the HTML style of .dot file | ||||
|         bUseHtmlOutput = False | ||||
| @@ -746,7 +748,7 @@ class FamilyLinesReport(Report): | ||||
|  | ||||
|     def writeFamilies(self): | ||||
|  | ||||
|         self.doc.write('\n') | ||||
|         self.doc.add_comment('') | ||||
|  | ||||
|         # loop through all the families we need to output | ||||
|         for familyHandle in self.familiesToOutput: | ||||
| @@ -804,7 +806,7 @@ class FamilyLinesReport(Report): | ||||
|                 if label != '': | ||||
|                     label += '\\n' | ||||
|                 label += '%s' % childrenStr | ||||
|             self.doc.add_node(fgid,label,"ellipse","","filled",self.colourFamilies) | ||||
|             self.doc.add_node(fgid, label, "ellipse", "", "filled", self.colourFamilies) | ||||
|              | ||||
|  | ||||
|         # now that we have the families written, go ahead and link the parents and children to the families | ||||
| @@ -820,7 +822,7 @@ class FamilyLinesReport(Report): | ||||
|             if self.useSubgraphs and fatherHandle and motherHandle: | ||||
|                 self.doc.start_subgraph(fgid) | ||||
|  | ||||
|             self.doc.write('\n') | ||||
|             self.doc.add_comment('') | ||||
|  | ||||
|             # see if we have a father to link to this family | ||||
|             if fatherHandle: | ||||
| @@ -843,7 +845,7 @@ class FamilyLinesReport(Report): | ||||
|             for childRef in family.get_child_ref_list(): | ||||
|                 if childRef.ref in self.peopleToOutput: | ||||
|                     child = self.db.get_person_from_handle(childRef.ref) | ||||
|                     comment = "child: %s" % child.get_primary_name().get_regular_name() | ||||
|                     comment = "child:  %s" % child.get_primary_name().get_regular_name() | ||||
|                     self.doc.add_link(child.get_gramps_id(), fgid, comment=comment) | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user