1#
2# Gramps - a GTK+/GNOME based genealogy program
3#
4# Copyright (C) 2007       Brian G. Matherly
5# Copyright (C) 2011       Tim G L Lyons
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20#
21
22"""
23Proxy class for the Gramps databases. Filter out all data marked private.
24"""
25
26#-------------------------------------------------------------------------
27#
28# Python modules
29#
30#-------------------------------------------------------------------------
31import types
32
33#-------------------------------------------------------------------------
34#
35# Gramps libraries
36#
37#-------------------------------------------------------------------------
38from ..db.base import DbReadBase, DbWriteBase
39from ..lib import (Citation, Event, Family, Media, Note, Person, Place,
40                   Repository, Source, Tag)
41from ..const import GRAMPS_LOCALE as glocale
42
43class ProxyCursor:
44    """
45    A cursor for moving through proxied data.
46    """
47    def __init__(self, get_raw, get_handles):
48        self.get_raw = get_raw
49        self.get_handles = get_handles
50
51    def __enter__(self):
52        """
53        Context manager enter method
54        """
55        return self
56
57    def __exit__(self, exc_type, exc_val, exc_tb):
58        pass
59
60    def __iter__(self):
61        for handle in self.get_handles():
62            yield handle, self.get_raw(handle)
63
64class ProxyMap:
65    """
66    A dictionary-like object for accessing "raw" proxied data. Of
67    course, proxied data may have been changed by the proxy.
68    """
69    def __init__(self, db, get_raw, get_keys):
70        self.get_raw = get_raw
71        self.get_keys = get_keys
72        self.db = db
73
74    def __getitem__(self, handle):
75        return self.get_raw(handle)
76
77    def keys(self):
78        """ return the keys """
79        return self.get_keys()
80
81class ProxyDbBase(DbReadBase):
82    """
83    ProxyDbBase is a base class for building a proxy to a Gramps database.
84    This class attempts to implement functions that are likely to be common
85    among proxy classes. Functions that are not likely to be common raise a
86    NotImplementedError to remind the developer to implement those functions.
87
88    Real database proxy classes can inherit from this class to make sure the
89    database interface is properly implemented.
90    """
91
92    def __init__(self, db):
93        """
94        Create a new ProxyDb instance.
95        """
96        self.db = self.basedb = db
97        while isinstance(self.basedb, ProxyDbBase):
98            self.basedb = self.basedb.db
99        self.name_formats = db.name_formats
100        self.bookmarks = db.bookmarks
101        self.family_bookmarks = db.family_bookmarks
102        self.event_bookmarks = db.event_bookmarks
103        self.place_bookmarks = db.place_bookmarks
104        self.source_bookmarks = db.source_bookmarks
105        self.citation_bookmarks = db.citation_bookmarks
106        self.repo_bookmarks = db.repo_bookmarks
107        self.media_bookmarks = db.media_bookmarks
108        self.note_bookmarks = db.note_bookmarks
109
110        self.person_map = ProxyMap(self, self.get_raw_person_data,
111                                   self.get_person_handles)
112        self.family_map = ProxyMap(self, self.get_raw_family_data,
113                                   self.get_family_handles)
114        self.event_map = ProxyMap(self, self.get_raw_event_data,
115                                  self.get_event_handles)
116        self.place_map = ProxyMap(self, self.get_raw_place_data,
117                                  self.get_place_handles)
118        self.source_map = ProxyMap(self, self.get_raw_source_data,
119                                   self.get_source_handles)
120        self.repository_map = ProxyMap(self, self.get_raw_repository_data,
121                                       self.get_repository_handles)
122        self.media_map = ProxyMap(self, self.get_raw_media_data,
123                                  self.get_media_handles)
124        self.note_map = ProxyMap(self, self.get_raw_note_data,
125                                 self.get_note_handles)
126
127    def is_open(self):
128        """
129        Return True if the database has been opened.
130        """
131        return self.db.is_open()
132
133    def get_researcher(self):
134        """returns the Researcher instance, providing information about
135        the owner of the database"""
136        return self.db.get_researcher()
137
138    def include_something(self, handle, obj=None):
139        """
140        Model predicate. Returns True if object referred to by handle is to be
141        included, otherwise returns False.
142        """
143        if obj is None:
144            obj = self.get_unfiltered_something(handle)
145
146        # Call function to determine if object should be included or not
147        return obj.include()
148
149    # Define default predicates for each object type
150
151    include_person = \
152    include_family = \
153    include_event = \
154    include_source = \
155    include_citation = \
156    include_place = \
157    include_media = \
158    include_repository = \
159    include_note = \
160    include_tag = \
161        None
162
163    def get_person_cursor(self):
164        return ProxyCursor(self.get_raw_person_data,
165                           self.get_person_handles)
166
167    def get_family_cursor(self):
168        return ProxyCursor(self.get_raw_family_data,
169                           self.get_family_handles)
170
171    def get_event_cursor(self):
172        return ProxyCursor(self.get_raw_event_data,
173                           self.get_event_handles)
174
175    def get_source_cursor(self):
176        return ProxyCursor(self.get_raw_source_data,
177                           self.get_source_handles)
178
179    def get_citation_cursor(self):
180        return ProxyCursor(self.get_raw_citation_data,
181                           self.get_citation_handles)
182
183    def get_place_cursor(self):
184        return ProxyCursor(self.get_raw_place_data,
185                           self.get_place_handles)
186
187    def get_media_cursor(self):
188        return ProxyCursor(self.get_raw_media_data,
189                           self.get_media_handles)
190
191    def get_repository_cursor(self):
192        return ProxyCursor(self.get_raw_repository_data,
193                           self.get_repository_handles)
194
195    def get_note_cursor(self):
196        return ProxyCursor(self.get_raw_note_data,
197                           self.get_note_handles)
198
199    def get_tag_cursor(self):
200        return ProxyCursor(self.get_raw_tag_data,
201                           self.get_tag_handles)
202
203    def get_person_handles(self, sort_handles=False, locale=glocale):
204        """
205        Return a list of database handles, one handle for each Person in
206        the database. If sort_handles is True, the list is sorted by surnames
207        """
208        if (self.db is not None) and self.db.is_open():
209            proxied = set(self.iter_person_handles())
210            all = self.basedb.get_person_handles(sort_handles=sort_handles,
211                                                 locale=locale)
212            return [hdl for hdl in all if hdl in proxied]
213        else:
214            return []
215
216    def get_family_handles(self, sort_handles=False, locale=glocale):
217        """
218        Return a list of database handles, one handle for each Family in
219        the database. If sort_handles is True, the list is sorted by surnames
220        """
221        if (self.db is not None) and self.db.is_open():
222            proxied = set(self.iter_family_handles())
223            all = self.basedb.get_family_handles(sort_handles=sort_handles,
224                                                 locale=locale)
225            return [hdl for hdl in all if hdl in proxied]
226        else:
227            return []
228
229    def get_event_handles(self):
230        """
231        Return a list of database handles, one handle for each Event in
232        the database.
233        """
234        if (self.db is not None) and self.db.is_open():
235            return list(self.iter_event_handles())
236        else:
237            return []
238
239    def get_source_handles(self, sort_handles=False, locale=glocale):
240        """
241        Return a list of database handles, one handle for each Source in
242        the database.
243        """
244        if (self.db is not None) and self.db.is_open():
245            return list(self.iter_source_handles())
246        else:
247            return []
248
249    def get_citation_handles(self, sort_handles=False, locale=glocale):
250        """
251        Return a list of database handles, one handle for each Citation in
252        the database.
253        """
254        if (self.db is not None) and self.db.is_open():
255            return list(self.iter_citation_handles())
256        else:
257            return []
258
259    def get_place_handles(self, sort_handles=False, locale=glocale):
260        """
261        Return a list of database handles, one handle for each Place in
262        the database.
263        """
264        if (self.db is not None) and self.db.is_open():
265            return list(self.iter_place_handles())
266        else:
267            return []
268
269    def get_media_handles(self, sort_handles=False, locale=glocale):
270        """
271        Return a list of database handles, one handle for each Media in
272        the database.
273        """
274        if (self.db is not None) and self.db.is_open():
275            return list(self.iter_media_handles())
276        else:
277            return []
278
279    def get_repository_handles(self):
280        """
281        Return a list of database handles, one handle for each Repository in
282        the database.
283        """
284        if (self.db is not None) and self.db.is_open():
285            return list(self.iter_repository_handles())
286        else:
287            return []
288
289    def get_note_handles(self):
290        """
291        Return a list of database handles, one handle for each Note in
292        the database.
293        """
294        if (self.db is not None) and self.db.is_open():
295            return list(self.iter_note_handles())
296        else:
297            return []
298
299    def get_tag_handles(self, sort_handles=False, locale=glocale):
300        """
301        Return a list of database handles, one handle for each Tag in
302        the database.
303        """
304        if (self.db is not None) and self.db.is_open():
305            return list(self.iter_tag_handles())
306        else:
307            return []
308
309    def get_default_person(self):
310        """returns the default Person of the database"""
311        return self.db.get_default_person()
312
313    def get_default_handle(self):
314        """returns the default Person of the database"""
315        return self.db.get_default_handle()
316
317    def iter_person_handles(self):
318        """
319        Return an iterator over database handles, one handle for each Person in
320        the database.
321        """
322        return filter(self.include_person, self.db.iter_person_handles())
323
324    def iter_family_handles(self):
325        """
326        Return an iterator over database handles, one handle for each Family in
327        the database.
328        """
329        return filter(self.include_family, self.db.iter_family_handles())
330
331    def iter_event_handles(self):
332        """
333        Return an iterator over database handles, one handle for each Event in
334        the database.
335        """
336        return filter(self.include_event, self.db.iter_event_handles())
337
338    def iter_source_handles(self):
339        """
340        Return an iterator over database handles, one handle for each Source in
341        the database.
342        """
343        return filter(self.include_source, self.db.iter_source_handles())
344
345    def iter_citation_handles(self):
346        """
347        Return an iterator over database handles, one handle for each Citation
348        in the database.
349        """
350        return filter(self.include_citation, self.db.iter_citation_handles())
351
352    def iter_place_handles(self):
353        """
354        Return an iterator over database handles, one handle for each Place in
355        the database.
356        """
357        return filter(self.include_place, self.db.iter_place_handles())
358
359    def iter_media_handles(self):
360        """
361        Return an iterator over database handles, one handle for each Media
362        Object in the database.
363        """
364        return filter(self.include_media, self.db.iter_media_handles())
365
366    def iter_repository_handles(self):
367        """
368        Return an iterator over database handles, one handle for each
369        Repository in the database.
370        """
371        return filter(self.include_repository,
372                      self.db.iter_repository_handles())
373
374    def iter_note_handles(self):
375        """
376        Return an iterator over database handles, one handle for each Note in
377        the database.
378        """
379        return filter(self.include_note, self.db.iter_note_handles())
380
381    def iter_tag_handles(self):
382        """
383        Return an iterator over database handles, one handle for each Tag in
384        the database.
385        """
386        return filter(self.include_tag, self.db.iter_tag_handles())
387
388    def __iter_object(self, selector, method):
389        """ Helper function to return an iterator over an object class """
390        retval = filter(lambda obj:
391                        ((selector is None) or selector(obj.handle)),
392                        method())
393        return retval
394
395    def iter_people(self):
396        """
397        Return an iterator over Person objects in the database
398        """
399        return self.__iter_object(self.include_person,
400                                  self.db.iter_people)
401
402    def iter_families(self):
403        """
404        Return an iterator over Family objects in the database
405        """
406        return self.__iter_object(self.include_family,
407                                  self.db.iter_families)
408
409    def iter_events(self):
410        """
411        Return an iterator over Event objects in the database
412        """
413        return self.__iter_object(self.include_event,
414                                  self.db.iter_events)
415
416    def iter_places(self):
417        """
418        Return an iterator over Place objects in the database
419        """
420        return self.__iter_object(self.include_place,
421                                  self.db.iter_places)
422
423    def iter_sources(self):
424        """
425        Return an iterator over Source objects in the database
426        """
427        return self.__iter_object(self.include_source,
428                                  self.db.iter_sources)
429
430    def iter_citations(self):
431        """
432        Return an iterator over Citation objects in the database
433        """
434        return self.__iter_object(self.include_citation,
435                                  self.db.iter_citations)
436
437    def iter_media(self):
438        """
439        Return an iterator over Media objects in the database
440        """
441        return self.__iter_object(self.include_media,
442                                  self.db.iter_media)
443
444    def iter_repositories(self):
445        """
446        Return an iterator over Repositories objects in the database
447        """
448        return self.__iter_object(self.include_repository,
449                                  self.db.iter_repositories)
450
451    def iter_notes(self):
452        """
453        Return an iterator over Note objects in the database
454        """
455        return self.__iter_object(self.include_note,
456                                  self.db.iter_notes)
457
458    def iter_tags(self):
459        """
460        Return an iterator over Tag objects in the database
461        """
462        return self.__iter_object(self.include_tag,
463                                  self.db.iter_tags)
464
465    @staticmethod
466    def gfilter(predicate, obj):
467        """
468        Returns obj if predicate is True or not callable, else returns None
469        """
470        if predicate is not None and obj is not None:
471            return obj if predicate(obj.handle) else None
472        return obj
473
474    def __getattr__(self, name):
475        """ Handle unknown attribute lookups """
476        if name == "readonly":
477            return True
478        sname = name.split('_')
479        if sname[:2] == ['get', 'unfiltered']:
480            """
481            Handle get_unfiltered calls.  Return the name of the access
482            method for the base database object.  Call setattr before
483            returning so that the lookup happens at most once for a given
484            method call and a given object.
485            """
486            attr = getattr(self.basedb, 'get_' + sname[2] + '_from_handle')
487            setattr(self, name, attr)
488            return attr
489
490        # if a write-method:
491        if (name in DbWriteBase.__dict__ and
492                not name.startswith("__") and
493                type(DbWriteBase.__dict__[name]) is types.FunctionType):
494            raise AttributeError
495        # Default behaviour: lookup attribute in parent object
496        return getattr(self.db, name)
497
498    def get_person_from_handle(self, handle):
499        """
500        Finds a Person in the database from the passed gramps handle.
501        If no such Person exists, None is returned.
502        """
503        return self.gfilter(self.include_person,
504                            self.db.get_person_from_handle(handle))
505
506    def get_family_from_handle(self, handle):
507        """
508        Finds a Family in the database from the passed gramps handle.
509        If no such Family exists, None is returned.
510        """
511        return self.gfilter(self.include_family,
512                            self.db.get_family_from_handle(handle))
513
514    def get_event_from_handle(self, handle):
515        """
516        Finds a Event in the database from the passed gramps handle.
517        If no such Event exists, None is returned.
518        """
519        return self.gfilter(self.include_event,
520                            self.db.get_event_from_handle(handle))
521
522    def get_source_from_handle(self, handle):
523        """
524        Finds a Source in the database from the passed gramps handle.
525        If no such Source exists, None is returned.
526        """
527        return self.gfilter(self.include_source,
528                            self.db.get_source_from_handle(handle))
529
530    def get_citation_from_handle(self, handle):
531        """
532        Finds a Citation in the database from the passed gramps handle.
533        If no such Citation exists, None is returned.
534        """
535        return self.gfilter(self.include_citation,
536                            self.db.get_citation_from_handle(handle))
537
538    def get_place_from_handle(self, handle):
539        """
540        Finds a Place in the database from the passed gramps handle.
541        If no such Place exists, None is returned.
542        """
543        return self.gfilter(self.include_place,
544                            self.db.get_place_from_handle(handle))
545
546    def get_media_from_handle(self, handle):
547        """
548        Finds an Object in the database from the passed gramps handle.
549        If no such Object exists, None is returned.
550        """
551        return self.gfilter(self.include_media,
552                            self.db.get_media_from_handle(handle))
553
554    def get_repository_from_handle(self, handle):
555        """
556        Finds a Repository in the database from the passed gramps handle.
557        If no such Repository exists, None is returned.
558        """
559        return self.gfilter(self.include_repository,
560                            self.db.get_repository_from_handle(handle))
561
562    def get_note_from_handle(self, handle):
563        """
564        Finds a Note in the database from the passed gramps handle.
565        If no such Note exists, None is returned.
566        """
567        return self.gfilter(self.include_note,
568                            self.db.get_note_from_handle(handle))
569
570    def get_tag_from_handle(self, handle):
571        """
572        Finds a Tag in the database from the passed gramps handle.
573        If no such Tag exists, None is returned.
574        """
575        return self.gfilter(self.include_tag,
576                            self.db.get_tag_from_handle(handle))
577
578    def get_person_from_gramps_id(self, val):
579        """
580        Finds a Person in the database from the passed Gramps ID.
581        If no such Person exists, None is returned.
582        """
583        return self.gfilter(self.include_person,
584                            self.db.get_person_from_gramps_id(val))
585
586    def get_family_from_gramps_id(self, val):
587        """
588        Finds a Family in the database from the passed Gramps ID.
589        If no such Family exists, None is returned.
590        """
591        return self.gfilter(self.include_family,
592                            self.db.get_family_from_gramps_id(val))
593
594    def get_event_from_gramps_id(self, val):
595        """
596        Finds an Event in the database from the passed Gramps ID.
597        If no such Event exists, None is returned.
598        """
599        return self.gfilter(self.include_event,
600                            self.db.get_event_from_gramps_id(val))
601
602    def get_place_from_gramps_id(self, val):
603        """
604        Finds a Place in the database from the passed gramps' ID.
605        If no such Place exists, None is returned.
606        """
607        return self.gfilter(self.include_place,
608                            self.db.get_place_from_gramps_id(val))
609
610    def get_source_from_gramps_id(self, val):
611        """
612        Finds a Source in the database from the passed gramps' ID.
613        If no such Source exists, None is returned.
614        """
615        return self.gfilter(self.include_source,
616                            self.db.get_source_from_gramps_id(val))
617
618    def get_citation_from_gramps_id(self, val):
619        """
620        Finds a Citation in the database from the passed gramps' ID.
621        If no such Citation exists, None is returned.
622        """
623        return self.gfilter(self.include_citation,
624                            self.db.get_citation_from_gramps_id(val))
625
626    def get_media_from_gramps_id(self, val):
627        """
628        Finds a Media in the database from the passed gramps' ID.
629        If no such Media exists, None is returned.
630        """
631        return self.gfilter(self.include_media,
632                            self.db.get_media_from_gramps_id(val))
633
634    def get_repository_from_gramps_id(self, val):
635        """
636        Finds a Repository in the database from the passed gramps' ID.
637        If no such Repository exists, None is returned.
638        """
639        return self.gfilter(self.include_repository,
640                            self.db.get_repository_from_gramps_id(val))
641
642    def get_note_from_gramps_id(self, val):
643        """
644        Finds a Note in the database from the passed gramps' ID.
645        If no such Note exists, None is returned.
646        """
647        return self.gfilter(self.include_note,
648                            self.db.get_note_from_gramps_id(val))
649
650    def get_tag_from_name(self, val):
651        """
652        Finds a Tag in the database from the passed tag name.
653        If no such Tag exists, None is returned.
654        """
655        return self.gfilter(self.include_tag,
656                            self.db.get_tag_from_name(val))
657
658    def get_name_group_mapping(self, surname):
659        """
660        Return the default grouping name for a surname
661        """
662        return self.db.get_name_group_mapping(surname)
663
664    def has_name_group_key(self, name):
665        """
666        Return if a key exists in the name_group table
667        """
668        return self.db.has_name_group_key(name)
669
670    def get_name_group_keys(self):
671        """
672        Return the defined names that have been assigned to a default grouping
673        """
674        return self.db.get_name_group_keys()
675
676    def get_number_of_people(self):
677        """
678        Return the number of people currently in the database.
679        """
680        return len(self.get_person_handles())
681
682    def get_number_of_families(self):
683        """
684        Return the number of families currently in the database.
685        """
686        return len(self.get_family_handles())
687
688    def get_number_of_events(self):
689        """
690        Return the number of events currently in the database.
691        """
692        return len(self.get_event_handles())
693
694    def get_number_of_places(self):
695        """
696        Return the number of places currently in the database.
697        """
698        return len(self.get_place_handles())
699
700    def get_number_of_sources(self):
701        """
702        Return the number of sources currently in the database.
703        """
704        return len(self.get_source_handles())
705
706    def get_number_of_citations(self):
707        """
708        Return the number of Citations currently in the database.
709        """
710        return len(self.get_citation_handles())
711
712    def get_number_of_media(self):
713        """
714        Return the number of media objects currently in the database.
715        """
716        return len(self.get_media_handles())
717
718    def get_number_of_repositories(self):
719        """
720        Return the number of source repositories currently in the database.
721        """
722        return len(self.get_repository_handles())
723
724    def get_number_of_notes(self):
725        """
726        Return the number of notes currently in the database.
727        """
728        return len(self.get_note_handles())
729
730    def get_number_of_tags(self):
731        """
732        Return the number of tags currently in the database.
733        """
734        return len(self.get_tag_handles())
735
736    def get_save_path(self):
737        """returns the save path of the file, or "" if one does not exist"""
738        return self.db.get_save_path()
739
740    def get_event_attribute_types(self):
741        """returns a list of all Attribute types associated with Event
742        instances in the database"""
743        return self.db.get_event_attribute_types()
744
745    def get_event_types(self):
746        """returns a list of all event types in the database"""
747        return self.db.get_event_types()
748
749    def get_person_event_types(self):
750        """Deprecated:  Use get_event_types"""
751        return self.db.get_event_types()
752
753    def get_person_attribute_types(self):
754        """returns a list of all Attribute types associated with Person
755        instances in the database"""
756        return self.db.get_person_attribute_types()
757
758    def get_family_attribute_types(self):
759        """returns a list of all Attribute types associated with Family
760        instances in the database"""
761        return self.db.get_family_attribute_types()
762
763    def get_family_event_types(self):
764        """Deprecated:  Use get_event_types"""
765        return self.db.get_event_types()
766
767    def get_media_attribute_types(self):
768        """returns a list of all Attribute types associated with Media
769        and MediaRef instances in the database"""
770        return self.db.get_media_attribute_types()
771
772    def get_family_relation_types(self):
773        """returns a list of all relationship types associated with Family
774        instances in the database"""
775        return self.db.get_family_relation_types()
776
777    def get_child_reference_types(self):
778        """returns a list of all child reference types associated with Family
779        instances in the database"""
780        return self.db.get_child_reference_types()
781
782    def get_event_roles(self):
783        """returns a list of all custom event role names associated with Event
784        instances in the database"""
785        return self.db.get_event_roles()
786
787    def get_name_types(self):
788        """returns a list of all custom names types associated with Person
789        instances in the database"""
790        return self.db.get_name_types()
791
792    def get_origin_types(self):
793        """
794        returns a list of all custom origin types
795        associated with Person/Surname
796        instances in the database
797        """
798        return self.db.get_origin_types()
799
800    def get_repository_types(self):
801        """returns a list of all custom repository types associated with
802        Repository instances in the database"""
803        return self.db.get_repository_types()
804
805    def get_note_types(self):
806        """returns a list of all custom note types associated with
807        Note instances in the database"""
808        return self.db.get_note_types()
809
810    def get_source_attribute_types(self):
811        """returns a list of all Attribute types associated with
812        Source/Citation instances in the database"""
813        return self.db.get_source_attribute_types()
814
815    def get_source_media_types(self):
816        """returns a list of all custom source media types associated with
817        Source instances in the database"""
818        return self.db.get_source_media_types()
819
820    def get_url_types(self):
821        """returns a list of all custom names types associated with Url
822        instances in the database"""
823        return self.db.get_url_types()
824
825    def get_raw_person_data(self, handle):
826        return self.get_person_from_handle(handle).serialize()
827
828    def get_raw_family_data(self, handle):
829        return self.get_family_from_handle(handle).serialize()
830
831    def get_raw_media_data(self, handle):
832        return self.get_media_from_handle(handle).serialize()
833
834    def get_raw_place_data(self, handle):
835        return self.get_place_from_handle(handle).serialize()
836
837    def get_raw_event_data(self, handle):
838        return self.get_event_from_handle(handle).serialize()
839
840    def get_raw_source_data(self, handle):
841        return self.get_source_from_handle(handle).serialize()
842
843    def get_raw_citation_data(self, handle):
844        return self.get_citation_from_handle(handle).serialize()
845
846    def get_raw_repository_data(self, handle):
847        return self.get_repository_from_handle(handle).serialize()
848
849    def get_raw_note_data(self, handle):
850        return self.get_note_from_handle(handle).serialize()
851
852    def get_raw_tag_data(self, handle):
853        return self.get_tag_from_handle(handle).serialize()
854
855    def has_person_handle(self, handle):
856        """
857        Returns True if the handle exists in the current Person database.
858        """
859        return self.gfilter(self.include_person,
860                            self.db.get_person_from_handle(handle)
861                           ) is not None
862
863    def has_family_handle(self, handle):
864        """
865        Returns True if the handle exists in the current Family database.
866        """
867        return self.gfilter(self.include_family,
868                            self.db.get_family_from_handle(handle)
869                           ) is not None
870
871    def has_event_handle(self, handle):
872        """
873        returns True if the handle exists in the current Event database.
874        """
875        return self.gfilter(self.include_event,
876                            self.db.get_event_from_handle(handle)
877                           ) is not None
878
879    def has_source_handle(self, handle):
880        """
881        returns True if the handle exists in the current Source database.
882        """
883        return self.gfilter(self.include_source,
884                            self.db.get_source_from_handle(handle)
885                           ) is not None
886
887    def has_citation_handle(self, handle):
888        """
889        returns True if the handle exists in the current Citation database.
890        """
891        return self.gfilter(self.include_citation,
892                            self.db.get_citation_from_handle(handle)
893                           ) is not None
894
895    def has_place_handle(self, handle):
896        """
897        returns True if the handle exists in the current Place database.
898        """
899        return self.gfilter(self.include_place,
900                            self.db.get_place_from_handle(handle)
901                           ) is not None
902
903    def has_media_handle(self, handle):
904        """
905        returns True if the handle exists in the current Mediadatabase.
906        """
907        return self.gfilter(self.include_media,
908                            self.db.get_media_from_handle(handle)
909                           ) is not None
910
911    def has_repository_handle(self, handle):
912        """
913        returns True if the handle exists in the current Repository database.
914        """
915        return self.gfilter(self.include_repository,
916                            self.db.get_repository_from_handle(handle)
917                           ) is not None
918
919    def has_note_handle(self, handle):
920        """
921        returns True if the handle exists in the current Note database.
922        """
923        return self.gfilter(self.include_note,
924                            self.db.get_note_from_handle(handle)
925                           ) is not None
926
927    def has_tag_handle(self, handle):
928        """
929        returns True if the handle exists in the current Tag database.
930        """
931        return self.gfilter(self.include_tag,
932                            self.db.get_tag_from_handle(handle)
933                           ) is not None
934
935    def get_mediapath(self):
936        """returns the default media path of the database"""
937        return self.db.get_mediapath()
938
939    def get_bookmarks(self):
940        """returns the list of Person handles in the bookmarks"""
941        return self.bookmarks
942
943    def get_family_bookmarks(self):
944        """returns the list of Family handles in the bookmarks"""
945        return self.family_bookmarks
946
947    def get_event_bookmarks(self):
948        """returns the list of Event handles in the bookmarks"""
949        return self.event_bookmarks
950
951    def get_place_bookmarks(self):
952        """returns the list of Place handles in the bookmarks"""
953        return self.place_bookmarks
954
955    def get_source_bookmarks(self):
956        """returns the list of Source handles in the bookmarks"""
957        return self.source_bookmarks
958
959    def get_citation_bookmarks(self):
960        """returns the list of Citation handles in the bookmarks"""
961        return self.citation_bookmarks
962
963    def get_media_bookmarks(self):
964        """returns the list of Media handles in the bookmarks"""
965        return self.media_bookmarks
966
967    def get_repo_bookmarks(self):
968        """returns the list of Repository handles in the bookmarks"""
969        return self.repo_bookmarks
970
971    def get_note_bookmarks(self):
972        """returns the list of Note handles in the bookmarks"""
973        return self.note_bookmarks
974
975    def close(self):
976        """
977        Close on a proxy closes real database.
978        """
979        self.basedb.close()
980
981    def find_initial_person(self):
982        """
983        Find an initial person, given that they might not be
984        available.
985        """
986        person = self.basedb.find_initial_person()
987        if person and self.has_person_handle(person.handle):
988            return person
989        else:
990            return None
991
992    def get_dbid(self):
993        """
994        Return the database ID.
995        """
996        return self.basedb.get_dbid()
997
998