1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """
24 Base class for the GRAMPS databases. All database interfaces should inherit
25 from this class.
26 """
27
28
29
30
31
32
33 import cPickle
34 import time
35 import random
36 import locale
37 import os
38 from sys import maxint
39 from bsddb import db
40 from gettext import gettext as _
41
42 import logging
43 LOG = logging.getLogger(".GrampsDb")
44
45
46
47
48
49
50 from gen.lib import (MediaObject, Person, Family, Source, Event, Place,
51 Repository, Note, GenderStats, Researcher)
52 from gen.utils.callback import Callback
53 from gen.db.iterator import CursorIterator
54
55
56
57
58
59
60 from gen.db.dbconst import (PERSON_KEY, FAMILY_KEY, SOURCE_KEY, EVENT_KEY,
61 MEDIA_KEY, PLACE_KEY, REPOSITORY_KEY, NOTE_KEY,
62 REFERENCE_KEY, PERSON_COL_KEY, FAMILY_COL_KEY,
63 CHILD_COL_KEY, PLACE_COL_KEY, SOURCE_COL_KEY,
64 MEDIA_COL_KEY, EVENT_COL_KEY, REPOSITORY_COL_KEY,
65 NOTE_COL_KEY)
66
67 _UNDO_SIZE = 1000
68
69
70
71
72
73
74
75
76 CLASS_TO_KEY_MAP = {Person.__name__: PERSON_KEY,
77 Family.__name__: FAMILY_KEY,
78 Source.__name__: SOURCE_KEY,
79 Event.__name__: EVENT_KEY,
80 MediaObject.__name__: MEDIA_KEY,
81 Place.__name__: PLACE_KEY,
82 Repository.__name__:REPOSITORY_KEY,
83 Note.__name__: NOTE_KEY}
84
85 KEY_TO_CLASS_MAP = {PERSON_KEY: Person.__name__,
86 FAMILY_KEY: Family.__name__,
87 SOURCE_KEY: Source.__name__,
88 EVENT_KEY: Event.__name__,
89 MEDIA_KEY: MediaObject.__name__,
90 PLACE_KEY: Place.__name__,
91 REPOSITORY_KEY: Repository.__name__,
92 NOTE_KEY: Note.__name__}
93
94 _SIGBASE = ('person', 'family', 'source', 'event',
95 'media', 'place', 'repository', 'reference', 'note')
96
99 self.bookmarks = list(default)
100
101 - def set(self, new_list):
102 self.bookmarks = list(new_list)
103
105 return self.bookmarks
106
108 self.bookmarks.append(item)
109
111 self.bookmarks += blist
112
114 self.bookmarks.remove(item)
115
116 - def pop(self, item):
117 return self.bookmarks.pop(item)
118
120 self.bookmarks.insert(pos, item)
121
123 """
124 GRAMPS database object. This object is a base class for all
125 database interfaces.
126 """
127
128
129
130 __config__ = None
131
132 __signals__ = {
133 'person-add' : (list, ),
134 'person-update' : (list, ),
135 'person-delete' : (list, ),
136 'person-rebuild' : None,
137 'family-add' : (list, ),
138 'family-update' : (list, ),
139 'family-delete' : (list, ),
140 'family-rebuild' : None,
141 'source-add' : (list, ),
142 'source-update' : (list, ),
143 'source-delete' : (list, ),
144 'source-rebuild' : None,
145 'place-add' : (list, ),
146 'place-update' : (list, ),
147 'place-delete' : (list, ),
148 'place-rebuild' : None,
149 'media-add' : (list, ),
150 'media-update' : (list, ),
151 'media-delete' : (list, ),
152 'media-rebuild' : None,
153 'event-add' : (list, ),
154 'event-update' : (list, ),
155 'event-delete' : (list, ),
156 'event-rebuild' : None,
157 'repository-add' : (list, ),
158 'repository-update' : (list, ),
159 'repository-delete' : (list, ),
160 'repository-rebuild' : None,
161 'note-add' : (list, ),
162 'note-update' : (list, ),
163 'note-delete' : (list, ),
164 'note-rebuild' : None,
165 'long-op-start' : (object, ),
166 'long-op-heartbeat' : None,
167 'long-op-end' : None
168 }
169
170
171 try:
172 _LOG_ALL = int(os.environ.get('GRAMPS_SIGNAL', "0")) == 1
173 except:
174 _LOG_ALL = False
175
176
178 """
179 Create a new GrampsDbBase instance.
180
181 A new GrampDbBase class should never be directly created. Only classes
182 derived from this class should be created.
183 """
184
185 Callback.__init__(self)
186
187 self.set_person_id_prefix('I%04d')
188 self.set_object_id_prefix('O%04d')
189 self.set_family_id_prefix('F%04d')
190 self.set_source_id_prefix('S%04d')
191 self.set_place_id_prefix('P%04d')
192 self.set_event_id_prefix('E%04d')
193 self.set_repository_id_prefix('R%04d')
194 self.set_note_id_prefix('N%04d')
195
196 self.readonly = False
197 self.rand = random.Random(time.time())
198 self.smap_index = 0
199 self.emap_index = 0
200 self.pmap_index = 0
201 self.fmap_index = 0
202 self.lmap_index = 0
203 self.omap_index = 0
204 self.rmap_index = 0
205 self.nmap_index = 0
206 self.db_is_open = False
207
208 self.family_event_names = set()
209 self.individual_event_names = set()
210 self.individual_attributes = set()
211 self.family_attributes = set()
212 self.marker_names = set()
213 self.child_ref_types = set()
214 self.family_rel_types = set()
215 self.event_role_names = set()
216 self.name_types = set()
217 self.repository_types = set()
218 self.note_types = set()
219 self.source_media_types = set()
220 self.url_types = set()
221 self.media_attributes = set()
222
223 self.open = 0
224 self.genderStats = GenderStats()
225
226 self.undodb = []
227 self.id_trans = {}
228 self.fid_trans = {}
229 self.pid_trans = {}
230 self.sid_trans = {}
231 self.oid_trans = {}
232 self.rid_trans = {}
233 self.nid_trans = {}
234 self.eid_trans = {}
235 self.env = None
236 self.person_map = {}
237 self.family_map = {}
238 self.place_map = {}
239 self.source_map = {}
240 self.repository_map = {}
241 self.note_map = {}
242 self.media_map = {}
243 self.event_map = {}
244 self.metadata = {}
245 self.name_group = {}
246 self.undo_callback = None
247 self.redo_callback = None
248 self.undo_history_callback = None
249 self.modified = 0
250
251 self.undoindex = -1
252 self.translist = [None] * _UNDO_SIZE
253 self.abort_possible = True
254 self.undo_history_timestamp = 0
255 self.default = None
256 self.owner = Researcher()
257 self.name_formats = []
258 self.bookmarks = GrampsDbBookmarks()
259 self.family_bookmarks = GrampsDbBookmarks()
260 self.event_bookmarks = GrampsDbBookmarks()
261 self.place_bookmarks = GrampsDbBookmarks()
262 self.source_bookmarks = GrampsDbBookmarks()
263 self.repo_bookmarks = GrampsDbBookmarks()
264 self.media_bookmarks = GrampsDbBookmarks()
265 self.note_bookmarks = GrampsDbBookmarks()
266 self._bm_changes = 0
267 self.path = ""
268 self.surname_list = []
269
270 - def set_prefixes(self, person, media, family, source, place, event,
271 repository, note):
272 self.person_prefix = person
273 self.mediaobject_prefix = media
274 self.family_prefix = family
275 self.source_prefix = source
276 self.place_prefix = place
277 self.event_prefix = event
278 self.repository_prefix = repository
279 self.note_prefix = note
280
283
285 """Return True when the file has a supported version."""
286 return True
287
290
293
296
299
302
305
308
311
314
317
319 return "%08x%08x" % ( int(time.time()*10000),
320 self.rand.randint(0, maxint))
321
323 raise NotImplementedError
324
327
329 raise NotImplementedError
330
333
335 raise NotImplementedError
336
339
341 raise NotImplementedError
342
345
347 raise NotImplementedError
348
351
354
357
359 raise NotImplementedError
360
363
365 raise NotImplementedError
366
369
371 if not self.readonly:
372 self.undolog = "%s.undo" % self.full_name
373 self.undodb = db.DB()
374 self.undodb.open(self.undolog, db.DB_RECNO, db.DB_CREATE)
375
377 if not self.readonly:
378 self.undodb.close()
379 try:
380 os.remove(self.undolog)
381 except:
382 pass
383
384 - def load(self, name, callback, mode="w"):
385 """
386 Open the specified database.
387
388 The method needs to be overridden in the derived class.
389 """
390 raise NotImplementedError
391
392 - def load_from(self, other_database, filename, callback):
393 """
394 Load data from the other database into itself.
395
396 The filename is the name of the file for the newly created database.
397 The method needs to be overridden in the derived class.
398 """
399 raise NotImplementedError
400
402 """
403 Close the specified database.
404
405 The method needs to be overridden in the derived class.
406 """
407 pass
408
410 """
411 Return 1 if the database has been opened.
412 """
413 return self.db_is_open
414
416 """
417 Notify clients that the data has changed significantly, and that all
418 internal data dependent on the database should be rebuilt.
419 """
420 self.emit('person-rebuild')
421 self.emit('family-rebuild')
422 self.emit('place-rebuild')
423 self.emit('source-rebuild')
424 self.emit('media-rebuild')
425 self.emit('event-rebuild')
426 self.emit('repository-rebuild')
427 self.emit('note-rebuild')
428
429 - def commit_base(self, obj, data_map, key, update_list, add_list,
430 transaction, change_time):
431 """
432 Commit the specified Person to the database, storing the changes as
433 part of the transaction.
434 """
435 if self.readonly or not obj or not obj.handle:
436 return
437
438 if change_time:
439 obj.change = int(change_time)
440 else:
441 obj.change = int(time.time())
442 handle = str(obj.handle)
443
444 self.update_reference_map(obj, transaction)
445
446 if transaction.batch:
447 data_map[handle] = obj.serialize()
448 old_data = None
449 else:
450 old_data = data_map.get(handle)
451 new_data = obj.serialize()
452 transaction.add(key, handle, old_data, new_data)
453 if old_data:
454 update_list.append((handle, new_data))
455 else:
456 add_list.append((handle, new_data))
457 return old_data
458
505
518
520 """
521 Commit the specified Source to the database, storing the changes as
522 part of the transaction.
523 """
524
525 self.commit_base(source, self.source_map, SOURCE_KEY,
526 transaction.source_update, transaction.source_add,
527 transaction, change_time)
528
529 self.source_media_types.update(
530 [str(ref.media_type) for ref in source.reporef_list
531 if ref.media_type.is_custom()])
532
533 attr_list = []
534 for mref in source.media_list:
535 attr_list += [str(attr.type) for attr in mref.attribute_list
536 if attr.type.is_custom() and str(attr.type)]
537 self.media_attributes.update(attr_list)
538
539 - def commit_place(self, place, transaction, change_time=None):
540 """
541 Commit the specified Place to the database, storing the changes as
542 part of the transaction.
543 """
544
545 self.commit_base(place, self.place_map, PLACE_KEY,
546 transaction.place_update, transaction.place_add,
547 transaction, change_time)
548
549 self.url_types.update([str(url.type) for url in place.urls
550 if url.type.is_custom()])
551
552 attr_list = []
553 for mref in place.media_list:
554 attr_list += [str(attr.type) for attr in mref.attribute_list
555 if attr.type.is_custom() and str(attr.type)]
556 self.media_attributes.update(attr_list)
557
562
567
568 - def commit_event(self, event, transaction, change_time=None):
569 """
570 Commit the specified Event to the database, storing the changes as
571 part of the transaction.
572 """
573 self.commit_base(event, self.event_map, EVENT_KEY,
574 transaction.event_update, transaction.event_add,
575 transaction, change_time)
576
577 attr_list = []
578 for mref in event.media_list:
579 attr_list += [str(attr.type) for attr in mref.attribute_list
580 if attr.type.is_custom() and str(attr.type)]
581 self.media_attributes.update(attr_list)
582
584 """
585 Commit the specified Family to the database, storing the changes as
586 part of the transaction.
587 """
588
589 self.commit_base(family, self.family_map, FAMILY_KEY,
590 transaction.family_update, transaction.family_add,
591 transaction, change_time)
592
593 self.family_attributes.update(
594 [str(attr.type) for attr in family.attribute_list
595 if attr.type.is_custom() and str(attr.type)])
596
597 rel_list = []
598 for ref in family.child_ref_list:
599 if ref.frel.is_custom():
600 rel_list.append(str(ref.frel))
601 if ref.mrel.is_custom():
602 rel_list.append(str(ref.mrel))
603 self.child_ref_types.update(rel_list)
604
605 self.event_role_names.update(
606 [str(eref.role) for eref in family.event_ref_list
607 if eref.role.is_custom()])
608
609 if family.type.is_custom():
610 self.family_rel_types.add(str(family.type))
611
612 attr_list = []
613 for mref in family.media_list:
614 attr_list += [str(attr.type) for attr in mref.attribute_list
615 if attr.type.is_custom() and str(attr.type)]
616 self.media_attributes.update(attr_list)
617
619 """
620 Commit the specified Repository to the database, storing the changes
621 as part of the transaction.
622 """
623 self.commit_base(repository, self.repository_map, REPOSITORY_KEY,
624 transaction.repository_update,
625 transaction.repository_add,
626 transaction, change_time)
627
628 if repository.type.is_custom():
629 self.repository_types.add(str(repository.type))
630
631 self.url_types.update([str(url.type) for url in repository.urls
632 if url.type.is_custom()])
633
634 - def commit_note(self, note, transaction, change_time=None):
635 """
636 Commit the specified Note to the database, storing the changes as part
637 of the transaction.
638 """
639 self.commit_base(note, self.note_map, NOTE_KEY,
640 transaction.note_update,
641 transaction.note_add,
642 transaction, change_time)
643
644 if note.type.is_custom():
645 self.note_types.add(str(note.type))
646
648 """
649 Return the next available GRAMPS' ID for a Person object based off the
650 person ID prefix.
651 """
652 index = self.person_prefix % self.pmap_index
653 while self.id_trans.has_key(str(index)):
654 self.pmap_index += 1
655 index = self.person_prefix % self.pmap_index
656 self.pmap_index += 1
657 return index
658
660 """
661 Return the next available GRAMPS' ID for a Place object based off the
662 place ID prefix.
663 """
664 index = self.place_prefix % self.lmap_index
665 while self.pid_trans.has_key(str(index)):
666 self.lmap_index += 1
667 index = self.place_prefix % self.lmap_index
668 self.lmap_index += 1
669 return index
670
672 """
673 Return the next available GRAMPS' ID for a Event object based off the
674 event ID prefix.
675 """
676 index = self.event_prefix % self.emap_index
677 while self.eid_trans.has_key(str(index)):
678 self.emap_index += 1
679 index = self.event_prefix % self.emap_index
680 self.emap_index += 1
681 return index
682
684 """
685 Return the next available GRAMPS' ID for a MediaObject object based
686 off the media object ID prefix.
687 """
688 index = self.mediaobject_prefix % self.omap_index
689 while self.oid_trans.has_key(str(index)):
690 self.omap_index += 1
691 index = self.mediaobject_prefix % self.omap_index
692 self.omap_index += 1
693 return index
694
696 """
697 Return the next available GRAMPS' ID for a Source object based off the
698 source ID prefix.
699 """
700 index = self.source_prefix % self.smap_index
701 while self.sid_trans.has_key(str(index)):
702 self.smap_index += 1
703 index = self.source_prefix % self.smap_index
704 self.smap_index += 1
705 return index
706
708 """
709 Return the next available GRAMPS' ID for a Family object based off the
710 family ID prefix.
711 """
712 index = self.family_prefix % self.fmap_index
713 while self.fid_trans.has_key(str(index)):
714 self.fmap_index += 1
715 index = self.family_prefix % self.fmap_index
716 self.fmap_index += 1
717 return index
718
720 """
721 Return the next available GRAMPS' ID for a Respository object based
722 off the repository ID prefix.
723 """
724 index = self.repository_prefix % self.rmap_index
725 while self.rid_trans.has_key(str(index)):
726 self.rmap_index += 1
727 index = self.repository_prefix % self.rmap_index
728 self.rmap_index += 1
729 return index
730
732 """
733 Return the next available GRAMPS' ID for a Note object based off the
734 note ID prefix.
735 """
736 index = self.note_prefix % self.nmap_index
737 while self.nid_trans.has_key(str(index)):
738 self.nmap_index += 1
739 index = self.note_prefix % self.nmap_index
740 self.nmap_index += 1
741 return index
742
744 data = data_map.get(str(handle))
745 if data:
746 newobj = class_type()
747 newobj.unserialize(data)
748 return newobj
749 return None
750
752 """
753 Find a Person in the database from the passed gramps' ID.
754
755 If no such Person exists, None is returned.
756 """
757 return self.get_from_handle(handle, Person, self.person_map)
758
760 """
761 Find a Source in the database from the passed gramps' ID.
762
763 If no such Source exists, None is returned.
764 """
765 return self.get_from_handle(handle, Source, self.source_map)
766
768 """
769 Find an Object in the database from the passed gramps' ID.
770
771 If no such Object exists, None is returned.
772 """
773 return self.get_from_handle(handle, MediaObject, self.media_map)
774
776 """
777 Find a Place in the database from the passed gramps' ID.
778
779 If no such Place exists, None is returned.
780 """
781 return self.get_from_handle(handle, Place, self.place_map)
782
784 """
785 Find a Event in the database from the passed gramps' ID.
786
787 If no such Event exists, None is returned.
788 """
789 return self.get_from_handle(handle, Event, self.event_map)
790
792 """
793 Find a Family in the database from the passed gramps' ID.
794
795 If no such Family exists, None is returned.
796 """
797 return self.get_from_handle(handle, Family, self.family_map)
798
800 """
801 Find a Repository in the database from the passed gramps' ID.
802
803 If no such Repository exists, None is returned.
804 """
805 return self.get_from_handle(handle, Repository, self.repository_map)
806
808 """
809 Find a Note in the database from the passed gramps' ID.
810
811 If no such Note exists, None is returned.
812 """
813 return self.get_from_handle(handle, Note, self.note_map)
814
815 - def find_from_handle(self, handle, transaction, class_type, dmap,
816 add_func):
817 """
818 Find a object of class_type in the database from the passed handle.
819
820 If no object exists, a new object is added to the database.
821
822 @return: Returns a tuple, first the object, second a bool which is True
823 if the object is new
824 @rtype: tuple
825 """
826 obj = class_type()
827 handle = str(handle)
828 new = True
829 if dmap.has_key(handle):
830 obj.unserialize(dmap.get(handle))
831
832 if obj.gramps_id is not None:
833 new = False
834 else:
835 obj.set_handle(handle)
836 add_func(obj, transaction)
837 return obj, new
838
839 - def __check_from_handle(self, handle, transaction, class_type, dmap,
840 add_func, set_gid=True):
841 handle = str(handle)
842 if not dmap.has_key(handle):
843 obj = class_type()
844 obj.set_handle(handle)
845 add_func(obj, transaction, set_gid=set_gid)
846
848 """
849 Find a Person in the database from the passed handle.
850
851 If no such Person exists, a new Person is added to the database.
852
853 @return: Returns a tuple, first the object, second a bool which is True
854 if the object is new
855 @rtype: tuple
856 """
857 return self.find_from_handle(handle, transaction, Person,
858 self.person_map, self.add_person)
859
861 """
862 Find a Source in the database from the passed handle.
863
864 If no such Source exists, a new Source is added to the database.
865
866 @return: Returns a tuple, first the object, second a bool which is True
867 if the object is new
868 @rtype: tuple
869 """
870 return self.find_from_handle(handle, transaction, Source,
871 self.source_map, self.add_source)
872
874 """
875 Find a Event in the database from the passed handle.
876
877 If no such Event exists, a new Event is added to the database.
878
879 @return: Returns a tuple, first the object, second a bool which is True
880 if the object is new
881 @rtype: tuple
882 """
883 return self.find_from_handle(handle, transaction, Event,
884 self.event_map, self.add_event)
885
887 """
888 Find a MediaObject in the database from the passed handle.
889
890 If no such MediaObject exists, a new Object is added to the database.
891
892 @return: Returns a tuple, first the object, second a bool which is True
893 if the object is new
894 @rtype: tuple
895 """
896 return self.find_from_handle(handle, transaction, MediaObject,
897 self.media_map, self.add_object)
898
900 """
901 Find a Place in the database from the passed handle.
902
903 If no such Place exists, a new Place is added to the database.
904
905 @return: Returns a tuple, first the object, second a bool which is True
906 if the object is new
907 @rtype: tuple
908 """
909 return self.find_from_handle(handle, transaction, Place,
910 self.place_map, self.add_place)
911
913 """
914 Find a Family in the database from the passed handle.
915
916 If no such Family exists, a new Family is added to the database.
917
918 @return: Returns a tuple, first the object, second a bool which is True
919 if the object is new
920 @rtype: tuple
921 """
922 return self.find_from_handle(handle, transaction, Family,
923 self.family_map, self.add_family)
924
926 """
927 Find a Repository in the database from the passed handle.
928
929 If no such Repository exists, a new Repository is added to the database.
930
931 @return: Returns a tuple, first the object, second a bool which is True
932 if the object is new
933 @rtype: tuple
934 """
935 return self.find_from_handle(handle, transaction, Repository,
936 self.repository_map, self.add_repository)
937
939 """
940 Find a Note in the database from the passed handle.
941
942 If no such Note exists, a new Note is added to the database.
943
944 @return: Returns a tuple, first the object, second a bool which is True
945 if the object is new
946 @rtype: tuple
947 """
948 return self.find_from_handle(handle, transaction, Note,
949 self.note_map, self.add_note)
950
952 """
953 Check whether a Person with the passed handle exists in the database.
954
955 If no such Person exists, a new Person is added to the database.
956 If set_gid then a new gramps_id is created, if not, None is used.
957 """
958 self.__check_from_handle(handle, transaction, Person,
959 self.person_map, self.add_person,
960 set_gid = set_gid)
961
963 """
964 Check whether a Source with the passed handle exists in the database.
965
966 If no such Source exists, a new Source is added to the database.
967 If set_gid then a new gramps_id is created, if not, None is used.
968 """
969 self.__check_from_handle(handle, transaction, Source,
970 self.source_map, self.add_source,
971 set_gid=set_gid)
972
974 """
975 Check whether an Event with the passed handle exists in the database.
976
977 If no such Event exists, a new Event is added to the database.
978 If set_gid then a new gramps_id is created, if not, None is used.
979 """
980 self.__check_from_handle(handle, transaction, Event,
981 self.event_map, self.add_event,
982 set_gid=set_gid)
983
985 """
986 Check whether a MediaObject with the passed handle exists in the
987 database.
988
989 If no such MediaObject exists, a new Object is added to the database.
990 If set_gid then a new gramps_id is created, if not, None is used.
991 """
992
993 self.__check_from_handle(handle, transaction, MediaObject,
994 self.media_map, self.add_object,
995 set_gid=set_gid)
996
998 """
999 Check whether a Place with the passed handle exists in the database.
1000
1001 If no such Place exists, a new Place is added to the database.
1002 If set_gid then a new gramps_id is created, if not, None is used.
1003 """
1004 self.__check_from_handle(handle, transaction, Place,
1005 self.place_map, self.add_place,
1006 set_gid=set_gid)
1007
1009 """
1010 Check whether a Family with the passed handle exists in the database.
1011
1012 If no such Family exists, a new Family is added to the database.
1013 If set_gid then a new gramps_id is created, if not, None is used.
1014 """
1015 self.__check_from_handle(handle, transaction, Family,
1016 self.family_map, self.add_family,
1017 set_gid=set_gid)
1018
1020 """
1021 Check whether a Repository with the passed handle exists in the
1022 database.
1023
1024 If no such Repository exists, a new Repository is added to the database.
1025 If set_gid then a new gramps_id is created, if not, None is used.
1026 """
1027 self.__check_from_handle(handle, transaction, Repository,
1028 self.repository_map, self.add_repository,
1029 set_gid=set_gid)
1030
1032 """
1033 Check whether a Note with the passed handle exists in the database.
1034
1035 If no such Note exists, a new Note is added to the database.
1036 If set_gid then a new gramps_id is created, if not, None is used.
1037 """
1038 self.__check_from_handle(handle, transaction, Note,
1039 self.note_map, self.add_note,
1040 set_gid=set_gid)
1041
1043 """
1044 Find a Person in the database from the passed GRAMPS ID.
1045
1046 If no such Person exists, None is returned.
1047 Needs to be overridden by the derrived class.
1048 """
1049 raise NotImplementedError
1050
1052 """
1053 Find a Family in the database from the passed GRAMPS ID.
1054
1055 If no such Family exists, None is returned.
1056 Need to be overridden by the derrived class.
1057 """
1058 raise NotImplementedError
1059
1061 """
1062 Find an Event in the database from the passed GRAMPS ID.
1063
1064 If no such Event exists, None is returned.
1065 Needs to be overridden by the derrived class.
1066 """
1067 raise NotImplementedError
1068
1070 """
1071 Find a Place in the database from the passed gramps' ID.
1072
1073 If no such Place exists, None is returned.
1074 Needs to be overridden by the derrived class.
1075 """
1076 raise NotImplementedError
1077
1079 """
1080 Find a Source in the database from the passed gramps' ID.
1081
1082 If no such Source exists, None is returned.
1083 Needs to be overridden by the derrived class.
1084 """
1085 raise NotImplementedError
1086
1088 """
1089 Find a MediaObject in the database from the passed gramps' ID.
1090
1091 If no such MediaObject exists, None is returned.
1092 Needs to be overridden by the derrived class.
1093 """
1094 raise NotImplementedError
1095
1097 """
1098 Find a Repository in the database from the passed gramps' ID.
1099
1100 If no such Repository exists, None is returned.
1101 Needs to be overridden by the derrived class.
1102 """
1103 raise NotImplementedError
1104
1106 """
1107 Find a Note in the database from the passed gramps' ID.
1108
1109 If no such Note exists, None is returned.
1110 Needs to be overridden by the derrived class.
1111 """
1112 raise NotImplementedError
1113
1114 - def __add_object(self, obj, transaction, find_next_func, commit_func):
1115 if find_next_func and not obj.gramps_id:
1116 obj.gramps_id = find_next_func()
1117 if not obj.handle:
1118 obj.handle = self.create_id()
1119 commit_func(obj, transaction)
1120 if obj.__class__.__name__ == 'Person':
1121 self.genderStats.count_person (obj)
1122 return obj.handle
1123
1124 - def add_person(self, person, transaction, set_gid=True):
1125 """
1126 Add a Person to the database, assigning internal IDs if they have
1127 not already been defined.
1128
1129 If not set_gid, then gramps_id is not set.
1130 """
1131 if set_gid:
1132 return self.__add_object(person, transaction,
1133 self.find_next_person_gramps_id,
1134 self.commit_person)
1135 else:
1136 return self.__add_object(person, transaction,
1137 None,
1138 self.commit_person)
1139
1140 - def add_family(self, family, transaction, set_gid=True):
1141 """
1142 Add a Family to the database, assigning internal IDs if they have
1143 not already been defined.
1144
1145 If not set_gid, then gramps_id is not set.
1146 """
1147 if set_gid:
1148 return self.__add_object(family, transaction,
1149 self.find_next_family_gramps_id,
1150 self.commit_family)
1151 else:
1152 return self.__add_object(family, transaction,
1153 None,
1154 self.commit_family)
1155
1156 - def add_source(self, source, transaction, set_gid=True):
1157 """
1158 Add a Source to the database, assigning internal IDs if they have
1159 not already been defined.
1160
1161 If not set_gid, then gramps_id is not set.
1162 """
1163 if set_gid:
1164 return self.__add_object(source, transaction,
1165 self.find_next_source_gramps_id,
1166 self.commit_source)
1167 else :
1168 return self.__add_object(source, transaction,
1169 None,
1170 self.commit_source)
1171
1172 - def add_event(self, event, transaction, set_gid=True):
1173 """
1174 Add an Event to the database, assigning internal IDs if they have
1175 not already been defined.
1176
1177 If not set_gid, then gramps_id is not set.
1178 """
1179 if set_gid:
1180 return self.__add_object(event, transaction,
1181 self.find_next_event_gramps_id,
1182 self.commit_event)
1183 else:
1184 return self.__add_object(event, transaction,
1185 None,
1186 self.commit_event)
1187
1189 """
1190 Add an Event to the database, assigning internal IDs if they have
1191 not already been defined.
1192 """
1193 if event.type.is_custom():
1194 self.individual_event_names.add(str(event.type))
1195 return self.add_event(event, transaction)
1196
1198 """
1199 Add an Event to the database, assigning internal IDs if they have
1200 not already been defined.
1201 """
1202 if event.type.is_custom():
1203 self.family_event_names.add(str(event.type))
1204 return self.add_event(event, transaction)
1205
1206 - def add_place(self, place, transaction, set_gid=True):
1207 """
1208 Add a Place to the database, assigning internal IDs if they have
1209 not already been defined.
1210
1211 If not set_gid, then gramps_id is not set.
1212 """
1213 if set_gid:
1214 return self.__add_object(place, transaction,
1215 self.find_next_place_gramps_id,
1216 self.commit_place)
1217 else:
1218 return self.__add_object(place, transaction,
1219 None,
1220 self.commit_place)
1221
1222 - def add_object(self, obj, transaction, set_gid=True):
1223 """
1224 Add a MediaObject to the database, assigning internal IDs if they have
1225 not already been defined.
1226
1227 If not set_gid, then gramps_id is not set.
1228 """
1229 if set_gid:
1230 return self.__add_object(obj, transaction,
1231 self.find_next_object_gramps_id,
1232 self.commit_media_object)
1233 else:
1234 return self.__add_object(obj, transaction,
1235 None,
1236 self.commit_media_object)
1237
1239 """
1240 Add a Repository to the database, assigning internal IDs if they have
1241 not already been defined.
1242
1243 If not set_gid, then gramps_id is not set.
1244 """
1245 if set_gid:
1246 return self.__add_object(obj, transaction,
1247 self.find_next_repository_gramps_id,
1248 self.commit_repository)
1249 else:
1250 return self.__add_object(obj, transaction,
1251 None,
1252 self.commit_repository)
1253
1254 - def add_note(self, obj, transaction, set_gid=True):
1255 """
1256 Add a Note to the database, assigning internal IDs if they have
1257 not already been defined.
1258
1259 If not set_gid, then gramps_id is not set.
1260 """
1261 if set_gid:
1262 return self.__add_object(obj, transaction,
1263 self.find_next_note_gramps_id,
1264 self.commit_note)
1265 else:
1266 return self.__add_object(obj, transaction,
1267 None,
1268 self.commit_note)
1269
1271 """
1272 Return the default grouping name for a surname.
1273 """
1274 return unicode(self.name_group.get(str(name), name))
1275
1277 """
1278 Return the defined names that have been assigned to a default grouping.
1279 """
1280 return [unicode(k) for k in self.name_group.keys()]
1281
1283 """
1284 Return if a key exists in the name_group table.
1285 """
1286 return self.name_group.has_key(str(name))
1287
1289 """
1290 Set the default grouping name for a surname.
1291
1292 Needs to be overridden in the derived class.
1293 """
1294 raise NotImplementedError
1295
1297 """
1298 Return the number of people currently in the database.
1299 """
1300 if self.db_is_open:
1301 return len(self.person_map)
1302 else:
1303 return 0
1304
1306 """
1307 Return the number of families currently in the database.
1308 """
1309 return len(self.family_map)
1310
1312 """
1313 Return the number of events currently in the database.
1314 """
1315 return len(self.event_map)
1316
1318 """
1319 Return the number of places currently in the database.
1320 """
1321 return len(self.place_map)
1322
1324 """
1325 Return the number of sources currently in the database.
1326 """
1327 return len(self.source_map)
1328
1334
1336 """
1337 Return the number of source repositories currently in the database.
1338 """
1339 return len(self.repository_map)
1340
1342 """
1343 Return the number of notes currently in the database.
1344 """
1345 return len(self.note_map)
1346
1349
1351 """
1352 Return a list of database handles, one handle for each Person in
1353 the database.
1354
1355 If sort_handles is True, the list is sorted by surnames.
1356 """
1357 if self.db_is_open:
1358 if sort_handles:
1359 slist = []
1360 cursor = self.get_person_cursor()
1361 data = cursor.first()
1362 while data:
1363 slist.append((data[1][3][3], data[0]))
1364 data = cursor.next()
1365 cursor.close()
1366 slist.sort()
1367 return map(lambda x: x[1], slist)
1368 else:
1369 return self.all_handles(self.person_map)
1370 return []
1371
1373 """
1374 Return a list of database handles, one handle for each Place in
1375 the database.
1376
1377 If sort_handles is True, the list is sorted by Place title.
1378 """
1379 if self.db_is_open:
1380 if sort_handles:
1381 slist = []
1382 cursor = self.get_place_cursor()
1383 data = cursor.first()
1384 while data:
1385 slist.append((data[1][2], data[0]))
1386 data = cursor.next()
1387 cursor.close()
1388 slist.sort()
1389 val = map(lambda x: x[1], slist)
1390 return val
1391 else:
1392 return self.all_handles(self.place_map)
1393 return []
1394
1396 """
1397 Return a list of database handles, one handle for each Source in
1398 the database.
1399
1400 If sort_handles is True, the list is sorted by Source title.
1401 """
1402 if self.db_is_open:
1403 handle_list = self.all_handles(self.source_map)
1404 if sort_handles:
1405 handle_list.sort(self.__sortbysource)
1406 return handle_list
1407 return []
1408
1422
1424 """
1425 Return a list of database handles, one handle for each Event in the
1426 database.
1427 """
1428 if self.db_is_open:
1429 return self.all_handles(self.event_map)
1430 return []
1431
1433 """
1434 Return a list of database handles, one handle for each Family in
1435 the database.
1436 """
1437 if self.db_is_open:
1438 return self.all_handles(self.family_map)
1439 return []
1440
1442 """
1443 Return a list of database handles, one handle for each Repository in
1444 the database.
1445 """
1446 if self.db_is_open:
1447 return self.all_handles(self.repository_map)
1448 return []
1449
1451 """
1452 Return a list of database handles, one handle for each Note in the
1453 database.
1454 """
1455 if self.db_is_open:
1456 return self.all_handles(self.note_map)
1457 return []
1458
1473
1488
1496
1498 if val:
1499 try:
1500 junk = val % 1
1501 prefix_var = val
1502 except:
1503 try:
1504 val = val + "%d"
1505 junk = val % 1
1506 prefix_var = val
1507 except:
1508 prefix_var = default+"%04d"
1509 else:
1510 prefix_var = default+"%04d"
1511 return prefix_var
1512
1514 """
1515 Set the naming template for GRAMPS Person ID values.
1516
1517 The string is expected to be in the form of a simple text string, or
1518 in a format that contains a C/Python style format string using %d,
1519 such as I%d or I%04d.
1520 """
1521 self.person_prefix = self._validated_id_prefix(val, "I")
1522
1524 """
1525 Set the naming template for GRAMPS Source ID values.
1526
1527 The string is expected to be in the form of a simple text string, or
1528 in a format that contains a C/Python style format string using %d,
1529 such as S%d or S%04d.
1530 """
1531 self.source_prefix = self._validated_id_prefix(val, "S")
1532
1534 """
1535 Set the naming template for GRAMPS MediaObject ID values.
1536
1537 The string is expected to be in the form of a simple text string, or
1538 in a format that contains a C/Python style format string using %d,
1539 such as O%d or O%04d.
1540 """
1541 self.mediaobject_prefix = self._validated_id_prefix(val, "O")
1542
1544 """
1545 Set the naming template for GRAMPS Place ID values.
1546
1547 The string is expected to be in the form of a simple text string, or
1548 in a format that contains a C/Python style format string using %d,
1549 such as P%d or P%04d.
1550 """
1551 self.place_prefix = self._validated_id_prefix(val, "P")
1552
1554 """
1555 Set the naming template for GRAMPS Family ID values. The string is
1556 expected to be in the form of a simple text string, or in a format
1557 that contains a C/Python style format string using %d, such as F%d
1558 or F%04d.
1559 """
1560 self.family_prefix = self._validated_id_prefix(val, "F")
1561
1563 """
1564 Set the naming template for GRAMPS Event ID values.
1565
1566 The string is expected to be in the form of a simple text string, or
1567 in a format that contains a C/Python style format string using %d,
1568 such as E%d or E%04d.
1569 """
1570 self.event_prefix = self._validated_id_prefix(val, "E")
1571
1573 """
1574 Set the naming template for GRAMPS Repository ID values.
1575
1576 The string is expected to be in the form of a simple text string, or
1577 in a format that contains a C/Python style format string using %d,
1578 such as R%d or R%04d.
1579 """
1580 self.repository_prefix = self._validated_id_prefix(val, "R")
1581
1583 """
1584 Set the naming template for GRAMPS Note ID values.
1585
1586 The string is expected to be in the form of a simple text string, or
1587 in a format that contains a C/Python style format string using %d,
1588 such as N%d or N%04d.
1589 """
1590 self.note_prefix = self._validated_id_prefix(val, "N")
1591
1593 """
1594 Create a new Transaction tied to the current UNDO database.
1595
1596 The transaction has no effect until it is committed using the
1597 transaction_commit function of the this database object.
1598 """
1599 if self._LOG_ALL:
1600 LOG.debug("%s: Transaction begin '%s'\n"
1601 % (self.__class__.__name__, str(msg)))
1602 if batch:
1603
1604
1605 self.abort_possible = False
1606 self.undo_history_timestamp = time.time()
1607
1608 self.undoindex = -1
1609 self.translist = [None] * _UNDO_SIZE
1610 return Transaction(msg, self.undodb, batch)
1611
1613 """
1614 Commit the transaction to the assocated UNDO database.
1615 """
1616 if self._LOG_ALL:
1617 LOG.debug("%s: Transaction commit '%s'\n"
1618 % (self.__class__.__name__, str(msg)))
1619
1620 if not len(transaction) or self.readonly:
1621 return
1622
1623 transaction.set_description(msg)
1624 transaction.timestamp = time.time()
1625 self.undoindex += 1
1626 if self.undoindex >= _UNDO_SIZE:
1627
1628
1629 self.abort_possible = False
1630 self.undo_history_timestamp = time.time()
1631 self.translist = self.translist[0:-1] + [ transaction ]
1632 else:
1633 self.translist[self.undoindex] = transaction
1634
1635
1636 for index in range(self.undoindex+1, _UNDO_SIZE):
1637 self.translist[index] = None
1638
1639 person_add = self.do_commit(transaction.person_add, self.person_map)
1640 family_add = self.do_commit(transaction.family_add, self.family_map)
1641 source_add = self.do_commit(transaction.source_add, self.source_map)
1642 place_add = self.do_commit(transaction.place_add, self.place_map)
1643 media_add = self.do_commit(transaction.media_add, self.media_map)
1644 event_add = self.do_commit(transaction.event_add, self.event_map)
1645 repository_add = self.do_commit(transaction.repository_add,
1646 self.repository_map)
1647
1648 note_add = self.do_commit(transaction.note_add, self.note_map)
1649 person_upd = self.do_commit(transaction.person_update, self.person_map)
1650 family_upd = self.do_commit(transaction.family_update, self.family_map)
1651 source_upd = self.do_commit(transaction.source_update, self.source_map)
1652 place_upd = self.do_commit(transaction.place_update, self.place_map)
1653 media_upd = self.do_commit(transaction.media_update, self.media_map)
1654 event_upd = self.do_commit(transaction.event_update, self.event_map)
1655 repository_upd = self.do_commit(transaction.repository_update,
1656 self.repository_map)
1657 note_upd = self.do_commit(transaction.note_update, self.note_map)
1658
1659 self.__do_emit('person', person_add, person_upd, transaction.person_del)
1660 self.__do_emit('family', family_add, family_upd, transaction.family_del)
1661 self.__do_emit('event', event_add, event_upd, transaction.event_del)
1662 self.__do_emit('source', source_add, source_upd, transaction.source_del)
1663 self.__do_emit('place', place_add, place_upd, transaction.place_del)
1664 self.__do_emit('media', media_add, media_upd, transaction.media_del)
1665 self.__do_emit('repository', repository_add, repository_upd,
1666 transaction.repository_del)
1667 self.__do_emit('note', note_add, note_upd, transaction.note_del)
1668
1669 self.__do_del(transaction.person_del, self.del_person)
1670 self.__do_del(transaction.family_del, self.del_family)
1671 self.__do_del(transaction.place_del, self.del_place)
1672 self.__do_del(transaction.source_del, self.del_source)
1673 self.__do_del(transaction.event_del, self.del_event)
1674 self.__do_del(transaction.media_del, self.del_media)
1675 self.__do_del(transaction.repository_del, self.del_repository)
1676 self.__do_del(transaction.note_del, self.del_note)
1677
1678 if self.undo_callback:
1679 self.undo_callback(_("_Undo %s") % transaction.get_description())
1680 if self.redo_callback:
1681 self.redo_callback(None)
1682 if self.undo_history_callback:
1683 self.undo_history_callback()
1684
1685 - def __do_emit(self, objtype, add_list, upd_list, del_list):
1686 if add_list:
1687 self.emit(objtype + '-add', (add_list, ))
1688 if upd_list:
1689 self.emit(objtype + '-update', (upd_list, ))
1690 if del_list:
1691 self.emit(objtype + '-delete', (del_list, ))
1692
1694 for handle in del_list:
1695 func(handle)
1696 return del_list
1697
1699 retlist = []
1700 for (handle, data) in add_list:
1701 db_map[handle] = data
1702 retlist.append(str(handle))
1703 return retlist
1704
1706 """
1707 Return boolean of whether or not there's a possibility of undo.
1708 """
1709 if self.undoindex == -1 or self.readonly:
1710 return False
1711 return True
1712
1714 """
1715 Return boolean of whether or not there's a possibility of redo.
1716 """
1717 if self.undoindex >= _UNDO_SIZE or self.readonly:
1718 return False
1719
1720 if self.translist[self.undoindex+1] == None:
1721 return False
1722
1723 return True
1724
1725 - def undo(self, update_history=True):
1726 """
1727 Access the last committed transaction, and revert the data to the
1728 state before the transaction was committed.
1729 """
1730 if not self.undo_available():
1731 return False
1732
1733 transaction = self.translist[self.undoindex]
1734
1735 mapbase = (self.person_map, self.family_map, self.source_map,
1736 self.event_map, self.media_map, self.place_map,
1737 self.repository_map, {}, self.note_map)
1738
1739 self.undoindex -= 1
1740 subitems = transaction.get_recnos()
1741 subitems.reverse()
1742 for record_id in subitems:
1743 (key, handle, old_data, new_data) = transaction.get_record(record_id)
1744 if key == REFERENCE_KEY:
1745 self.undo_reference(old_data, handle)
1746 else:
1747 self.undo_data(old_data, handle, mapbase[key], _SIGBASE[key])
1748
1749 if self.undo_callback:
1750 if self.undo_available():
1751 new_transaction = self.translist[self.undoindex]
1752 self.undo_callback(_("_Undo %s")
1753 % new_transaction.get_description())
1754 else:
1755 self.undo_callback(None)
1756
1757 if self.redo_callback:
1758 if self. redo_available():
1759 self.redo_callback(_("_Redo %s")
1760 % transaction.get_description())
1761 else:
1762 self.redo_callback(None)
1763
1764 if update_history and self.undo_history_callback:
1765 self.undo_history_callback()
1766 return True
1767
1768 - def redo(self, update_history=True):
1769 """
1770 Accesse the last undone transaction, and revert the data to the state
1771 before the transaction was undone.
1772 """
1773
1774 if not self.redo_available():
1775 return False
1776
1777 self.undoindex += 1
1778 transaction = self.translist[self.undoindex]
1779 mapbase = (self.person_map, self.family_map, self.source_map,
1780 self.event_map, self.media_map, self.place_map,
1781 self.repository_map, {}, self.note_map)
1782
1783 subitems = transaction.get_recnos()
1784 for record_id in subitems:
1785 (key, handle, old_data, new_data) = transaction.get_record(record_id)
1786 if key == REFERENCE_KEY:
1787 self.undo_reference(new_data, handle)
1788 else:
1789 self.undo_data(new_data, handle, mapbase[key], _SIGBASE[key])
1790
1791 if self.undo_callback:
1792 if self.undo_available():
1793 self.undo_callback(_("_Undo %s")
1794 % transaction.get_description())
1795 else:
1796 self.undo_callback(None)
1797
1798 if self.redo_callback:
1799 if self.redo_available():
1800 new_transaction = self.translist[self.undoindex+1]
1801 self.redo_callback(_("_Redo %s")
1802 % new_transaction.get_description())
1803 else:
1804 self.redo_callback(None)
1805
1806 if update_history and self.undo_history_callback:
1807 self.undo_history_callback()
1808 return True
1809
1812
1813 - def undo_data(self, data, handle, db_map, signal_root):
1814 if data == None:
1815 self.emit(signal_root + '-delete', ([handle], ))
1816 del db_map[handle]
1817 else:
1818 if db_map.has_key(handle):
1819 signal = signal_root + '-update'
1820 else:
1821 signal = signal_root + '-add'
1822 db_map[handle] = data
1823 self.emit(signal, ([handle], ))
1824
1826 """
1827 Define the callback function that is called whenever an undo operation
1828 is executed.
1829
1830 The callback function receives a single argument that is a text string
1831 that defines the operation.
1832 """
1833 self.undo_callback = callback
1834
1836 """
1837 Define the callback function that is called whenever an redo operation
1838 is executed.
1839
1840 The callback function receives a single argument that is a text string
1841 that defines the operation.
1842 """
1843 self.redo_callback = callback
1844
1846 """
1847 Return the list of locale-sorted surnames contained in the database.
1848 """
1849 return self.surname_list
1850
1852 """
1853 Build the list of locale-sorted surnames contained in the database.
1854
1855 The function must be overridden in the derived class.
1856 """
1857 raise NotImplementedError
1858
1860 vals = [(locale.strxfrm(item), item) for item in self.surname_list]
1861 vals.sort()
1862 self.surname_list = [item[1] for item in vals]
1863
1871
1873 """
1874 Check whether there are persons with the same surname left in
1875 the database.
1876
1877 If not then we need to remove the name from the list.
1878 The function must be overridden in the derived class.
1879 """
1880 raise NotImplementedError
1881
1883 """Return the list of Person handles in the bookmarks."""
1884 return self.bookmarks
1885
1887 """Return the list of Person handles in the bookmarks."""
1888 return self.family_bookmarks
1889
1891 """Return the list of Person handles in the bookmarks."""
1892 return self.event_bookmarks
1893
1895 """Return the list of Person handles in the bookmarks."""
1896 return self.place_bookmarks
1897
1899 """Return the list of Person handles in the bookmarks."""
1900 return self.source_bookmarks
1901
1905
1907 """Return the list of Person handles in the bookmarks."""
1908 return self.repo_bookmarks
1909
1911 """Return the list of Note handles in the bookmarks."""
1912 return self.note_bookmarks
1913
1915 """Set the information about the owner of the database."""
1916 self.owner.set_from(owner)
1917
1919 """
1920 Return the Researcher instance, providing information about the owner
1921 of the database.
1922 """
1923 return self.owner
1924
1926 """Set the default Person to the passed instance."""
1927 if (self.metadata != None) and (not self.readonly):
1928 self.metadata['default'] = str(handle)
1929
1938
1940 """Return the default Person of the database."""
1941 if self.metadata != None:
1942 return self.metadata.get('default')
1943 return None
1944
1946 """Return the save path of the file, or "" if one does not exist."""
1947 return self.path
1948
1950 """Set the save path for the database."""
1951 self.path = path
1952
1954 """
1955 Return a list of all Event types assocated with Person instances in
1956 the database.
1957 """
1958 return list(self.individual_event_names)
1959
1961 """
1962 Return a list of all Attribute types assocated with Person instances
1963 in the database.
1964 """
1965 return list(self.individual_attributes)
1966
1968 """
1969 Return a list of all Attribute types assocated with Family instances
1970 in the database.
1971 """
1972 return list(self.family_attributes)
1973
1975 """
1976 Return a list of all Event types assocated with Family instances in
1977 the database.
1978 """
1979 return list(self.family_event_names)
1980
1982 """
1983 Return a list of all marker types available in the database.
1984 """
1985 return list(self.marker_names)
1986
1993
1995 """
1996 Return a list of all relationship types assocated with Family
1997 instances in the database.
1998 """
1999 return list(self.family_rel_types)
2000
2002 """
2003 Return a list of all child reference types assocated with Family
2004 instances in the database.
2005 """
2006 return list(self.child_ref_types)
2007
2009 """
2010 Return a list of all custom event role names assocated with Event
2011 instances in the database.
2012 """
2013 return list(self.event_role_names)
2014
2016 """
2017 Return a list of all custom names types assocated with Person
2018 instances in the database.
2019 """
2020 return list(self.name_types)
2021
2023 """
2024 Return a list of all custom repository types assocated with Repository
2025 instances in the database.
2026 """
2027 return list(self.repository_types)
2028
2030 """
2031 Return a list of all custom note types assocated with Note instances
2032 in the database.
2033 """
2034 return list(self.note_types)
2035
2042
2044 """
2045 Return a list of all custom names types assocated with Url instances
2046 in the database.
2047 """
2048 return list(self.url_types)
2049
2069
2082
2084 if self.readonly or not handle:
2085 return
2086
2087 handle = str(handle)
2088 self.delete_primary_from_reference_map(handle, trans)
2089 if trans.batch:
2090 del_func = self.get_del_func(key)
2091 del_func(handle)
2092 else:
2093 old_data = dmap.get(handle)
2094 trans.add(key, handle, old_data, None)
2095 del_list.append(handle)
2096
2098 """
2099 Remove the Source specified by the database handle from the
2100 database, preserving the change in the passed transaction.
2101
2102 This method must be overridden in the derived class.
2103 """
2104 self.do_remove_object(handle, transaction, self.source_map,
2105 SOURCE_KEY, transaction.source_del)
2106
2108 """
2109 Remove the Event specified by the database handle from the
2110 database, preserving the change in the passed transaction.
2111
2112 This method must be overridden in the derived class.
2113 """
2114 self.do_remove_object(handle, transaction, self.event_map,
2115 EVENT_KEY, transaction.event_del)
2116
2118 """
2119 Remove the MediaObjectPerson specified by the database handle from the
2120 database, preserving the change in the passed transaction.
2121
2122 This method must be overridden in the derived class.
2123 """
2124 self.do_remove_object(handle, transaction, self.media_map,
2125 MEDIA_KEY, transaction.media_del)
2126
2128 """
2129 Remove the Place specified by the database handle from the
2130 database, preserving the change in the passed transaction.
2131
2132 This method must be overridden in the derived class.
2133 """
2134 self.do_remove_object(handle, transaction, self.place_map,
2135 PLACE_KEY, transaction.place_del)
2136
2138 """
2139 Remove the Family specified by the database handle from the
2140 database, preserving the change in the passed transaction.
2141
2142 This method must be overridden in the derived class.
2143 """
2144 self.do_remove_object(handle, transaction, self.family_map,
2145 FAMILY_KEY, transaction.family_del)
2146
2148 """
2149 Remove the Repository specified by the database handle from the
2150 database, preserving the change in the passed transaction.
2151
2152 This method must be overridden in the derived class.
2153 """
2154 self.do_remove_object(handle, transaction, self.repository_map,
2155 REPOSITORY_KEY, transaction.repository_del)
2156
2158 """
2159 Remove the Note specified by the database handle from the
2160 database, preserving the change in the passed transaction.
2161
2162 This method must be overridden in the derived class.
2163 """
2164 self.do_remove_object(handle, transaction, self.note_map,
2165 NOTE_KEY, transaction.note_del)
2166
2168 return self.person_map.get(str(handle))
2169
2171 return self.family_map.get(str(handle))
2172
2174 return self.media_map.get(str(handle))
2175
2177 return self.place_map.get(str(handle))
2178
2180 return self.event_map.get(str(handle))
2181
2183 return self.source_map.get(str(handle))
2184
2186 return self.repository_map.get(str(handle))
2187
2189 return self.note_map.get(str(handle))
2190
2192 """
2193 Return True if the handle exists in the current Person database.
2194 """
2195 return self.person_map.has_key(str(handle))
2196
2198 """
2199 Return True if the handle exists in the current Event database.
2200 """
2201 return self.event_map.has_key(str(handle))
2202
2204 """
2205 Return True if the handle exists in the current Source database.
2206 """
2207 return self.source_map.has_key(str(handle))
2208
2210 """
2211 Return True if the handle exists in the current Place database.
2212 """
2213 return self.place_map.has_key(str(handle))
2214
2216 """
2217 Return True if the handle exists in the current Family database.
2218 """
2219 return self.family_map.has_key(str(handle))
2220
2222 """
2223 Return True if the handle exists in the current MediaObjectdatabase.
2224 """
2225 return self.media_map.has_key(str(handle))
2226
2228 """
2229 Return True if the handle exists in the current Repository database.
2230 """
2231 return self.repository_map.has_key(str(handle))
2232
2234 """
2235 Return True if the handle exists in the current Note database.
2236 """
2237 return self.note_map.has_key(str(handle))
2238
2240 return locale.strcoll(self.place_map.get(str(first))[2],
2241 self.place_map.get(str(second))[2])
2242
2244 source1 = unicode(self.source_map[str(first)][2])
2245 source2 = unicode(self.source_map[str(second)][2])
2246 return locale.strcoll(source1, source2)
2247
2252
2257
2263
2265 if (self.metadata != None) and (not self.readonly):
2266 self.metadata[name] = col_list
2267
2273
2279
2281 """
2282 Store the Person display common information in the database's metadata.
2283 """
2284 self.set_column_order(col_list, CHILD_COL_KEY)
2285
2287 """
2288 Store the Place display common information in the database's metadata.
2289 """
2290 self.set_column_order(col_list, PLACE_COL_KEY)
2291
2297
2303
2305 """
2306 Store the Event display common information in the database's metadata.
2307 """
2308 self.set_column_order(col_list, EVENT_COL_KEY)
2309
2316
2318 """
2319 Store the Note display common information in the database's metadata.
2320 """
2321 self.set_column_order(col_list, NOTE_COL_KEY)
2322
2324 if self.metadata == None:
2325 return default
2326 else:
2327 cols = self.metadata.get(name, default)
2328 if len(cols) != len(default):
2329 return cols + default[len(cols):]
2330 else:
2331 return cols
2332
2334 """
2335 Return the Person display common information stored in the database's
2336 metadata.
2337 """
2338 default = [(1, 1, 100), (1, 2, 100), (1, 3, 150), (0, 4, 150),
2339 (1, 5, 150), (0, 6, 150), (0, 7, 100), (0, 8, 100),
2340 ]
2341 return self.__get_column_order(PERSON_COL_KEY, default)
2342
2344 values = self.__get_column_order(key, default)
2345 new = []
2346 for val in values:
2347 if len(val) == 2:
2348 for x in default:
2349 if val[1] == x[1]:
2350 new.append((val[0], val[1], x[2]))
2351 break
2352 else:
2353 new.append(val)
2354 return new
2355
2357 """
2358 Return the Person display common information stored in the database's
2359 metadata.
2360 """
2361 default = [(1, 0, 75), (1, 1, 200), (1, 2, 200), (1, 3, 100),
2362 (0, 4, 100)]
2363 return self.__get_columns(FAMILY_COL_KEY, default)
2364
2366 """
2367 Return the Person display common information stored in the database's
2368 metadata.
2369 """
2370 default = [(1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
2371 (0, 6), (0, 7)]
2372 return self.__get_column_order(CHILD_COL_KEY, default)
2373
2375 """
2376 Return the Place display common information stored in thedatabase's
2377 metadata.
2378 """
2379 default = [(1, 0, 250), (1, 1, 75), (1, 11, 100), (0, 3, 100),
2380 (1, 4, 100, ), (0, 5, 150), (1, 6, 150), (0, 7, 150),
2381 (0, 8, 150), (0, 9, 150), (0, 10, 150),(0,2,100)]
2382 return self.__get_columns(PLACE_COL_KEY, default)
2383
2385 """
2386 Return the Source display common information stored in the database's
2387 metadata.
2388 """
2389 default = [(1, 0, 200), (1, 1, 75), (1, 2, 150), (0, 3, 100),
2390 (1, 4, 150), (0, 5, 100)]
2391 return self.__get_columns(SOURCE_COL_KEY, default)
2392
2401
2403 """
2404 Return the Event display common information stored in the database's
2405 metadata.
2406 """
2407 default = [(1, 0, 200), (1, 1, 75), (1, 2, 100), (1, 3, 150),
2408 (1, 4, 200), (0, 5, 100)]
2409 return self.__get_columns(EVENT_COL_KEY, default)
2410
2412 """
2413 Return the Repository display common information stored in the
2414 database's metadata.
2415 """
2416 default = [(1, 0, 200), (1, 1, 75), (0, 5, 100), (0, 6, 100),
2417 (1, 2, 100), (1, 3, 250), (1, 4, 100), (0, 7, 100),
2418 (0, 8, 100), (0, 9, 100), (0, 10, 100), (0, 12, 100)]
2419 return self.__get_columns(REPOSITORY_COL_KEY, default)
2420
2422 """
2423 Return the Note display common information stored in the database's
2424 metadata.
2425 """
2426 default = [(1, 0, 350), (1, 1, 75), (1, 2, 100), (1, 3, 100)]
2427 return self.__get_columns(NOTE_COL_KEY, default)
2428
2430 """
2431 Called each time an object is removed from the database.
2432
2433 This can be used by subclasses to update any additional index tables
2434 that might need to be changed.
2435 """
2436 pass
2437
2439 """
2440 Called each time an object is writen to the database.
2441
2442 This can be used by subclasses to update any additional index tables
2443 that might need to be changed.
2444 """
2445 pass
2446
2448 """
2449 Reindex all primary records in the database.
2450 """
2451 pass
2452
2454 """
2455 Find all objects that hold a reference to the object handle.
2456
2457 Returns an interator over alist of (class_name, handle) tuples.
2458
2459 @param handle: handle of the object to search for.
2460 @type handle: database handle
2461 @param include_classes: list of class names to include in the results.
2462 Default: None means include all classes.
2463 @type include_classes: list of class names
2464
2465 This default implementation does a sequencial scan through all
2466 the primary object databases and is very slow. Backends can
2467 override this method to provide much faster implementations that
2468 make use of additional capabilities of the backend.
2469
2470 Note that this is a generator function, it returns a iterator for
2471 use in loops. If you want a list of the results use:
2472
2473 > result_list = [i for i in find_backlink_handles(handle)]
2474 """
2475
2476
2477
2478 primary_tables = {
2479 'Person': {'cursor_func': self.get_person_cursor,
2480 'class_func': Person},
2481 'Family': {'cursor_func': self.get_family_cursor,
2482 'class_func': Family},
2483 'Event': {'cursor_func': self.get_event_cursor,
2484 'class_func': Event},
2485 'Place': {'cursor_func': self.get_place_cursor,
2486 'class_func': Place},
2487 'Source': {'cursor_func': self.get_source_cursor,
2488 'class_func': Source},
2489 'MediaObject': {'cursor_func': self.get_media_cursor,
2490 'class_func': MediaObject},
2491 'Repository': {'cursor_func': self.get_repository_cursor,
2492 'class_func': Repository},
2493 'Note': {'cursor_func': self.get_note_cursor,
2494 'class_func': Note},
2495 }
2496
2497
2498
2499 if (include_classes == None):
2500 the_tables = primary_tables.keys()
2501 else:
2502 the_tables = include_classes
2503
2504
2505
2506 for primary_table_name in the_tables:
2507 cursor = primary_tables[primary_table_name]['cursor_func']()
2508 data = cursor.first()
2509
2510
2511
2512 class_func = primary_tables[primary_table_name]['class_func']
2513
2514 while data:
2515 found_handle, val = data
2516 obj = class_func()
2517 obj.unserialize(val)
2518
2519
2520
2521 for classname in primary_tables.keys():
2522 if obj.has_handle_reference(classname, handle):
2523 yield (primary_table_name, found_handle)
2524
2525 data = cursor.next()
2526
2527 cursor.close()
2528
2529 return
2530
2532 """
2533 Add 1 to the number of bookmark changes during this session.
2534 """
2535 self._bm_changes += 1
2536
2538 """
2539 Return whethere there were bookmark changes during the session.
2540 """
2541 return self._bm_changes > 0
2542
2544 """
2545 Define a group of database commits that define a single logical operation.
2546 """
2547 - def __init__(self, msg, db, batch=False, no_magic=False):
2548 """
2549 Create a new transaction.
2550
2551 A Transaction instance should not be created directly, but by the
2552 GrampsDbBase class or classes derived from GrampsDbBase. The db
2553 parameter is a list-like interface that stores the commit data. This
2554 could be a simple list, or a RECNO-style database object.
2555
2556 The batch parameter is set to True for large transactions. For such
2557 transactions, the list of changes is not maintained, and no undo
2558 is possible.
2559
2560 The no_magic parameter is ignored for non-batch transactions, and
2561 is also of no importance for DB backends other than BSD DB. For
2562 the BSDDB, when this paramter is set to True, some secondary
2563 indices will be removed at the beginning and then rebuilt at
2564 the end of such transaction (only if it is batch).
2565 """
2566 self.db = db
2567 self.first = None
2568 self.last = None
2569 self.batch = batch
2570 self.no_magic = no_magic
2571 self.length = 0
2572 self.timestamp = 0
2573
2574 self.person_add = []
2575 self.person_del = []
2576 self.person_update = []
2577
2578 self.family_add = []
2579 self.family_del = []
2580 self.family_update = []
2581
2582 self.source_add = []
2583 self.source_del = []
2584 self.source_update = []
2585
2586 self.event_add = []
2587 self.event_del = []
2588 self.event_update = []
2589
2590 self.media_add = []
2591 self.media_del = []
2592 self.media_update = []
2593
2594 self.place_add = []
2595 self.place_del = []
2596 self.place_update = []
2597
2598 self.repository_add = []
2599 self.repository_del = []
2600 self.repository_update = []
2601
2602 self.note_add = []
2603 self.note_del = []
2604 self.note_update = []
2605
2607 """
2608 Return the text string that describes the logical operation performed
2609 by the Transaction.
2610 """
2611 return self.msg
2612
2614 """
2615 Set the text string that describes the logical operation performed by
2616 the Transaction.
2617 """
2618 self.msg = msg
2619
2620 - def add(self, obj_type, handle, old_data, new_data):
2621 """
2622 Add a commit operation to the Transaction.
2623
2624 The obj_type is a constant that indicates what type of PrimaryObject
2625 is being added. The handle is the object's database handle, and the
2626 data is the tuple returned by the object's serialize method.
2627 """
2628 self.last = self.db.append(
2629 cPickle.dumps((obj_type, handle, old_data, new_data), 1))
2630 if self.first == None:
2631 self.first = self.last
2632
2634 """
2635 Return a list of record numbers associated with the transaction.
2636
2637 While the list is an arbitrary index of integers, it can be used
2638 to indicate record numbers for a database.
2639 """
2640 return range (self.first, self.last+1)
2641
2643 """
2644 Return a tuple representing the PrimaryObject type, database handle
2645 for the PrimaryObject, and a tuple representing the data created by
2646 the object's serialize method.
2647 """
2648 return cPickle.loads(self.db[recno])
2649
2651 """
2652 Return the number of commits associated with the Transaction.
2653 """
2654 if self.last and self.first:
2655 return self.last - self.first + 1
2656 return 0
2657