add_comment() and work in progress for the new GraphViz framework

svn: r9679
This commit is contained in:
Stéphane Charette 2008-01-02 08:43:19 +00:00
parent a8a6c017e6
commit 95496e6449
6 changed files with 282 additions and 23 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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, \

View File

@ -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')

View File

@ -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)