79
78
# class FamilyLinesOptions(MenuReportOptions)
80
79
# - this class is created when the report dialog comes up
81
80
# - all configuration controls for the report are created here
82
# - see src/ReportBase/_ReportOptions.py for more information
84
82
# class FamilyLinesReport(Report)
85
83
# - this class is created only after the user clicks on "OK"
86
84
# - the actual report generation is done by this class
87
# - see src/ReportBase/_Report.py for more information
89
# Likely to be of additional interest is register_report() at the
90
# very bottom of this file.
92
86
#------------------------------------------------------------------------
94
88
class FamilyLinesOptions(MenuReportOptions):
96
90
Defines all of the controls necessary
97
to configure the FamilyLines reports.
91
to configure the FamilyLines report.
99
93
def __init__(self, name, dbase):
100
94
self.limit_parents = None
108
102
def add_menu_options(self, menu):
110
# --------------------------------
111
category_name = _('People of Interest')
104
# ---------------------
105
category_name = _('Report Options')
112
106
add_option = partial(menu.add_option, category_name)
113
# --------------------------------
115
person_list = PersonListOption(_('People of interest'))
116
person_list.set_help(_('People of interest are used as a starting '
117
'point when determining "family lines".'))
118
add_option('gidlist', person_list)
107
# ---------------------
120
109
stdoptions.add_name_format_option(menu, category_name)
122
followpar = BooleanOption(
123
_('Follow parents to determine family lines'), True)
111
stdoptions.add_private_data_option(menu, category_name, default=False)
113
followpar = BooleanOption(_('Follow parents to determine '
114
'"family lines"'), True)
124
115
followpar.set_help(_('Parents and their ancestors will be '
125
116
'considered when determining "family lines".'))
126
117
add_option('followpar', followpar)
131
122
'determining "family lines".'))
132
123
add_option('followchild', followchild)
134
remove_extra_people = BooleanOption(
135
_('Try to remove extra people and families'), True)
125
remove_extra_people = BooleanOption(_('Try to remove extra '
126
'people and families'), True)
136
127
remove_extra_people.set_help(_('People and families not directly '
137
128
'related to people of interest will '
138
129
'be removed when determining '
139
130
'"family lines".'))
140
131
add_option('removeextra', remove_extra_people)
133
use_roundedcorners = BooleanOption(_('Use rounded corners'), False)
134
use_roundedcorners.set_help(_('Use rounded corners to differentiate '
135
'between women and men.'))
136
add_option("useroundedcorners", use_roundedcorners)
138
color = EnumeratedListOption(_("Graph coloring"), "filled")
139
for i in range(len(_COLORS)):
140
color.add_item(_COLORS[i]["value"], _COLORS[i]["name"])
141
color.set_help(_("Males will be shown with blue, females "
142
"with red, unless otherwise set above for filled. "
143
"If the sex of an individual "
144
"is unknown it will be shown with gray."))
145
add_option("color", color)
142
147
stdoptions.add_localization_option(menu, category_name)
144
# ----------------------------
145
add_option = partial(menu.add_option, _('Family Colors'))
146
# ----------------------------
148
surname_color = SurnameColorOption(_('Family colors'))
149
surname_color.set_help(_('Colors to use for various family lines.'))
150
add_option('surnamecolors', surname_color)
152
# -------------------------
153
add_option = partial(menu.add_option, _('Individuals'))
154
# -------------------------
156
color_males = ColorOption(_('Males'), '#e0e0ff')
157
color_males.set_help(_('The color to use to display men.'))
158
add_option('colormales', color_males)
160
color_females = ColorOption(_('Females'), '#ffe0e0')
161
color_females.set_help(_('The color to use to display women.'))
162
add_option('colorfemales', color_females)
164
color_unknown = ColorOption(_('Unknown'), '#e0e0e0')
165
color_unknown.set_help(_('The color to use '
166
'when the gender is unknown.'))
167
add_option('colorunknown', color_unknown)
169
color_family = ColorOption(_('Families'), '#ffffe0')
170
color_family.set_help(_('The color to use to display families.'))
171
add_option('colorfamilies', color_family)
149
# --------------------------------
150
add_option = partial(menu.add_option, _('People of Interest'))
151
# --------------------------------
153
person_list = PersonListOption(_('People of interest'))
154
person_list.set_help(_('People of interest are used as a starting '
155
'point when determining "family lines".'))
156
add_option('gidlist', person_list)
173
158
self.limit_parents = BooleanOption(_('Limit the number of ancestors'),
196
181
add_option('maxchildren', self.max_children)
198
183
# --------------------
199
add_option = partial(menu.add_option, _('Images'))
184
add_option = partial(menu.add_option, _('Include'))
200
185
# --------------------
202
self.include_images = BooleanOption(_('Include '
203
'thumbnail images of people'),
205
self.include_images.set_help(_('Whether to '
206
'include thumbnail images of people.'))
207
add_option('incimages', self.include_images)
208
self.include_images.connect('value-changed', self.images_changed)
210
self.image_location = EnumeratedListOption(_('Thumbnail location'), 0)
211
self.image_location.add_item(0, _('Above the name'))
212
self.image_location.add_item(1, _('Beside the name'))
213
self.image_location.set_help(_('Where the thumbnail image '
214
'should appear relative to the name'))
215
add_option('imageonside', self.image_location)
217
# ---------------------
218
add_option = partial(menu.add_option, _('Options'))
219
# ---------------------
221
color = EnumeratedListOption(_("Graph coloring"), "filled")
222
for i in range(len(_COLORS)):
223
color.add_item(_COLORS[i]["value"], _COLORS[i]["name"])
224
color.set_help(_("Males will be shown with blue, females "
225
"with red, unless otherwise set above for filled. "
226
"If the sex of an individual "
227
"is unknown it will be shown with gray."))
228
add_option("color", color)
230
use_roundedcorners = BooleanOption(_('Use rounded corners'), False)
231
use_roundedcorners.set_help(_('Use rounded corners to differentiate '
232
'between women and men.'))
233
add_option("useroundedcorners", use_roundedcorners)
187
include_id = EnumeratedListOption(_('Include Gramps ID'), 0)
188
include_id.add_item(0, _('Do not include'))
189
include_id.add_item(1, _('Share an existing line'))
190
include_id.add_item(2, _('On a line of its own'))
191
include_id.set_help(_("Whether (and where) to include Gramps IDs"))
192
add_option("incid", include_id)
235
194
self.include_dates = BooleanOption(_('Include dates'), True)
236
195
self.include_dates.set_help(_('Whether to include dates for people '
249
208
'and families.'))
250
209
add_option('incplaces', include_places)
252
include_num_children = BooleanOption(
253
_('Include the number of children'), True)
211
include_num_children = BooleanOption(_('Include the number of '
254
213
include_num_children.set_help(_('Whether to include the number of '
255
214
'children for families with more '
256
215
'than 1 child.'))
257
216
add_option('incchildcnt', include_num_children)
259
include_private = BooleanOption(_('Include private records'), False)
260
include_private.set_help(_('Whether to include names, dates, and '
261
'families that are marked as private.'))
262
add_option('incprivate', include_private)
218
self.include_images = BooleanOption(_('Include '
219
'thumbnail images of people'),
221
self.include_images.set_help(_('Whether to '
222
'include thumbnail images of people.'))
223
add_option('incimages', self.include_images)
224
self.include_images.connect('value-changed', self.images_changed)
226
self.image_location = EnumeratedListOption(_('Thumbnail location'), 0)
227
self.image_location.add_item(0, _('Above the name'))
228
self.image_location.add_item(1, _('Beside the name'))
229
self.image_location.set_help(_('Where the thumbnail image '
230
'should appear relative to the name'))
231
add_option('imageonside', self.image_location)
233
# ----------------------------
234
add_option = partial(menu.add_option, _('Family Colors'))
235
# ----------------------------
237
surname_color = SurnameColorOption(_('Family colors'))
238
surname_color.set_help(_('Colors to use for various family lines.'))
239
add_option('surnamecolors', surname_color)
241
# -------------------------
242
add_option = partial(menu.add_option, _('Individuals'))
243
# -------------------------
245
color_males = ColorOption(_('Males'), '#e0e0ff')
246
color_males.set_help(_('The color to use to display men.'))
247
add_option('colormales', color_males)
249
color_females = ColorOption(_('Females'), '#ffe0e0')
250
color_females.set_help(_('The color to use to display women.'))
251
add_option('colorfemales', color_females)
253
color_unknown = ColorOption(_('Unknown'), '#e0e0e0')
254
color_unknown.set_help(_('The color to use '
255
'when the gender is unknown.'))
256
add_option('colorunknown', color_unknown)
258
color_family = ColorOption(_('Families'), '#ffffe0')
259
color_family.set_help(_('The color to use to display families.'))
260
add_option('colorfamilies', color_family)
264
262
self.limit_changed()
265
263
self.images_changed()
299
297
The arguments are:
301
database - the GRAMPS database instance
302
options - instance of the FamilyLinesOptions class for this report
303
user - a gen.user.User() instance
299
database - the GRAMPS database instance
300
options - instance of the FamilyLinesOptions class for this report
301
user - a gen.user.User() instance
302
name_format - Preferred format to display names
303
incl_private - Whether to include private data
304
incid - Whether to include IDs.
305
306
Report.__init__(self, database, options, user)
309
get_option_by_name = menu.get_option_by_name
310
get_value = lambda name: get_option_by_name(name).get_value()
312
stdoptions.run_private_data_option(self, menu)
313
self._db = self.database
307
315
# initialize several convenient variables
309
316
self._people = set() # handle of people we need in the report
310
317
self._families = set() # handle of families we need in the report
311
318
self._deleted_people = 0
312
319
self._deleted_families = 0
313
320
self._user = user
316
get_option_by_name = menu.get_option_by_name
317
get_value = lambda name: get_option_by_name(name).get_value()
319
322
self._followpar = get_value('followpar')
320
323
self._followchild = get_value('followchild')
321
324
self._removeextra = get_value('removeextra')
489
486
for family_handle in person.get_parent_family_handle_list():
490
487
family = self._db.get_family_from_handle(family_handle)
492
if not family.private or self._incprivate:
493
father = self._db.get_person_from_handle(
494
family.get_father_handle())
495
mother = self._db.get_person_from_handle(
496
family.get_mother_handle())
498
if not father.private or self._incprivate:
499
ancestorsNotYetProcessed.add(
500
family.get_father_handle())
501
self._families.add(family_handle)
503
if not mother.private or self._incprivate:
504
ancestorsNotYetProcessed.add(
505
family.get_mother_handle())
506
self._families.add(family_handle)
489
father = self._db.get_person_from_handle(
490
family.get_father_handle())
491
mother = self._db.get_person_from_handle(
492
family.get_mother_handle())
494
ancestorsNotYetProcessed.add(
495
family.get_father_handle())
496
self._families.add(family_handle)
498
ancestorsNotYetProcessed.add(
499
family.get_mother_handle())
500
self._families.add(family_handle)
508
502
def removeUninterestingParents(self):
509
503
# start with all the people we've already identified
694
684
# iterate through this person's families
695
685
for family_handle in person.get_family_handle_list():
696
686
family = self._db.get_family_from_handle(family_handle)
697
if (family.private and self._incprivate) or not family.private:
699
# queue up any children from this person's family
700
for childRef in family.get_child_ref_list():
701
child = self._db.get_person_from_handle(childRef.ref)
702
if (child.private and self._incprivate) or not child.private:
703
childrenNotYetProcessed.add(child.get_handle())
704
self._families.add(family_handle)
706
# include the spouse from this person's family
707
spouse_handle = ReportUtils.find_spouse(person, family)
709
spouse = self._db.get_person_from_handle(spouse_handle)
710
if (spouse.private and self._incprivate) or not spouse.private:
711
childrenToInclude.add(spouse_handle)
712
self._families.add(family_handle)
688
# queue up any children from this person's family
689
for childRef in family.get_child_ref_list():
690
child = self._db.get_person_from_handle(childRef.ref)
691
childrenNotYetProcessed.add(child.get_handle())
692
self._families.add(family_handle)
694
# include the spouse from this person's family
695
spouse_handle = ReportUtils.find_spouse(person, family)
697
spouse = self._db.get_person_from_handle(spouse_handle)
698
childrenToInclude.add(spouse_handle)
699
self._families.add(family_handle)
714
701
# we now merge our temp set "childrenToInclude" into our master set
715
702
self._people.update(childrenToInclude)
718
704
def writePeople(self):
720
706
self.doc.add_comment('')
754
741
# output the birth or fallback event
756
743
if bth_event and self._incdates:
757
if not bth_event.private or self._incprivate:
758
date = bth_event.get_date_object()
759
if self._just_years and date.get_year_valid():
760
birthStr = '%i' % date.get_year()
762
birthStr = self._get_date(date)
744
date = bth_event.get_date_object()
745
if self._just_years and date.get_year_valid():
746
birthStr = '%i' % date.get_year()
748
birthStr = self._get_date(date)
764
750
# get birth place (one of: city, state, or country) we can use
765
751
birthplace = None
766
752
if bth_event and self._incplaces:
767
if not bth_event.private or self._incprivate:
768
place = self._db.get_place_from_handle(bth_event.get_place_handle())
770
location = get_main_location(self._db, place)
771
if location.get(PlaceType.CITY):
772
birthplace = location.get(PlaceType.CITY)
773
elif location.get(PlaceType.STATE):
774
birthplace = location.get(PlaceType.STATE)
775
elif location.get(PlaceType.COUNTRY):
776
birthplace = location.get(PlaceType.COUNTRY)
753
place = self._db.get_place_from_handle(
754
bth_event.get_place_handle())
756
location = get_main_location(self._db, place)
757
if location.get(PlaceType.CITY):
758
birthplace = location.get(PlaceType.CITY)
759
elif location.get(PlaceType.STATE):
760
birthplace = location.get(PlaceType.STATE)
761
elif location.get(PlaceType.COUNTRY):
762
birthplace = location.get(PlaceType.COUNTRY)
778
764
# see if we have a deceased date we can use
780
766
if dth_event and self._incdates:
781
if not dth_event.private or self._incprivate:
782
date = dth_event.get_date_object()
783
if self._just_years and date.get_year_valid():
784
deathStr = '%i' % date.get_year()
786
deathStr = self._get_date(date)
767
date = dth_event.get_date_object()
768
if self._just_years and date.get_year_valid():
769
deathStr = '%i' % date.get_year()
771
deathStr = self._get_date(date)
788
773
# get death place (one of: city, state, or country) we can use
789
774
deathplace = None
790
775
if dth_event and self._incplaces:
791
if not dth_event.private or self._incprivate:
792
place = self._db.get_place_from_handle(dth_event.get_place_handle())
794
location = get_main_location(self._db, place)
795
if location.get(PlaceType.CITY):
796
deathplace = location.get(PlaceType.CITY)
797
elif location.get(PlaceType.STATE):
798
deathplace = location.get(PlaceType.STATE)
799
elif location.get(PlaceType.COUNTRY):
800
deathplace = location.get(PlaceType.COUNTRY)
776
place = self._db.get_place_from_handle(
777
dth_event.get_place_handle())
779
location = get_main_location(self._db, place)
780
if location.get(PlaceType.CITY):
781
deathplace = location.get(PlaceType.CITY)
782
elif location.get(PlaceType.STATE):
783
deathplace = location.get(PlaceType.STATE)
784
elif location.get(PlaceType.COUNTRY):
785
deathplace = location.get(PlaceType.COUNTRY)
802
787
# see if we have an image to use for this person
905
894
(event_ref.get_role() == EventRoleType.FAMILY or
906
895
event_ref.get_role() == EventRoleType.PRIMARY ):
907
896
# get the wedding date
908
if (event.private and self._incprivate) or not event.private:
910
date = event.get_date_object()
911
if self._just_years and date.get_year_valid():
912
weddingDate = '%i' % date.get_year()
914
weddingDate = self._get_date(date)
915
# get the wedding location
917
place = self._db.get_place_from_handle(event.get_place_handle())
919
location = get_main_location(self._db, place)
920
if location.get(PlaceType.CITY):
921
weddingPlace = location.get(PlaceType.CITY)
922
elif location.get(PlaceType.STATE):
923
weddingPlace = location.get(PlaceType.STATE)
924
elif location.get(PlaceType.COUNTRY):
925
weddingPlace = location.get(PlaceType.COUNTRY)
898
date = event.get_date_object()
899
if self._just_years and date.get_year_valid():
900
weddingDate = '%i' % date.get_year()
902
weddingDate = self._get_date(date)
903
# get the wedding location
905
place = self._db.get_place_from_handle(
906
event.get_place_handle())
908
location = get_main_location(self._db, place)
909
if location.get(PlaceType.CITY):
910
weddingPlace = location.get(PlaceType.CITY)
911
elif location.get(PlaceType.STATE):
912
weddingPlace = location.get(PlaceType.STATE)
913
elif location.get(PlaceType.COUNTRY):
914
weddingPlace = location.get(PlaceType.COUNTRY)
928
917
# figure out the number of children (if any)
936
925
).format(number_of=child_count)
942
932
label += '%s' % weddingDate
933
if self.includeid == 1 and not fgid_already: # same line
934
label += " (%s)" % fgid
946
939
label += '%s' % weddingPlace
940
if self.includeid == 1 and not fgid_already: # same line
941
label += " (%s)" % fgid
943
if self.includeid == 1 and not label:
944
label = "(%s)" % fgid
946
elif self.includeid == 2 and not label: # own line
947
label = "(%s)" % fgid
949
elif self.includeid == 2 and label and not fgid_already:
950
label += "\\n(%s)" % fgid
950
955
label += '%s' % childrenStr
956
if self.includeid == 1 and not fgid_already: # same line
957
label += " (%s)" % fgid
952
960
shape = "ellipse"