From 16a5665e3e871dc7e96ebc5bf7278c3dd0c3be96 Mon Sep 17 00:00:00 2001 From: Doug Blank Date: Wed, 13 May 2015 08:09:30 -0400 Subject: [PATCH] Added Django and Dictionary plugins, to be developed --- gramps/plugins/database/dbdjango.py | 2036 ++++++++++++++++ gramps/plugins/database/dictionarydb.gpr.py | 31 + .../{dictionary.py => dictionarydb.py} | 22 +- .../database/django_support/libdjango.py | 2063 +++++++++++++++++ gramps/plugins/database/djangodb.gpr.py | 31 + gramps/plugins/database/djangodb.py | 2036 ++++++++++++++++ 6 files changed, 6208 insertions(+), 11 deletions(-) create mode 100644 gramps/plugins/database/dbdjango.py create mode 100644 gramps/plugins/database/dictionarydb.gpr.py rename gramps/plugins/database/{dictionary.py => dictionarydb.py} (98%) create mode 100644 gramps/plugins/database/django_support/libdjango.py create mode 100644 gramps/plugins/database/djangodb.gpr.py create mode 100644 gramps/plugins/database/djangodb.py diff --git a/gramps/plugins/database/dbdjango.py b/gramps/plugins/database/dbdjango.py new file mode 100644 index 000000000..adb28dc54 --- /dev/null +++ b/gramps/plugins/database/dbdjango.py @@ -0,0 +1,2036 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +""" Implements a Db interface """ + +#------------------------------------------------------------------------ +# +# Python Modules +# +#------------------------------------------------------------------------ +import sys +import time +import re +import base64 +import pickle +import os + +#------------------------------------------------------------------------ +# +# Gramps Modules +# +#------------------------------------------------------------------------ +import gramps +from gramps.gen.lib import (Person, Family, Event, Place, Repository, + Citation, Source, Note, MediaObject, Tag, + Researcher) +from gramps.gen.db import DbReadBase, DbWriteBase, DbTxn +from gramps.gen.utils.callback import Callback +from gramps.gen.updatecallback import UpdateCallback +from gramps.gen.db import (PERSON_KEY, + FAMILY_KEY, + CITATION_KEY, + SOURCE_KEY, + EVENT_KEY, + MEDIA_KEY, + PLACE_KEY, + REPOSITORY_KEY, + NOTE_KEY) +from gramps.gen.utils.id import create_id +from django.db import transaction + +class Environment(object): + """ + Implements the Environment API. + """ + def __init__(self, db): + self.db = db + + def txn_begin(self): + return DjangoTxn("DbDjango Transaction", self.db) + +class Table(object): + """ + Implements Table interface. + """ + def __init__(self, funcs): + self.funcs = funcs + + def cursor(self): + """ + Returns a Cursor for this Table. + """ + return self.funcs["cursor_func"]() + + def put(key, data, txn=None): + self[key] = data + +class Map(dict): + """ + Implements the map API for person_map, etc. + + Takes a Table() as argument. + """ + def __init__(self, tbl, *args, **kwargs): + super().__init__(*args, **kwargs) + self.db = tbl + +class MetaCursor(object): + def __init__(self): + pass + def __enter__(self): + return self + def __iter__(self): + return self.__next__() + def __next__(self): + yield None + def __exit__(self, *args, **kwargs): + pass + def iter(self): + yield None + def first(self): + self._iter = self.__iter__() + return self.next() + def next(self): + try: + return next(self._iter) + except: + return None + def close(self): + pass + +class Cursor(object): + def __init__(self, model, func): + self.model = model + self.func = func + def __enter__(self): + return self + def __iter__(self): + return self.__next__() + def __next__(self): + for item in self.model.all(): + yield (bytes(item.handle, "utf-8"), self.func(item.handle)) + def __exit__(self, *args, **kwargs): + pass + def iter(self): + for item in self.model.all(): + yield (bytes(item.handle, "utf-8"), self.func(item.handle)) + yield None + def first(self): + self._iter = self.__iter__() + return self.next() + def next(self): + try: + return next(self._iter) + except: + return None + def close(self): + pass + +class Bookmarks(object): + def __init__(self): + self.handles = [] + def get(self): + return self.handles + def append(self, handle): + self.handles.append(handle) + +class DjangoTxn(DbTxn): + def __init__(self, message, db, table=None): + DbTxn.__init__(self, message, db) + self.table = table + + def get(self, key, default=None, txn=None, **kwargs): + """ + Returns the data object associated with key + """ + try: + return self.table.objects(handle=key) + except: + if txn and key in txn: + return txn[key] + else: + return None + + def put(self, handle, new_data, txn): + """ + """ + txn[handle] = new_data + + def commit(self): + pass + +class DbDjango(DbWriteBase, DbReadBase, UpdateCallback, Callback): + """ + A Gramps Database Backend. This replicates the grampsdb functions. + """ + # Set up dictionary for callback signal handler + # --------------------------------------------- + # 1. Signals for primary objects + __signals__ = dict((obj+'-'+op, signal) + for obj in + ['person', 'family', 'event', 'place', + 'source', 'citation', 'media', 'note', 'repository', 'tag'] + for op, signal in zip( + ['add', 'update', 'delete', 'rebuild'], + [(list,), (list,), (list,), None] + ) + ) + + # 2. Signals for long operations + __signals__.update(('long-op-'+op, signal) for op, signal in zip( + ['start', 'heartbeat', 'end'], + [(object,), None, None] + )) + + # 3. Special signal for change in home person + __signals__['home-person-changed'] = None + + # 4. Signal for change in person group name, parameters are + __signals__['person-groupname-rebuild'] = (str, str) + + def __init__(self, directory=None): + DbReadBase.__init__(self) + DbWriteBase.__init__(self) + Callback.__init__(self) + self._tables = { + 'Person': + { + "handle_func": self.get_person_from_handle, + "gramps_id_func": self.get_person_from_gramps_id, + "class_func": gramps.gen.lib.Person, + "cursor_func": self.get_person_cursor, + "handles_func": self.get_person_handles, + "iter_func": self.iter_people, + }, + 'Family': + { + "handle_func": self.get_family_from_handle, + "gramps_id_func": self.get_family_from_gramps_id, + "class_func": gramps.gen.lib.Family, + "cursor_func": self.get_family_cursor, + "handles_func": self.get_family_handles, + "iter_func": self.iter_families, + }, + 'Source': + { + "handle_func": self.get_source_from_handle, + "gramps_id_func": self.get_source_from_gramps_id, + "class_func": gramps.gen.lib.Source, + "cursor_func": self.get_source_cursor, + "handles_func": self.get_source_handles, + "iter_func": self.iter_sources, + }, + 'Citation': + { + "handle_func": self.get_citation_from_handle, + "gramps_id_func": self.get_citation_from_gramps_id, + "class_func": gramps.gen.lib.Citation, + "cursor_func": self.get_citation_cursor, + "handles_func": self.get_citation_handles, + "iter_func": self.iter_citations, + }, + 'Event': + { + "handle_func": self.get_event_from_handle, + "gramps_id_func": self.get_event_from_gramps_id, + "class_func": gramps.gen.lib.Event, + "cursor_func": self.get_event_cursor, + "handles_func": self.get_event_handles, + "iter_func": self.iter_events, + }, + 'Media': + { + "handle_func": self.get_object_from_handle, + "gramps_id_func": self.get_object_from_gramps_id, + "class_func": gramps.gen.lib.MediaObject, + "cursor_func": self.get_media_cursor, + "handles_func": self.get_media_object_handles, + "iter_func": self.iter_media_objects, + }, + 'Place': + { + "handle_func": self.get_place_from_handle, + "gramps_id_func": self.get_place_from_gramps_id, + "class_func": gramps.gen.lib.Place, + "cursor_func": self.get_place_cursor, + "handles_func": self.get_place_handles, + "iter_func": self.iter_places, + }, + 'Repository': + { + "handle_func": self.get_repository_from_handle, + "gramps_id_func": self.get_repository_from_gramps_id, + "class_func": gramps.gen.lib.Repository, + "cursor_func": self.get_repository_cursor, + "handles_func": self.get_repository_handles, + "iter_func": self.iter_repositories, + }, + 'Note': + { + "handle_func": self.get_note_from_handle, + "gramps_id_func": self.get_note_from_gramps_id, + "class_func": gramps.gen.lib.Note, + "cursor_func": self.get_note_cursor, + "handles_func": self.get_note_handles, + "iter_func": self.iter_notes, + }, + 'Tag': + { + "handle_func": self.get_tag_from_handle, + "gramps_id_func": None, + "class_func": gramps.gen.lib.Tag, + "cursor_func": self.get_tag_cursor, + "handles_func": self.get_tag_handles, + "iter_func": self.iter_tags, + }, + } + # skip GEDCOM cross-ref check for now: + self.set_feature("skip-check-xref", True) + self.readonly = False + self.db_is_open = True + self.name_formats = [] + self.bookmarks = Bookmarks() + self.undo_callback = None + self.redo_callback = None + self.undo_history_callback = None + self.modified = 0 + self.txn = DjangoTxn("DbDjango Transaction", self) + self.transaction = None + # Import cache for gedcom import, uses transactions, and + # two step adding of objects. + self.import_cache = {} + self.use_import_cache = False + self.use_db_cache = True + self._directory = directory + if directory: + self.load(directory) + + def load(self, directory, pulse_progress=None, mode=None): + self._directory = directory + from django.conf import settings + default_settings = {} + settings_file = os.path.join(directory, "default_settings.py") + with open(settings_file) as f: + code = compile(f.read(), settings_file, 'exec') + exec(code, globals(), default_settings) + + class Module(object): + def __init__(self, dictionary): + self.dictionary = dictionary + def __getattr__(self, item): + return self.dictionary[item] + + try: + settings.configure(Module(default_settings)) + except RuntimeError: + # already configured; ignore + pass + + import django + django.setup() + + from django_support.libdjango import DjangoInterface + self.dji = DjangoInterface() + self.family_bookmarks = Bookmarks() + self.event_bookmarks = Bookmarks() + self.place_bookmarks = Bookmarks() + self.citation_bookmarks = Bookmarks() + self.source_bookmarks = Bookmarks() + self.repo_bookmarks = Bookmarks() + self.media_bookmarks = Bookmarks() + self.note_bookmarks = Bookmarks() + self.set_person_id_prefix('I%04d') + self.set_object_id_prefix('O%04d') + self.set_family_id_prefix('F%04d') + self.set_citation_id_prefix('C%04d') + self.set_source_id_prefix('S%04d') + self.set_place_id_prefix('P%04d') + self.set_event_id_prefix('E%04d') + self.set_repository_id_prefix('R%04d') + self.set_note_id_prefix('N%04d') + # ---------------------------------- + self.id_trans = DjangoTxn("ID Transaction", self, self.dji.Person) + self.fid_trans = DjangoTxn("FID Transaction", self, self.dji.Family) + self.pid_trans = DjangoTxn("PID Transaction", self, self.dji.Place) + self.cid_trans = DjangoTxn("CID Transaction", self, self.dji.Citation) + self.sid_trans = DjangoTxn("SID Transaction", self, self.dji.Source) + self.oid_trans = DjangoTxn("OID Transaction", self, self.dji.Media) + self.rid_trans = DjangoTxn("RID Transaction", self, self.dji.Repository) + self.nid_trans = DjangoTxn("NID Transaction", self, self.dji.Note) + self.eid_trans = DjangoTxn("EID Transaction", self, self.dji.Event) + self.cmap_index = 0 + self.smap_index = 0 + self.emap_index = 0 + self.pmap_index = 0 + self.fmap_index = 0 + self.lmap_index = 0 + self.omap_index = 0 + self.rmap_index = 0 + self.nmap_index = 0 + self.env = Environment(self) + self.person_map = Map(Table(self._tables["Person"])) + self.family_map = Map(Table(self._tables["Family"])) + self.place_map = Map(Table(self._tables["Place"])) + self.citation_map = Map(Table(self._tables["Citation"])) + self.source_map = Map(Table(self._tables["Source"])) + self.repository_map = Map(Table(self._tables["Repository"])) + self.note_map = Map(Table(self._tables["Note"])) + self.media_map = Map(Table(self._tables["Media"])) + self.event_map = Map(Table(self._tables["Event"])) + self.tag_map = Map(Table(self._tables["Tag"])) + self.metadata = Map(Table({"cursor_func": lambda: MetaCursor()})) + self.name_group = {} + self.event_names = set() + self.individual_attributes = set() + self.family_attributes = set() + self.source_attributes = set() + self.child_ref_types = set() + self.family_rel_types = set() + self.event_role_names = set() + self.name_types = set() + self.origin_types = set() + self.repository_types = set() + self.note_types = set() + self.source_media_types = set() + self.url_types = set() + self.media_attributes = set() + self.place_types = set() + + def prepare_import(self): + """ + DbDjango does not commit data on gedcom import, but saves them + for later commit. + """ + self.use_import_cache = True + self.import_cache = {} + + @transaction.atomic + def commit_import(self): + """ + Commits the items that were queued up during the last gedcom + import for two step adding. + """ + # First we add the primary objects: + for key in list(self.import_cache.keys()): + obj = self.import_cache[key] + if isinstance(obj, Person): + self.dji.add_person(obj.serialize()) + elif isinstance(obj, Family): + self.dji.add_family(obj.serialize()) + elif isinstance(obj, Event): + self.dji.add_event(obj.serialize()) + elif isinstance(obj, Place): + self.dji.add_place(obj.serialize()) + elif isinstance(obj, Repository): + self.dji.add_repository(obj.serialize()) + elif isinstance(obj, Citation): + self.dji.add_citation(obj.serialize()) + elif isinstance(obj, Source): + self.dji.add_source(obj.serialize()) + elif isinstance(obj, Note): + self.dji.add_note(obj.serialize()) + elif isinstance(obj, MediaObject): + self.dji.add_media(obj.serialize()) + elif isinstance(obj, Tag): + self.dji.add_tag(obj.serialize()) + # Next we add the links: + for key in list(self.import_cache.keys()): + obj = self.import_cache[key] + if isinstance(obj, Person): + self.dji.add_person_detail(obj.serialize()) + elif isinstance(obj, Family): + self.dji.add_family_detail(obj.serialize()) + elif isinstance(obj, Event): + self.dji.add_event_detail(obj.serialize()) + elif isinstance(obj, Place): + self.dji.add_place_detail(obj.serialize()) + elif isinstance(obj, Repository): + self.dji.add_repository_detail(obj.serialize()) + elif isinstance(obj, Citation): + self.dji.add_citation_detail(obj.serialize()) + elif isinstance(obj, Source): + self.dji.add_source_detail(obj.serialize()) + elif isinstance(obj, Note): + self.dji.add_note_detail(obj.serialize()) + elif isinstance(obj, MediaObject): + self.dji.add_media_detail(obj.serialize()) + elif isinstance(obj, Tag): + self.dji.add_tag_detail(obj.serialize()) + self.use_import_cache = False + self.import_cache = {} + self.dji.update_publics() + + def transaction_commit(self, txn): + pass + + def request_rebuild(self): + # caches are ok, but let's compute public's + self.dji.update_publics() + self.emit('person-rebuild') + self.emit('family-rebuild') + self.emit('place-rebuild') + self.emit('source-rebuild') + self.emit('citation-rebuild') + self.emit('media-rebuild') + self.emit('event-rebuild') + self.emit('repository-rebuild') + self.emit('note-rebuild') + self.emit('tag-rebuild') + + def get_undodb(self): + return None + + def transaction_abort(self, txn): + pass + + @staticmethod + def _validated_id_prefix(val, default): + if isinstance(val, str) and val: + try: + str_ = val % 1 + except TypeError: # missing conversion specifier + prefix_var = val + "%d" + except ValueError: # incomplete format + prefix_var = default+"%04d" + else: + prefix_var = val # OK as given + else: + prefix_var = default+"%04d" # not a string or empty string + return prefix_var + + @staticmethod + def __id2user_format(id_pattern): + """ + Return a method that accepts a Gramps ID and adjusts it to the users + format. + """ + pattern_match = re.match(r"(.*)%[0 ](\d+)[diu]$", id_pattern) + if pattern_match: + str_prefix = pattern_match.group(1) + nr_width = pattern_match.group(2) + def closure_func(gramps_id): + if gramps_id and gramps_id.startswith(str_prefix): + id_number = gramps_id[len(str_prefix):] + if id_number.isdigit(): + id_value = int(id_number, 10) + #if len(str(id_value)) > nr_width: + # # The ID to be imported is too large to fit in the + # # users format. For now just create a new ID, + # # because that is also what happens with IDs that + # # are identical to IDs already in the database. If + # # the problem of colliding import and already + # # present IDs is solved the code here also needs + # # some solution. + # gramps_id = id_pattern % 1 + #else: + gramps_id = id_pattern % id_value + return gramps_id + else: + def closure_func(gramps_id): + return gramps_id + return closure_func + + def set_person_id_prefix(self, val): + """ + Set the naming template for GRAMPS Person ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as I%d or I%04d. + """ + self.person_prefix = self._validated_id_prefix(val, "I") + self.id2user_format = self.__id2user_format(self.person_prefix) + + def set_citation_id_prefix(self, val): + """ + Set the naming template for GRAMPS Citation ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as C%d or C%04d. + """ + self.citation_prefix = self._validated_id_prefix(val, "C") + self.cid2user_format = self.__id2user_format(self.citation_prefix) + + def set_source_id_prefix(self, val): + """ + Set the naming template for GRAMPS Source ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as S%d or S%04d. + """ + self.source_prefix = self._validated_id_prefix(val, "S") + self.sid2user_format = self.__id2user_format(self.source_prefix) + + def set_object_id_prefix(self, val): + """ + Set the naming template for GRAMPS MediaObject ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as O%d or O%04d. + """ + self.mediaobject_prefix = self._validated_id_prefix(val, "O") + self.oid2user_format = self.__id2user_format(self.mediaobject_prefix) + + def set_place_id_prefix(self, val): + """ + Set the naming template for GRAMPS Place ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as P%d or P%04d. + """ + self.place_prefix = self._validated_id_prefix(val, "P") + self.pid2user_format = self.__id2user_format(self.place_prefix) + + def set_family_id_prefix(self, val): + """ + Set the naming template for GRAMPS Family ID values. The string is + expected to be in the form of a simple text string, or in a format + that contains a C/Python style format string using %d, such as F%d + or F%04d. + """ + self.family_prefix = self._validated_id_prefix(val, "F") + self.fid2user_format = self.__id2user_format(self.family_prefix) + + def set_event_id_prefix(self, val): + """ + Set the naming template for GRAMPS Event ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as E%d or E%04d. + """ + self.event_prefix = self._validated_id_prefix(val, "E") + self.eid2user_format = self.__id2user_format(self.event_prefix) + + def set_repository_id_prefix(self, val): + """ + Set the naming template for GRAMPS Repository ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as R%d or R%04d. + """ + self.repository_prefix = self._validated_id_prefix(val, "R") + self.rid2user_format = self.__id2user_format(self.repository_prefix) + + def set_note_id_prefix(self, val): + """ + Set the naming template for GRAMPS Note ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as N%d or N%04d. + """ + self.note_prefix = self._validated_id_prefix(val, "N") + self.nid2user_format = self.__id2user_format(self.note_prefix) + + def __find_next_gramps_id(self, prefix, map_index, trans): + """ + Helper function for find_next__gramps_id methods + """ + index = prefix % map_index + while trans.get(str(index), txn=self.txn) is not None: + map_index += 1 + index = prefix % map_index + map_index += 1 + return (map_index, index) + + def find_next_person_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Person object based off the + person ID prefix. + """ + self.pmap_index, gid = self.__find_next_gramps_id(self.person_prefix, + self.pmap_index, self.id_trans) + return gid + + def find_next_place_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Place object based off the + place ID prefix. + """ + self.lmap_index, gid = self.__find_next_gramps_id(self.place_prefix, + self.lmap_index, self.pid_trans) + return gid + + def find_next_event_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Event object based off the + event ID prefix. + """ + self.emap_index, gid = self.__find_next_gramps_id(self.event_prefix, + self.emap_index, self.eid_trans) + return gid + + def find_next_object_gramps_id(self): + """ + Return the next available GRAMPS' ID for a MediaObject object based + off the media object ID prefix. + """ + self.omap_index, gid = self.__find_next_gramps_id(self.mediaobject_prefix, + self.omap_index, self.oid_trans) + return gid + + def find_next_citation_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Citation object based off the + citation ID prefix. + """ + self.cmap_index, gid = self.__find_next_gramps_id(self.citation_prefix, + self.cmap_index, self.cid_trans) + return gid + + def find_next_source_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Source object based off the + source ID prefix. + """ + self.smap_index, gid = self.__find_next_gramps_id(self.source_prefix, + self.smap_index, self.sid_trans) + return gid + + def find_next_family_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Family object based off the + family ID prefix. + """ + self.fmap_index, gid = self.__find_next_gramps_id(self.family_prefix, + self.fmap_index, self.fid_trans) + return gid + + def find_next_repository_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Respository object based + off the repository ID prefix. + """ + self.rmap_index, gid = self.__find_next_gramps_id(self.repository_prefix, + self.rmap_index, self.rid_trans) + return gid + + def find_next_note_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Note object based off the + note ID prefix. + """ + self.nmap_index, gid = self.__find_next_gramps_id(self.note_prefix, + self.nmap_index, self.nid_trans) + return gid + + def get_mediapath(self): + return None + + def get_name_group_keys(self): + return [] + + def get_name_group_mapping(self, key): + return None + + def get_researcher(self): + obj = Researcher() + return obj + + def get_tag_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Tag.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Tag.all()] + + def get_person_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Person.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Person.all()] + + def get_family_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Family.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Family.all()] + + def get_event_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Event.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Event.all()] + + def get_citation_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Citation.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Citation.all()] + + def get_source_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Source.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Source.all()] + + def get_place_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Place.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Place.all()] + + def get_repository_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Repository.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Repository.all()] + + def get_media_object_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Media.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Media.all()] + + def get_note_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Note.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Note.all()] + + def get_media_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + media = self.dji.Media.get(handle=handle) + except: + return None + return self.make_media(media) + + def get_event_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + event = self.dji.Event.get(handle=handle) + except: + return None + return self.make_event(event) + + def get_family_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + family = self.dji.Family.get(handle=handle) + except: + return None + return self.make_family(family) + + def get_repository_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + repository = self.dji.Repository.get(handle=handle) + except: + return None + return self.make_repository(repository) + + def get_person_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + person = self.dji.Person.get(handle=handle) + except: + return None + return self.make_person(person) + + def get_tag_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + tag = self.dji.Tag.get(handle=handle) + except: + return None + return self.make_tag(tag) + + def make_repository(self, repository): + if self.use_db_cache and repository.cache: + data = repository.from_cache() + else: + data = self.dji.get_repository(repository) + return Repository.create(data) + + def make_citation(self, citation): + if self.use_db_cache and citation.cache: + data = citation.from_cache() + else: + data = self.dji.get_citation(citation) + return Citation.create(data) + + def make_source(self, source): + if self.use_db_cache and source.cache: + data = source.from_cache() + else: + data = self.dji.get_source(source) + return Source.create(data) + + def make_family(self, family): + if self.use_db_cache and family.cache: + data = family.from_cache() + else: + data = self.dji.get_family(family) + return Family.create(data) + + def make_person(self, person): + if self.use_db_cache and person.cache: + data = person.from_cache() + else: + data = self.dji.get_person(person) + return Person.create(data) + + def make_event(self, event): + if self.use_db_cache and event.cache: + data = event.from_cache() + else: + data = self.dji.get_event(event) + return Event.create(data) + + def make_note(self, note): + if self.use_db_cache and note.cache: + data = note.from_cache() + else: + data = self.dji.get_note(note) + return Note.create(data) + + def make_tag(self, tag): + data = self.dji.get_tag(tag) + return Tag.create(data) + + def make_place(self, place): + if self.use_db_cache and place.cache: + data = place.from_cache() + else: + data = self.dji.get_place(place) + return Place.create(data) + + def make_media(self, media): + if self.use_db_cache and media.cache: + data = media.from_cache() + else: + data = self.dji.get_media(media) + return MediaObject.create(data) + + def get_place_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + place = self.dji.Place.get(handle=handle) + except: + return None + return self.make_place(place) + + def get_citation_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + citation = self.dji.Citation.get(handle=handle) + except: + return None + return self.make_citation(citation) + + def get_source_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + source = self.dji.Source.get(handle=handle) + except: + return None + return self.make_source(source) + + def get_note_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + note = self.dji.Note.get(handle=handle) + except: + return None + return self.make_note(note) + + def get_object_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + media = self.dji.Media.get(handle=handle) + except: + return None + return self.make_media(media) + + def get_default_person(self): + people = self.dji.Person.all() + if people.count() > 0: + return self.make_person(people[0]) + return None + + def iter_people(self): + return (self.get_person_from_handle(person.handle) + for person in self.dji.Person.all()) + + def iter_person_handles(self): + return (person.handle for person in self.dji.Person.all()) + + def iter_families(self): + return (self.get_family_from_handle(family.handle) + for family in self.dji.Family.all()) + + def iter_family_handles(self): + return (family.handle for family in self.dji.Family.all()) + + def iter_notes(self): + return (self.get_note_from_handle(note.handle) + for note in self.dji.Note.all()) + + def iter_note_handles(self): + return (note.handle for note in self.dji.Note.all()) + + def iter_events(self): + return (self.get_event_from_handle(event.handle) + for event in self.dji.Event.all()) + + def iter_event_handles(self): + return (event.handle for event in self.dji.Event.all()) + + def iter_places(self): + return (self.get_place_from_handle(place.handle) + for place in self.dji.Place.all()) + + def iter_place_handles(self): + return (place.handle for place in self.dji.Place.all()) + + def iter_repositories(self): + return (self.get_repository_from_handle(repository.handle) + for repository in self.dji.Repository.all()) + + def iter_repository_handles(self): + return (repository.handle for repository in self.dji.Repository.all()) + + def iter_sources(self): + return (self.get_source_from_handle(source.handle) + for source in self.dji.Source.all()) + + def iter_source_handles(self): + return (source.handle for source in self.dji.Source.all()) + + def iter_citations(self): + return (self.get_citation_from_handle(citation.handle) + for citation in self.dji.Citation.all()) + + def iter_citation_handles(self): + return (citation.handle for citation in self.dji.Citation.all()) + + def iter_tags(self): + return (self.get_tag_from_handle(tag.handle) + for tag in self.dji.Tag.all()) + + def iter_tag_handles(self): + return (tag.handle for tag in self.dji.Tag.all()) + + def iter_media_objects(self): + return (self.get_media_from_handle(media.handle) + for media in self.dji.Media.all()) + + def get_tag_from_name(self, name): + try: + tag = self.dji.Tag.filter(name=name) + return self.make_tag(tag[0]) + except: + return None + + def get_person_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Person.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_person(match_list[0]) + else: + return None + + def get_family_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + try: + family = self.dji.Family.get(gramps_id=gramps_id) + except: + return None + return self.make_family(family) + + def get_source_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Source.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_source(match_list[0]) + else: + return None + + def get_citation_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Citation.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_citation(match_list[0]) + else: + return None + + def get_event_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Event.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_event(match_list[0]) + else: + return None + + def get_object_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Media.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_media(match_list[0]) + else: + return None + + def get_place_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Place.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_place(match_list[0]) + else: + return None + + def get_repository_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Repsoitory.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_repository(match_list[0]) + else: + return None + + def get_note_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Note.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_note(match_list[0]) + else: + return None + + def get_number_of_people(self): + return self.dji.Person.count() + + def get_number_of_events(self): + return self.dji.Event.count() + + def get_number_of_places(self): + return self.dji.Place.count() + + def get_number_of_tags(self): + return self.dji.Tag.count() + + def get_number_of_families(self): + return self.dji.Family.count() + + def get_number_of_notes(self): + return self.dji.Note.count() + + def get_number_of_citations(self): + return self.dji.Citation.count() + + def get_number_of_sources(self): + return self.dji.Source.count() + + def get_number_of_media_objects(self): + return self.dji.Media.count() + + def get_number_of_repositories(self): + return self.dji.Repository.count() + + def get_place_cursor(self): + return Cursor(self.dji.Place, self.get_raw_place_data) + + def get_person_cursor(self): + return Cursor(self.dji.Person, self.get_raw_person_data) + + def get_family_cursor(self): + return Cursor(self.dji.Family, self.get_raw_family_data) + + def get_event_cursor(self): + return Cursor(self.dji.Event, self.get_raw_event_data) + + def get_citation_cursor(self): + return Cursor(self.dji.Citation, self.get_raw_citation_data) + + def get_source_cursor(self): + return Cursor(self.dji.Source, self.get_raw_source_data) + + def get_note_cursor(self): + return Cursor(self.dji.Note, self.get_raw_note_data) + + def get_tag_cursor(self): + return Cursor(self.dji.Tag, self.get_raw_tag_data) + + def get_repository_cursor(self): + return Cursor(self.dji.Repository, self.get_raw_repository_data) + + def get_media_cursor(self): + return Cursor(self.dji.Media, self.get_raw_object_data) + + def has_gramps_id(self, obj_key, gramps_id): + key2table = { + PERSON_KEY: self.dji.Person, + FAMILY_KEY: self.dji.Family, + SOURCE_KEY: self.dji.Source, + CITATION_KEY: self.dji.Citation, + EVENT_KEY: self.dji.Event, + MEDIA_KEY: self.dji.Media, + PLACE_KEY: self.dji.Place, + REPOSITORY_KEY: self.dji.Repository, + NOTE_KEY: self.dji.Note, + } + table = key2table[obj_key] + return table.filter(gramps_id=gramps_id).count() > 0 + + def has_person_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Person.filter(handle=handle).count() == 1 + + def has_family_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Family.filter(handle=handle).count() == 1 + + def has_citation_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Citation.filter(handle=handle).count() == 1 + + def has_source_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Source.filter(handle=handle).count() == 1 + + def has_repository_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Repository.filter(handle=handle).count() == 1 + + def has_note_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Note.filter(handle=handle).count() == 1 + + def has_place_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Place.filter(handle=handle).count() == 1 + + def has_event_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Event.filter(handle=handle).count() == 1 + + def has_tag_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Tag.filter(handle=handle).count() == 1 + + def has_object_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Media.filter(handle=handle).count() == 1 + + def has_name_group_key(self, key): + # FIXME: + return False + + def set_name_group_mapping(self, key, value): + # FIXME: + pass + + def set_default_person_handle(self, handle): + pass + + def set_mediapath(self, mediapath): + pass + + def get_raw_person_data(self, handle): + try: + return self.dji.get_person(self.dji.Person.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_family_data(self, handle): + try: + return self.dji.get_family(self.dji.Family.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_citation_data(self, handle): + try: + return self.dji.get_citation(self.dji.Citation.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_source_data(self, handle): + try: + return self.dji.get_source(self.dji.Source.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_repository_data(self, handle): + try: + return self.dji.get_repository(self.dji.Repository.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_note_data(self, handle): + try: + return self.dji.get_note(self.dji.Note.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_place_data(self, handle): + try: + return self.dji.get_place(self.dji.Place.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_object_data(self, handle): + try: + return self.dji.get_media(self.dji.Media.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_tag_data(self, handle): + try: + return self.dji.get_tag(self.dji.Tag.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_event_data(self, handle): + try: + return self.dji.get_event(self.dji.Event.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def add_person(self, person, trans, set_gid=True): + if not person.handle: + person.handle = create_id() + if not person.gramps_id and set_gid: + person.gramps_id = self.find_next_person_gramps_id() + self.commit_person(person, trans) + self.emit("person-add", ([person.handle],)) + return person.handle + + def add_family(self, family, trans, set_gid=True): + if not family.handle: + family.handle = create_id() + if not family.gramps_id and set_gid: + family.gramps_id = self.find_next_family_gramps_id() + self.commit_family(family, trans) + self.emit("family-add", ([family.handle],)) + return family.handle + + def add_citation(self, citation, trans, set_gid=True): + if not citation.handle: + citation.handle = create_id() + if not citation.gramps_id and set_gid: + citation.gramps_id = self.find_next_citation_gramps_id() + self.commit_citation(citation, trans) + self.emit("citation-add", ([citation.handle],)) + return citation.handle + + def add_source(self, source, trans, set_gid=True): + if not source.handle: + source.handle = create_id() + if not source.gramps_id and set_gid: + source.gramps_id = self.find_next_source_gramps_id() + self.commit_source(source, trans) + self.emit("source-add", ([source.handle],)) + return source.handle + + def add_repository(self, repository, trans, set_gid=True): + if not repository.handle: + repository.handle = create_id() + if not repository.gramps_id and set_gid: + repository.gramps_id = self.find_next_repository_gramps_id() + self.commit_repository(repository, trans) + self.emit("repository-add", ([repository.handle],)) + return repository.handle + + def add_note(self, note, trans, set_gid=True): + if not note.handle: + note.handle = create_id() + if not note.gramps_id and set_gid: + note.gramps_id = self.find_next_note_gramps_id() + self.commit_note(note, trans) + self.emit("note-add", ([note.handle],)) + return note.handle + + def add_place(self, place, trans, set_gid=True): + if not place.handle: + place.handle = create_id() + if not place.gramps_id and set_gid: + place.gramps_id = self.find_next_place_gramps_id() + self.commit_place(place, trans) + return place.handle + + def add_event(self, event, trans, set_gid=True): + if not event.handle: + event.handle = create_id() + if not event.gramps_id and set_gid: + event.gramps_id = self.find_next_event_gramps_id() + self.commit_event(event, trans) + return event.handle + + def add_tag(self, tag, trans): + if not tag.handle: + tag.handle = create_id() + self.commit_event(tag, trans) + return tag.handle + + def add_object(self, obj, transaction, set_gid=True): + """ + Add a MediaObject to the database, assigning internal IDs if they have + not already been defined. + + If not set_gid, then gramps_id is not set. + """ + if not obj.handle: + obj.handle = create_id() + if not obj.gramps_id and set_gid: + obj.gramps_id = self.find_next_object_gramps_id() + self.commit_media_object(obj, transaction) + return obj.handle + + def commit_person(self, person, trans, change_time=None): + if self.use_import_cache: + self.import_cache[person.handle] = person + else: + raw = person.serialize() + items = self.dji.Person.filter(handle=person.handle) + if items.count() > 0: + # Hack, for the moment: delete and re-add + items[0].delete() + self.dji.add_person(person.serialize()) + self.dji.add_person_detail(person.serialize()) + if items.count() > 0: + self.emit("person-update", ([person.handle],)) + else: + self.emit("person-add", ([person.handle],)) + + def commit_family(self, family, trans, change_time=None): + if self.use_import_cache: + self.import_cache[family.handle] = family + else: + raw = family.serialize() + items = self.dji.Family.filter(handle=family.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_family(family.serialize()) + self.dji.add_family_detail(family.serialize()) + if items.count() > 0: + self.emit("family-update", ([family.handle],)) + else: + self.emit("family-add", ([family.handle],)) + + def commit_citation(self, citation, trans, change_time=None): + if self.use_import_cache: + self.import_cache[citation.handle] = citation + else: + raw = citation.serialize() + items = self.dji.Citation.filter(handle=citation.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_citation(citation.serialize()) + self.dji.add_citation_detail(citation.serialize()) + if items.count() > 0: + self.emit("citation-update", ([citation.handle],)) + else: + self.emit("citation-add", ([citation.handle],)) + + def commit_source(self, source, trans, change_time=None): + if self.use_import_cache: + self.import_cache[source.handle] = source + else: + raw = source.serialize() + items = self.dji.Source.filter(handle=source.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_source(source.serialize()) + self.dji.add_source_detail(source.serialize()) + if items.count() > 0: + self.emit("source-update", ([source.handle],)) + else: + self.emit("source-add", ([source.handle],)) + + def commit_repository(self, repository, trans, change_time=None): + if self.use_import_cache: + self.import_cache[repository.handle] = repository + else: + raw = repository.serialize() + items = self.dji.Repository.filter(handle=repository.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_repository(repository.serialize()) + self.dji.add_repository_detail(repository.serialize()) + if items.count() > 0: + self.emit("repository-update", ([repository.handle],)) + else: + self.emit("repository-add", ([repository.handle],)) + + def commit_note(self, note, trans, change_time=None): + if self.use_import_cache: + self.import_cache[note.handle] = note + else: + raw = note.serialize() + items = self.dji.Note.filter(handle=note.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_note(note.serialize()) + self.dji.add_note_detail(note.serialize()) + if items.count() > 0: + self.emit("note-update", ([note.handle],)) + else: + self.emit("note-add", ([note.handle],)) + + def commit_place(self, place, trans, change_time=None): + if self.use_import_cache: + self.import_cache[place.handle] = place + else: + raw = place.serialize() + items = self.dji.Place.filter(handle=place.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_place(place.serialize()) + self.dji.add_place_detail(place.serialize()) + if items.count() > 0: + self.emit("place-update", ([place.handle],)) + else: + self.emit("place-add", ([place.handle],)) + + def commit_event(self, event, trans, change_time=None): + if self.use_import_cache: + self.import_cache[event.handle] = event + else: + raw = event.serialize() + items = self.dji.Event.filter(handle=event.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_event(event.serialize()) + self.dji.add_event_detail(event.serialize()) + if items.count() > 0: + self.emit("event-update", ([event.handle],)) + else: + self.emit("event-add", ([event.handle],)) + + def commit_tag(self, tag, trans, change_time=None): + if self.use_import_cache: + self.import_cache[tag.handle] = tag + else: + raw = tag.serialize() + items = self.dji.Tag.filter(handle=tag.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_tag(tag.serialize()) + self.dji.add_tag_detail(tag.serialize()) + if items.count() > 0: + self.emit("tag-update", ([tag.handle],)) + else: + self.emit("tag-add", ([tag.handle],)) + + def commit_media_object(self, media, transaction, change_time=None): + """ + Commit the specified MediaObject to the database, storing the changes + as part of the transaction. + """ + if self.use_import_cache: + self.import_cache[obj.handle] = media + else: + raw = media.serialize() + items = self.dji.Media.filter(handle=media.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_media(media.serialize()) + self.dji.add_media_detail(media.serialize()) + if items.count() > 0: + self.emit("media-update", ([media.handle],)) + else: + self.emit("media-add", ([media.handle],)) + + def get_gramps_ids(self, obj_key): + key2table = { + PERSON_KEY: self.id_trans, + FAMILY_KEY: self.fid_trans, + CITATION_KEY: self.cid_trans, + SOURCE_KEY: self.sid_trans, + EVENT_KEY: self.eid_trans, + MEDIA_KEY: self.oid_trans, + PLACE_KEY: self.pid_trans, + REPOSITORY_KEY: self.rid_trans, + NOTE_KEY: self.nid_trans, + } + + table = key2table[obj_key] + return list(table.keys()) + + def transaction_begin(self, transaction): + return + + def set_researcher(self, owner): + pass + + def copy_from_db(self, db): + """ + A (possibily) implementation-specific method to get data from + db into this database. + """ + # First we add the primary objects: + for key in db._tables.keys(): + cursor = db._tables[key]["cursor_func"] + for (handle, data) in cursor(): + if key == "Person": + self.dji.add_person(data) + elif key == "Family": + self.dji.add_family(data) + elif key == "Event": + self.dji.add_event(data) + elif key == "Place": + self.dji.add_place(data) + elif key == "Repository": + self.dji.add_repository(data) + elif key == "Citation": + self.dji.add_citation(data) + elif key == "Source": + self.dji.add_source(data) + elif key == "Note": + self.dji.add_note(data) + elif key == "Media": + self.dji.add_media(data) + elif key == "Tag": + self.dji.add_tag(data) + for key in db._tables.keys(): + cursor = db._tables[key]["cursor_func"] + for (handle, data) in cursor(): + if key == "Person": + self.dji.add_person_detail(data) + elif key == "Family": + self.dji.add_family_detail(data) + elif key == "Event": + self.dji.add_event_detail(data) + elif key == "Place": + self.dji.add_place_detail(data) + elif key == "Repository": + self.dji.add_repository_detail(data) + elif key == "Citation": + self.dji.add_citation_detail(data) + elif key == "Source": + self.dji.add_source_detail(data) + elif key == "Note": + self.dji.add_note_detail(data) + elif key == "Media": + self.dji.add_media_detail(data) + elif key == "Tag": + self.dji.add_tag_detail(data) + # Next we add the links: + self.dji.update_publics() + + def get_from_name_and_handle(self, table_name, handle): + """ + Returns a gen.lib object (or None) given table_name and + handle. + + Examples: + + >>> self.get_from_name_and_handle("Person", "a7ad62365bc652387008") + >>> self.get_from_name_and_handle("Media", "c3434653675bcd736f23") + """ + if table_name in self._tables: + return self._tables[table_name]["handle_func"](handle) + return None + + def is_empty(self): + """ + Is the database empty? + """ + return (self.get_number_of_people() == 0 and + self.get_number_of_events() == 0 and + self.get_number_of_places() == 0 and + self.get_number_of_tags() == 0 and + self.get_number_of_families() == 0 and + self.get_number_of_notes() == 0 and + self.get_number_of_citations() == 0 and + self.get_number_of_sources() == 0 and + self.get_number_of_media_objects() == 0 and + self.get_number_of_repositories() == 0) + + __callback_map = {} + + def set_prefixes(self, person, media, family, source, citation, + place, event, repository, note): + self.set_person_id_prefix(person) + self.set_object_id_prefix(media) + self.set_family_id_prefix(family) + self.set_source_id_prefix(source) + self.set_citation_id_prefix(citation) + self.set_place_id_prefix(place) + self.set_event_id_prefix(event) + self.set_repository_id_prefix(repository) + self.set_note_id_prefix(note) + + def has_changed(self): + return False + + def find_backlink_handles(self, handle, include_classes=None): + ## FIXME: figure out how to get objects that refer + ## to this handle + return [] + + def get_note_bookmarks(self): + return self.note_bookmarks + + def get_media_bookmarks(self): + return self.media_bookmarks + + def get_repo_bookmarks(self): + return self.repo_bookmarks + + def get_citation_bookmarks(self): + return self.citation_bookmarks + + def get_source_bookmarks(self): + return self.source_bookmarks + + def get_place_bookmarks(self): + return self.place_bookmarks + + def get_event_bookmarks(self): + return self.event_bookmarks + + def get_bookmarks(self): + return self.bookmarks + + def get_family_bookmarks(self): + return self.family_bookmarks + + def get_save_path(self): + return "/tmp/" + + ## Get types: + def get_event_attribute_types(self): + """ + Return a list of all Attribute types assocated with Event instances + in the database. + """ + return list(self.event_attributes) + + def get_event_types(self): + """ + Return a list of all event types in the database. + """ + return list(self.event_names) + + def get_person_event_types(self): + """ + Deprecated: Use get_event_types + """ + return list(self.event_names) + + def get_person_attribute_types(self): + """ + Return a list of all Attribute types assocated with Person instances + in the database. + """ + return list(self.individual_attributes) + + def get_family_attribute_types(self): + """ + Return a list of all Attribute types assocated with Family instances + in the database. + """ + return list(self.family_attributes) + + def get_family_event_types(self): + """ + Deprecated: Use get_event_types + """ + return list(self.event_names) + + def get_media_attribute_types(self): + """ + Return a list of all Attribute types assocated with Media and MediaRef + instances in the database. + """ + return list(self.media_attributes) + + def get_family_relation_types(self): + """ + Return a list of all relationship types assocated with Family + instances in the database. + """ + return list(self.family_rel_types) + + def get_child_reference_types(self): + """ + Return a list of all child reference types assocated with Family + instances in the database. + """ + return list(self.child_ref_types) + + def get_event_roles(self): + """ + Return a list of all custom event role names assocated with Event + instances in the database. + """ + return list(self.event_role_names) + + def get_name_types(self): + """ + Return a list of all custom names types assocated with Person + instances in the database. + """ + return list(self.name_types) + + def get_origin_types(self): + """ + Return a list of all custom origin types assocated with Person/Surname + instances in the database. + """ + return list(self.origin_types) + + def get_repository_types(self): + """ + Return a list of all custom repository types assocated with Repository + instances in the database. + """ + return list(self.repository_types) + + def get_note_types(self): + """ + Return a list of all custom note types assocated with Note instances + in the database. + """ + return list(self.note_types) + + def get_source_attribute_types(self): + """ + Return a list of all Attribute types assocated with Source/Citation + instances in the database. + """ + return list(self.source_attributes) + + def get_source_media_types(self): + """ + Return a list of all custom source media types assocated with Source + instances in the database. + """ + return list(self.source_media_types) + + def get_url_types(self): + """ + Return a list of all custom names types assocated with Url instances + in the database. + """ + return list(self.url_types) + + def get_place_types(self): + """ + Return a list of all custom place types assocated with Place instances + in the database. + """ + return list(self.place_types) + + def get_default_handle(self): + people = self.dji.Person.all() + if people.count() > 0: + return people[0].handle + return None + + def close(self): + pass + + def get_surname_list(self): + return [] + + def is_open(self): + return True + + def get_table_names(self): + """Return a list of valid table names.""" + return list(self._tables.keys()) + + def find_initial_person(self): + return self.get_default_person() + + # Removals: + def remove_person(self, handle, txn): + self.dji.Person.filter(handle=handle)[0].delete() + self.emit("person-delete", ([handle],)) + + def remove_source(self, handle, transaction): + self.dji.Source.filter(handle=handle)[0].delete() + self.emit("source-delete", ([handle],)) + + def remove_citation(self, handle, transaction): + self.dji.Citation.filter(handle=handle)[0].delete() + self.emit("citation-delete", ([handle],)) + + def remove_event(self, handle, transaction): + self.dji.Event.filter(handle=handle)[0].delete() + self.emit("event-delete", ([handle],)) + + def remove_object(self, handle, transaction): + self.dji.Media.filter(handle=handle)[0].delete() + self.emit("media-delete", ([handle],)) + + def remove_place(self, handle, transaction): + self.dji.Place.filter(handle=handle)[0].delete() + self.emit("place-delete", ([handle],)) + + def remove_family(self, handle, transaction): + self.dji.Family.filter(handle=handle)[0].delete() + self.emit("family-delete", ([handle],)) + + def remove_repository(self, handle, transaction): + self.dji.Repository.filter(handle=handle)[0].delete() + self.emit("repository-delete", ([handle],)) + + def remove_note(self, handle, transaction): + self.dji.Note.filter(handle=handle)[0].delete() + self.emit("note-delete", ([handle],)) + + def remove_tag(self, handle, transaction): + self.dji.Tag.filter(handle=handle)[0].delete() + self.emit("tag-delete", ([handle],)) + + def remove_from_surname_list(self, person): + ## FIXME + pass + + def get_dbname(self): + return "Django Database" + + ## missing + + def find_place_child_handles(self, handle): + pass + + def get_cursor(self, table, txn=None, update=False, commit=False): + pass + + def get_from_name_and_handle(self, table_name, handle): + """ + Returns a gen.lib object (or None) given table_name and + handle. + + Examples: + + >>> self.get_from_name_and_handle("Person", "a7ad62365bc652387008") + >>> self.get_from_name_and_handle("Media", "c3434653675bcd736f23") + """ + if table_name in self._tables: + return self._tables[table_name]["handle_func"](handle) + return None + + def get_number_of_records(self, table): + pass + + def get_place_parent_cursor(self): + pass + + def get_place_tree_cursor(self): + pass + + def get_table_metadata(self, table_name): + """Return the metadata for a valid table name.""" + if table_name in self._tables: + return self._tables[table_name] + return None + + def get_transaction_class(self): + pass + + def undo(self, update_history=True): + # FIXME: + return self.undodb.undo(update_history) + + def redo(self, update_history=True): + # FIXME: + return self.undodb.redo(update_history) + + def backup(self): + pass + + def restore(self): + pass diff --git a/gramps/plugins/database/dictionarydb.gpr.py b/gramps/plugins/database/dictionarydb.gpr.py new file mode 100644 index 000000000..3b0e62eca --- /dev/null +++ b/gramps/plugins/database/dictionarydb.gpr.py @@ -0,0 +1,31 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2015 Douglas Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +plg = newplugin() +plg.id = 'dictionarydb' +plg.name = _("Dictionary Database Backend") +plg.name_accell = _("Di_ctionary Database Backend") +plg.description = _("Dictionary (in-memory) Database Backend") +plg.version = '1.0' +plg.gramps_target_version = "4.2" +plg.status = STABLE +plg.fname = 'dictionarydb.py' +plg.ptype = DATABASE +plg.databaseclass = 'DictionaryDb' diff --git a/gramps/plugins/database/dictionary.py b/gramps/plugins/database/dictionarydb.py similarity index 98% rename from gramps/plugins/database/dictionary.py rename to gramps/plugins/database/dictionarydb.py index 2d785ef6e..a3dbd9586 100644 --- a/gramps/plugins/database/dictionary.py +++ b/gramps/plugins/database/dictionarydb.py @@ -28,17 +28,17 @@ import pickle import base64 import time import re -from . import DbReadBase, DbWriteBase, DbTxn -from . import (PERSON_KEY, - FAMILY_KEY, - CITATION_KEY, - SOURCE_KEY, - EVENT_KEY, - MEDIA_KEY, - PLACE_KEY, - REPOSITORY_KEY, - NOTE_KEY, - TAG_KEY) +from gramps.gen.db import DbReadBase, DbWriteBase, DbTxn +from gramps.gen.db import (PERSON_KEY, + FAMILY_KEY, + CITATION_KEY, + SOURCE_KEY, + EVENT_KEY, + MEDIA_KEY, + PLACE_KEY, + REPOSITORY_KEY, + NOTE_KEY, + TAG_KEY) from gramps.gen.utils.id import create_id from gramps.gen.lib.researcher import Researcher diff --git a/gramps/plugins/database/django_support/libdjango.py b/gramps/plugins/database/django_support/libdjango.py new file mode 100644 index 000000000..fa0a596c8 --- /dev/null +++ b/gramps/plugins/database/django_support/libdjango.py @@ -0,0 +1,2063 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +""" Interface to Django models """ + +#------------------------------------------------------------------------ +# +# Python Modules +# +#------------------------------------------------------------------------ +import time +import sys +import pickle +import base64 +import collections + +#------------------------------------------------------------------------ +# +# Django Modules +# +#------------------------------------------------------------------------ +from django.contrib.contenttypes.models import ContentType +from django.db import transaction + +#------------------------------------------------------------------------ +# +# Gramps Modules +# +#------------------------------------------------------------------------ +import gramps.webapp.grampsdb.models as models +from gramps.gen.lib import Name +from gramps.gen.utils.id import create_id +from gramps.gen.constfunc import conv_to_unicode + +# To get a django person from a django database: +# djperson = dji.Person.get(handle='djhgsdh324hjg234hj24') +# +# To turn the djperson into a Gramps Person: +# tuple = dji.get_person(djperson) +# gperson = lib.gen.Person(tuple) +# OR +# gperson = dbdjango.DbDjango().get_person_from_handle(handle) + +def check_diff(item, raw): + encoded = str(base64.encodebytes(pickle.dumps(raw)), "utf-8") + if item.cache != encoded: + print("Different:", item.__class__.__name__, item.gramps_id) + print("raw :", raw) + print("cache:", item.from_cache()) + # FIXING, TOO: + item.save_cache() + +#------------------------------------------------------------------------- +# +# Import functions +# +#------------------------------------------------------------------------- +def lookup_role_index(role0, event_ref_list): + """ + Find the handle in a unserialized event_ref_list and return code. + """ + if role0 is None: + return -1 + else: + count = 0 + for event_ref in event_ref_list: + (private, note_list, attribute_list, ref, erole) = event_ref + try: + event = models.Event.objects.get(handle=ref) + except: + return -1 + if event.event_type[0] == role0: + return count + count += 1 + return -1 + +def totime(dtime): + if dtime: + return int(time.mktime(dtime.timetuple())) + else: + return 0 + +#------------------------------------------------------------------------- +# +# Export functions +# +#------------------------------------------------------------------------- +def todate(t): + return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(t)) + +def lookup(index, event_ref_list): + """ + Get the unserialized event_ref in an list of them and return it. + """ + if index < 0: + return None + else: + count = 0 + for event_ref in event_ref_list: + (private, note_list, attribute_list, ref, role) = event_ref + if index == count: + return ref + count += 1 + return None + +def get_datamap(grampsclass): + return [x[0] for x in grampsclass._DATAMAP if x[0] != grampsclass.CUSTOM] + +#------------------------------------------------------------------------- +# +# Django Interface +# +#------------------------------------------------------------------------- +class DjangoInterface(object): + """ + DjangoInterface for interoperating between Gramps and Django. + + This interface comes in a number of parts: + get_ITEMS() + add_ITEMS() + + get_ITEM(ITEM) + + Given an ITEM from a Django table, construct a Gramps Raw Data tuple. + + add_ITEM(data) + + Given a Gramps Raw Data tuple, add the data to the Django tables. + + + """ + def __init__(self): + self.debug = 0 + + def __getattr__(self, name): + """ + Django Objects database interface. + + >>> self.Person.all() + >>> self.Person.get(id=1) + >>> self.Person.get(handle='gh71234dhf3746347734') + """ + if hasattr(models, name): + return getattr(models, name).objects + else: + raise AttributeError("no such model: '%s'" % name) + + def get_next_id(self, obj, prefix): + """ + Get next gramps_id + + >>> dji.get_next_id(Person, "P") + 'P0002' + >>> dji.get_next_id(Media, "M") + 'M2349' + """ + ids = [o["gramps_id"] for o in obj.objects.values("gramps_id")] + count = 1 + while "%s%04d" % (prefix, count) in ids: + count += 1 + return "%s%04d" % (prefix, count) + + def get_model(self, name): + if hasattr(models, name): + return getattr(models, name) + elif hasattr(models, name.title()): + return getattr(models, name.title()) + else: + raise AttributeError("no such model: '%s'" % name) + + # ----------------------------------------------- + # Get methods to retrieve list data from the tables + # ----------------------------------------------- + + def clear_tables(self, *args): + return models.clear_tables(*args) + + def get_tag_list(self, obj): + return obj.get_tag_list() + + def get_attribute_list(self, obj): + obj_type = ContentType.objects.get_for_model(obj) + attribute_list = models.Attribute.objects.filter(object_id=obj.id, + object_type=obj_type) + return list(map(self.pack_attribute, attribute_list)) + + def get_primary_name(self, person): + names = person.name_set.filter(preferred=True).order_by("order") + if len(names) > 0: + return Name.create(self.pack_name(names[0])) + else: + return Name() + + def get_alternate_names(self, person): + names = person.name_set.filter(preferred=False).order_by("order") + return [Name.create(self.pack_name(n)) for n in names] + + def get_names(self, person, preferred): + names = person.name_set.filter(preferred=preferred).order_by("order") + if preferred: + if len(names) > 0: + return self.pack_name(names[0]) + else: + return Name().serialize() + else: + return list(map(self.pack_name, names)) + + def get_source_attribute_list(self, source): + return [(map.private, map.key, map.value) for map in source.sourceattribute_set.all().order_by("order")] + + def get_citation_attribute_list(self, citation): + return [(map.private, map.key, map.value) for map in citation.citationattribute_set.all().order_by("order")] + + def get_media_list(self, obj): + obj_type = ContentType.objects.get_for_model(obj) + mediarefs = models.MediaRef.objects.filter(object_id=obj.id, + object_type=obj_type) + return list(map(self.pack_media_ref, mediarefs)) + + def get_note_list(self, obj): + obj_type = ContentType.objects.get_for_model(obj) + noterefs = models.NoteRef.objects.filter(object_id=obj.id, + object_type=obj_type) + return [noteref.ref_object.handle for noteref in noterefs] + + def get_repository_ref_list(self, obj): + obj_type = ContentType.objects.get_for_model(obj) + reporefs = models.RepositoryRef.objects.filter(object_id=obj.id, + object_type=obj_type) + return list(map(self.pack_repository_ref, reporefs)) + + def get_place_ref_list(self, obj): + obj_type = ContentType.objects.get_for_model(obj) + refs = models.PlaceRef.objects.filter(object_id=obj.id, + object_type=obj_type) + return list(map(self.pack_place_ref, refs)) + + def get_url_list(self, obj): + return list(map(self.pack_url, obj.url_set.all().order_by("order"))) + + def get_address_list(self, obj, with_parish): # person or repository + addresses = obj.address_set.all().order_by("order") + return [self.pack_address(address, with_parish) + for address in addresses] + + def get_child_ref_list(self, family): + obj_type = ContentType.objects.get_for_model(family) + childrefs = models.ChildRef.objects.filter(object_id=family.id, + object_type=obj_type).order_by("order") + return list(map(self.pack_child_ref, childrefs)) + + def get_citation_list(self, obj): + obj_type = ContentType.objects.get_for_model(obj) + citationrefs = models.CitationRef.objects.filter(object_id=obj.id, + object_type=obj_type).order_by("order") + return [citationref.citation.handle for citationref in citationrefs] + + def get_event_refs(self, obj, order="order"): + obj_type = ContentType.objects.get_for_model(obj) + eventrefs = models.EventRef.objects.filter(object_id=obj.id, + object_type=obj_type).order_by(order) + return eventrefs + + def get_event_ref_list(self, obj): + obj_type = ContentType.objects.get_for_model(obj) + eventrefs = models.EventRef.objects.filter(object_id=obj.id, + object_type=obj_type).order_by("order") + return list(map(self.pack_event_ref, eventrefs)) + + def get_family_list(self, person): # person has families + return [fam.family.handle for fam in + models.MyFamilies.objects.filter(person=person).order_by("order")] + + def get_parent_family_list(self, person): # person's parents has families + return [fam.family.handle for fam in + models.MyParentFamilies.objects.filter(person=person).order_by("order")] + + def get_person_ref_list(self, person): + obj_type = ContentType.objects.get_for_model(person) + return list(map(self.pack_person_ref, + models.PersonRef.objects.filter(object_id=person.id, + object_type=obj_type))) + + def get_lds_list(self, obj): # person or family + return list(map(self.pack_lds, obj.lds_set.all().order_by("order"))) + + def get_place_handle(self, obj): # obj is event + if obj.place: + return obj.place.handle + return '' + + ## Packers: + + def get_event(self, event): + handle = event.handle + gid = event.gramps_id + the_type = tuple(event.event_type) + description = event.description + change = totime(event.last_changed) + private = event.private + note_list = self.get_note_list(event) + citation_list = self.get_citation_list(event) + media_list = self.get_media_list(event) + attribute_list = self.get_attribute_list(event) + date = self.get_date(event) + place_handle = self.get_place_handle(event) + tag_list = self.get_tag_list(event) + return (str(handle), gid, the_type, date, description, place_handle, + citation_list, note_list, media_list, attribute_list, + change, tag_list, private) + + def get_note_markup(self, note): + retval = [] + markups = models.Markup.objects.filter(note=note).order_by("order") + for markup in markups: + if markup.string and markup.string.isdigit(): + value = int(markup.string) + else: + value = markup.string + start_stop_list = markup.start_stop_list + ss_list = eval(start_stop_list) + retval += [(tuple(markup.styled_text_tag_type), value, ss_list)] + return retval + + def get_tag(self, tag): + changed = totime(tag.last_changed) + return (str(tag.handle), + tag.name, + tag.color, + tag.priority, + changed) + + def get_note(self, note): + styled_text = [note.text, self.get_note_markup(note)] + changed = totime(note.last_changed) + tag_list = self.get_tag_list(note) + return (str(note.handle), + note.gramps_id, + styled_text, + note.preformatted, + tuple(note.note_type), + changed, + tag_list, + note.private) + + def get_family(self, family): + child_ref_list = self.get_child_ref_list(family) + event_ref_list = self.get_event_ref_list(family) + media_list = self.get_media_list(family) + attribute_list = self.get_attribute_list(family) + lds_seal_list = self.get_lds_list(family) + citation_list = self.get_citation_list(family) + note_list = self.get_note_list(family) + tag_list = self.get_tag_list(family) + if family.father: + father_handle = family.father.handle + else: + father_handle = '' + if family.mother: + mother_handle = family.mother.handle + else: + mother_handle = '' + return (str(family.handle), family.gramps_id, + father_handle, mother_handle, + child_ref_list, tuple(family.family_rel_type), + event_ref_list, media_list, + attribute_list, lds_seal_list, + citation_list, note_list, + totime(family.last_changed), + tag_list, + family.private) + + def get_repository(self, repository): + note_list = self.get_note_list(repository) + address_list = self.get_address_list(repository, with_parish=False) + url_list = self.get_url_list(repository) + tag_list = self.get_tag_list(repository) + return (str(repository.handle), + repository.gramps_id, + tuple(repository.repository_type), + repository.name, + note_list, + address_list, + url_list, + totime(repository.last_changed), + tag_list, + repository.private) + + def get_citation(self, citation): + note_list = self.get_note_list(citation) + media_list = self.get_media_list(citation) + attribute_list = self.get_citation_attribute_list(citation) + tag_list = self.get_tag_list(citation) + date = self.get_date(citation) + # I guess citations can have no source + if citation.source: + handle = citation.source.handle + else: + handle = None + return (str(citation.handle), + citation.gramps_id, + date, + citation.page, + citation.confidence, + handle, + note_list, + media_list, + attribute_list, + totime(citation.last_changed), + tag_list, + citation.private) + + def get_source(self, source): + note_list = self.get_note_list(source) + media_list = self.get_media_list(source) + attribute_list = self.get_source_attribute_list(source) + reporef_list = self.get_repository_ref_list(source) + tag_list = self.get_tag_list(source) + return (str(source.handle), + source.gramps_id, + source.title, + source.author, + source.pubinfo, + note_list, + media_list, + source.abbrev, + totime(source.last_changed), + attribute_list, + reporef_list, + tag_list, + source.private) + + def get_media(self, media): + attribute_list = self.get_attribute_list(media) + citation_list = self.get_citation_list(media) + note_list = self.get_note_list(media) + tag_list = self.get_tag_list(media) + date = self.get_date(media) + return (str(media.handle), + media.gramps_id, + conv_to_unicode(media.path, None), + str(media.mime), + str(media.desc), + media.checksum, + attribute_list, + citation_list, + note_list, + totime(media.last_changed), + date, + tag_list, + media.private) + + def get_person(self, person): + primary_name = self.get_names(person, True) # one + alternate_names = self.get_names(person, False) # list + event_ref_list = self.get_event_ref_list(person) + family_list = self.get_family_list(person) + parent_family_list = self.get_parent_family_list(person) + media_list = self.get_media_list(person) + address_list = self.get_address_list(person, with_parish=False) + attribute_list = self.get_attribute_list(person) + url_list = self.get_url_list(person) + lds_ord_list = self.get_lds_list(person) + pcitation_list = self.get_citation_list(person) + pnote_list = self.get_note_list(person) + person_ref_list = self.get_person_ref_list(person) + # This looks up the events for the first EventType given: + death_ref_index = person.death_ref_index + birth_ref_index = person.birth_ref_index + tag_list = self.get_tag_list(person) + + return (str(person.handle), + person.gramps_id, + tuple(person.gender_type)[0], + primary_name, + alternate_names, + death_ref_index, + birth_ref_index, + event_ref_list, + family_list, + parent_family_list, + media_list, + address_list, + attribute_list, + url_list, + lds_ord_list, + pcitation_list, + pnote_list, + totime(person.last_changed), + tag_list, + person.private, + person_ref_list) + + def get_date(self, obj): + if ((obj.calendar == obj.modifier == obj.quality == obj.sortval == obj.newyear == 0) and + obj.text == "" and (not obj.slash1) and (not obj.slash2) and + (obj.day1 == obj.month1 == obj.year1 == 0) and + (obj.day2 == obj.month2 == obj.year2 == 0)): + return None + elif ((not obj.slash1) and (not obj.slash2) and + (obj.day2 == obj.month2 == obj.year2 == 0)): + dateval = (obj.day1, obj.month1, obj.year1, obj.slash1) + else: + dateval = (obj.day1, obj.month1, obj.year1, obj.slash1, + obj.day2, obj.month2, obj.year2, obj.slash2) + return (obj.calendar, obj.modifier, obj.quality, dateval, + obj.text, obj.sortval, obj.newyear) + + def get_place(self, place): + locations = place.location_set.all().order_by("order") + alt_location_list = [self.pack_location(location, True) for location in locations] + url_list = self.get_url_list(place) + media_list = self.get_media_list(place) + citation_list = self.get_citation_list(place) + note_list = self.get_note_list(place) + tag_list = self.get_tag_list(place) + place_ref_list = self.get_place_ref_list(place) + return (str(place.handle), + place.gramps_id, + place.title, + place.long, + place.lat, + place_ref_list, + place.name, + [], ## FIXME: get_alt_names + tuple(place.place_type), + place.code, + alt_location_list, + url_list, + media_list, + citation_list, + note_list, + totime(place.last_changed), + tag_list, + place.private) + + # --------------------------------- + # Packers + # --------------------------------- + + ## The packers build GRAMPS raw unserialized data. + + ## Reference packers + + def pack_child_ref(self, child_ref): + citation_list = self.get_citation_list(child_ref) + note_list = self.get_note_list(child_ref) + return (child_ref.private, citation_list, note_list, child_ref.ref_object.handle, + tuple(child_ref.father_rel_type), tuple(child_ref.mother_rel_type)) + + def pack_person_ref(self, personref): + citation_list = self.get_citation_list(personref) + note_list = self.get_note_list(personref) + return (personref.private, + citation_list, + note_list, + personref.ref_object.handle, + personref.description) + + def pack_media_ref(self, media_ref): + citation_list = self.get_citation_list(media_ref) + note_list = self.get_note_list(media_ref) + attribute_list = self.get_attribute_list(media_ref) + if ((media_ref.x1 == media_ref.y1 == media_ref.x2 == media_ref.y2 == -1) or + (media_ref.x1 == media_ref.y1 == media_ref.x2 == media_ref.y2 == 0)): + role = None + else: + role = (media_ref.x1, media_ref.y1, media_ref.x2, media_ref.y2) + return (media_ref.private, citation_list, note_list, attribute_list, + media_ref.ref_object.handle, role) + + def pack_repository_ref(self, repo_ref): + note_list = self.get_note_list(repo_ref) + return (note_list, + repo_ref.ref_object.handle, + repo_ref.call_number, + tuple(repo_ref.source_media_type), + repo_ref.private) + + def pack_place_ref(self, place_ref): + date = self.get_date(place_ref) + return (place_ref.ref_object.handle, date) + + def pack_media_ref(self, media_ref): + note_list = self.get_note_list(media_ref) + attribute_list = self.get_attribute_list(media_ref) + citation_list = self.get_citation_list(media_ref) + return (media_ref.private, citation_list, note_list, attribute_list, + media_ref.ref_object.handle, (media_ref.x1, + media_ref.y1, + media_ref.x2, + media_ref.y2)) + + def pack_event_ref(self, event_ref): + note_list = self.get_note_list(event_ref) + attribute_list = self.get_attribute_list(event_ref) + return (event_ref.private, note_list, attribute_list, + event_ref.ref_object.handle, tuple(event_ref.role_type)) + + def pack_citation(self, citation): + handle = citation.handle + gid = citation.gramps_id + date = self.get_date(citation) + page = citation.page + confidence = citation.confidence + source_handle = citation.source.handle + note_list = self.get_note_list(citation) + media_list = self.get_media_list(citation) + attribute_list = self.get_citation_attribute_list(citation) + changed = totime(citation.last_changed) + private = citation.private + tag_list = self.get_tag_list(citation) + return (handle, gid, date, page, confidence, source_handle, + note_list, media_list, attribute_list, changed, tag_list, + private) + + def pack_address(self, address, with_parish): + citation_list = self.get_citation_list(address) + date = self.get_date(address) + note_list = self.get_note_list(address) + locations = address.location_set.all().order_by("order") + if len(locations) > 0: + location = self.pack_location(locations[0], with_parish) + else: + if with_parish: + location = (("", "", "", "", "", "", ""), "") + else: + location = ("", "", "", "", "", "", "") + return (address.private, citation_list, note_list, date, location) + + def pack_lds(self, lds): + citation_list = self.get_citation_list(lds) + note_list = self.get_note_list(lds) + date = self.get_date(lds) + if lds.famc: + famc = lds.famc.handle + else: + famc = None + place_handle = self.get_place_handle(lds) + return (citation_list, note_list, date, lds.lds_type[0], place_handle, + famc, lds.temple, lds.status[0], lds.private) + + def pack_source(self, source): + note_list = self.get_note_list(source) + media_list = self.get_media_list(source) + reporef_list = self.get_repository_ref_list(source) + attribute_list = self.get_source_attribute_list(source) + tag_list = self.get_tag_list(source) + return (source.handle, source.gramps_id, source.title, + source.author, source.pubinfo, + note_list, + media_list, + source.abbrev, + totime(last_changed), attribute_list, + reporef_list, + tag_list, + source.private) + + def pack_name(self, name): + citation_list = self.get_citation_list(name) + note_list = self.get_note_list(name) + date = self.get_date(name) + return (name.private, citation_list, note_list, date, + name.first_name, name.make_surname_list(), name.suffix, + name.title, tuple(name.name_type), + name.group_as, name.sort_as.val, + name.display_as.val, name.call, name.nick, + name.famnick) + + def pack_location(self, loc, with_parish): + if with_parish: + return ((loc.street, loc.locality, loc.city, loc.county, loc.state, loc.country, + loc.postal, loc.phone), loc.parish) + else: + return (loc.street, loc.locality, loc.city, loc.county, loc.state, loc.country, + loc.postal, loc.phone) + + def pack_url(self, url): + return (url.private, url.path, url.desc, tuple(url.url_type)) + + def pack_attribute(self, attribute): + citation_list = self.get_citation_list(attribute) + note_list = self.get_note_list(attribute) + return (attribute.private, + citation_list, + note_list, + tuple(attribute.attribute_type), + attribute.value) + + + ## Export lists: + + def add_child_ref_list(self, obj, ref_list): + ## Currently, only Family references children + for child_data in ref_list: + self.add_child_ref(obj, child_data) + + def add_citation_list(self, obj, citation_list): + for citation_handle in citation_list: + self.add_citation_ref(obj, citation_handle) + + def add_event_ref_list(self, obj, event_ref_list): + for event_ref in event_ref_list: + self.add_event_ref(obj, event_ref) + + def add_surname_list(self, name, surname_list): + order = 1 + for data in surname_list: + (surname_text, prefix, primary, origin_type, + connector) = data + surname = models.Surname() + surname.surname = surname_text + surname.prefix = prefix + surname.primary = primary + surname.name_origin_type = models.get_type(models.NameOriginType, + origin_type) + surname.connector = connector + surname.name = name + surname.order = order + surname.save() + order += 1 + + def add_note_list(self, obj, note_list): + for handle in note_list: + # Just the handle + try: + note = models.Note.objects.get(handle=handle) + self.add_note_ref(obj, note) + except: + print(("ERROR: Note does not exist: '%s'" % + str(handle)), file=sys.stderr) + + def add_alternate_name_list(self, person, alternate_names): + for name in alternate_names: + if name: + self.add_name(person, name, False) + + def add_parent_family_list(self, person, parent_family_list): + for parent_family_data in parent_family_list: + self.add_parent_family(person, parent_family_data) + + def add_media_ref_list(self, person, media_list): + for media_data in media_list: + self.add_media_ref(person, media_data) + + def add_attribute_list(self, obj, attribute_list): + for attribute_data in attribute_list: + self.add_attribute(obj, attribute_data) + + def add_tag_list(self, obj, tag_list): + for tag_handle in tag_list: + try: + tag = models.Tag.objects.get(handle=tag_handle) + except: + print(("ERROR: Tag does not exist: '%s'" % + str(tag_handle)), file=sys.stderr) + obj.tags.add(tag) + + def add_url_list(self, field, obj, url_list): + if not url_list: return None + count = 1 + for url_data in url_list: + self.add_url(field, obj, url_data, count) + count += 1 + + def add_person_ref_list(self, obj, person_ref_list): + for person_ref_data in person_ref_list: + self.add_person_ref(obj, person_ref_data) + + def add_address_list(self, field, obj, address_list): + count = 1 + for address_data in address_list: + self.add_address(field, obj, address_data, count) + count += 1 + + def add_lds_list(self, field, obj, lds_ord_list): + count = 1 + for ldsord in lds_ord_list: + lds = self.add_lds(field, obj, ldsord, count) + #obj.lds_list.add(lds) + #obj.save() + count += 1 + + def add_repository_ref_list(self, obj, reporef_list): + for data in reporef_list: + self.add_repository_ref(obj, data) + + def add_place_ref_list(self, obj, placeref_list): + for data in placeref_list: + self.add_place_ref(obj, data) + + def add_family_ref_list(self, person, family_list): + for family_handle in family_list: + self.add_family_ref(person, family_handle) + + def add_alt_name_list(self, place, alt_name_list): + print("FIXME: add alt_name_list!", alt_name_list) + + ## Export reference objects: + + def add_person_ref_default(self, obj, person, private=False, desc=None): + count = person.references.count() + person_ref = models.PersonRef(referenced_by=obj, + ref_object=person, + private=private, + order=count + 1, + description=desc) + person_ref.save() + + def add_person_ref(self, obj, person_ref_data): + (private, + citation_list, + note_list, + handle, + desc) = person_ref_data + try: + person = models.Person.objects.get(handle=handle) + except: + print(("ERROR: Person does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + + count = person.references.count() + person_ref = models.PersonRef(referenced_by=obj, + ref_object=person, + private=private, + order=count + 1, + description=desc) + person_ref.save() + self.add_note_list(person_ref, note_list) + self.add_citation_list(person_ref, citation_list) + + def add_note_ref(self, obj, note): + count = note.references.count() + note_ref = models.NoteRef(referenced_by=obj, + ref_object=note, + private=False, + order=count + 1) + note_ref.save() + + def add_media_ref_default(self, obj, media, private=False, role=None): + count = media.references.count() + if not role: + role = (0,0,0,0) + media_ref = models.MediaRef(referenced_by=obj, + ref_object=media, + x1=role[0], + y1=role[1], + x2=role[2], + y2=role[3], + private=private, + order=count + 1) + media_ref.save() + + def add_media_ref(self, obj, media_ref_data): + (private, citation_list, note_list, attribute_list, + ref, role) = media_ref_data + try: + media = models.Media.objects.get(handle=ref) + except: + print(("ERROR: Media does not exist: '%s'" % + str(ref)), file=sys.stderr) + return + count = media.references.count() + if not role: + role = (0,0,0,0) + media_ref = models.MediaRef(referenced_by=obj, + ref_object=media, + x1=role[0], + y1=role[1], + x2=role[2], + y2=role[3], + private=private, + order=count + 1) + media_ref.save() + self.add_note_list(media_ref, note_list) + self.add_attribute_list(media_ref, attribute_list) + self.add_citation_list(media_ref, citation_list) + + def add_citation_ref_default(self, obj, citation, private=False): + object_type = ContentType.objects.get_for_model(obj) + count = models.CitationRef.objects.filter(object_id=obj.id,object_type=object_type).count() + citation_ref = models.CitationRef(private=private, + referenced_by=obj, + citation=citation, + order=count + 1) + citation_ref.save() + + def add_citation_ref(self, obj, handle): + try: + citation = models.Citation.objects.get(handle=handle) + except: + print(("ERROR: Citation does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + + object_type = ContentType.objects.get_for_model(obj) + count = models.CitationRef.objects.filter(object_id=obj.id,object_type=object_type).count() + citation_ref = models.CitationRef(private=False, + referenced_by=obj, + citation=citation, + order=count + 1) + citation_ref.save() + + def add_citation(self, citation_data): + (handle, gid, date, page, confidence, source_handle, note_list, + media_list, attribute_list, changed, tag_list, private) = citation_data + citation = models.Citation( + handle=handle, + gramps_id=gid, + private=private, + last_changed=todate(changed), + confidence=confidence, + page=page) + citation.save(save_cache=False) + + def add_citation_detail(self, citation_data): + (handle, gid, date, page, confidence, source_handle, note_list, + media_list, attribute_list, change, tag_list, private) = citation_data + try: + citation = models.Citation.objects.get(handle=handle) + except: + print(("ERROR: Citation does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + try: + source = models.Source.objects.get(handle=source_handle) + except: + print(("ERROR: Source does not exist: '%s'" % + str(source_handle)), file=sys.stderr) + return + citation.source = source + self.add_date(citation, date) + citation.save(save_cache=False) + self.add_note_list(citation, note_list) + self.add_media_ref_list(citation, media_list) + self.add_citation_attribute_list(citation, attribute_list) + self.add_tag_list(citation, tag_list) + citation.save_cache() + + def add_child_ref_default(self, obj, child, frel=1, mrel=1, private=False): + object_type = ContentType.objects.get_for_model(obj) # obj is family + count = models.ChildRef.objects.filter(object_id=obj.id,object_type=object_type).count() + child_ref = models.ChildRef(private=private, + referenced_by=obj, + ref_object=child, + order=count + 1, + father_rel_type=models.get_type(models.ChildRefType, frel), # birth + mother_rel_type=models.get_type(models.ChildRefType, mrel)) + child_ref.save() + + def add_child_ref(self, obj, data): + (private, citation_list, note_list, ref, frel, mrel) = data + try: + child = models.Person.objects.get(handle=ref) + except: + print(("ERROR: Person does not exist: '%s'" % + str(ref)), file=sys.stderr) + return + object_type = ContentType.objects.get_for_model(obj) + count = models.ChildRef.objects.filter(object_id=obj.id,object_type=object_type).count() + child_ref = models.ChildRef(private=private, + referenced_by=obj, + ref_object=child, + order=count + 1, + father_rel_type=models.get_type(models.ChildRefType, frel), + mother_rel_type=models.get_type(models.ChildRefType, mrel)) + child_ref.save() + self.add_citation_list(child_ref, citation_list) + self.add_note_list(child_ref, note_list) + + def add_event_ref_default(self, obj, event, private=False, role=models.EventRoleType._DEFAULT): + object_type = ContentType.objects.get_for_model(obj) + count = models.EventRef.objects.filter(object_id=obj.id,object_type=object_type).count() + event_ref = models.EventRef(private=private, + referenced_by=obj, + ref_object=event, + order=count + 1, + role_type = models.get_type(models.EventRoleType, role)) + event_ref.save() + + def add_event_ref(self, obj, event_data): + (private, note_list, attribute_list, ref, role) = event_data + try: + event = models.Event.objects.get(handle=ref) + except: + print(("ERROR: Event does not exist: '%s'" % + str(ref)), file=sys.stderr) + return + object_type = ContentType.objects.get_for_model(obj) + count = models.EventRef.objects.filter(object_id=obj.id,object_type=object_type).count() + event_ref = models.EventRef(private=private, + referenced_by=obj, + ref_object=event, + order=count + 1, + role_type = models.get_type(models.EventRoleType, role)) + event_ref.save() + self.add_note_list(event_ref, note_list) + self.add_attribute_list(event_ref, attribute_list) + + def add_repository_ref_default(self, obj, repository, private=False, call_number="", + source_media_type=models.SourceMediaType._DEFAULT): + object_type = ContentType.objects.get_for_model(obj) + count = models.RepositoryRef.objects.filter(object_id=obj.id,object_type=object_type).count() + repos_ref = models.RepositoryRef(private=private, + referenced_by=obj, + call_number=call_number, + source_media_type=models.get_type(models.SourceMediaType, + source_media_type), + ref_object=repository, + order=count + 1) + repos_ref.save() + + def add_repository_ref(self, obj, reporef_data): + (note_list, + ref, + call_number, + source_media_type, + private) = reporef_data + try: + repository = models.Repository.objects.get(handle=ref) + except: + print(("ERROR: Repository does not exist: '%s'" % + str(ref)), file=sys.stderr) + return + object_type = ContentType.objects.get_for_model(obj) + count = models.RepositoryRef.objects.filter(object_id=obj.id,object_type=object_type).count() + repos_ref = models.RepositoryRef(private=private, + referenced_by=obj, + call_number=call_number, + source_media_type=models.get_type(models.SourceMediaType, + source_media_type), + ref_object=repository, + order=count + 1) + repos_ref.save() + self.add_note_list(repos_ref, note_list) + + def add_family_ref(self, obj, handle): + try: + family = models.Family.objects.get(handle=handle) + except: + print(("ERROR: Family does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + #obj.families.add(family) + pfo = models.MyFamilies(person=obj, family=family, + order=len(models.MyFamilies.objects.filter(person=obj)) + 1) + pfo.save() + obj.save() + + ## Export individual objects: + + def add_source_attribute_list(self, source, attribute_list): + ## FIXME: dict to list + count = 1 + #for key in datamap_dict: + # value = datamap_dict[key] + # datamap = models.SourceDatamap(key=key, value=value, order=count) + # datamap.source = source + # datamap.save() + # count += 1 + + def add_citation_attribute_list(self, citation, attribute_list): + ## FIXME: dict to list + count = 1 + #for key in datamap_dict: + # value = datamap_dict[key] + # datamap = models.CitationDatamap(key=key, value=value, order=count) + # datamap.citation = citation + # datamap.save() + # count += 1 + + def add_lds(self, field, obj, data, order): + (lcitation_list, lnote_list, date, type, place_handle, + famc_handle, temple, status, private) = data + if place_handle: + try: + place = models.Place.objects.get(handle=place_handle) + except: + print(("ERROR: Place does not exist: '%s'" % + str(place_handle)), file=sys.stderr) + place = None + else: + place = None + if famc_handle: + try: + famc = models.Family.objects.get(handle=famc_handle) + except: + print(("ERROR: Family does not exist: '%s'" % + str(famc_handle)), file=sys.stderr) + famc = None + else: + famc = None + lds = models.Lds(lds_type = models.get_type(models.LdsType, type), + temple=temple, + place=place, + famc=famc, + order=order, + status = models.get_type(models.LdsStatus, status), + private=private) + self.add_date(lds, date) + lds.save() + self.add_note_list(lds, lnote_list) + self.add_citation_list(lds, lcitation_list) + if field == "person": + lds.person = obj + elif field == "family": + lds.family = obj + else: + raise AttributeError("invalid field '%s' to attach lds" % + str(field)) + lds.save() + return lds + + def add_address(self, field, obj, address_data, order): + (private, acitation_list, anote_list, date, location) = address_data + address = models.Address(private=private, order=order) + self.add_date(address, date) + address.save() + self.add_location("address", address, location, 1) + self.add_note_list(address, anote_list) + self.add_citation_list(address, acitation_list) + if field == "person": + address.person = obj + elif field == "repository": + address.repository = obj + else: + raise AttributeError("invalid field '%s' to attach address" % + str(field)) + address.save() + #obj.save() + #obj.addresses.add(address) + #obj.save() + + def add_attribute(self, obj, attribute_data): + (private, citation_list, note_list, the_type, value) = attribute_data + attribute_type = models.get_type(models.AttributeType, the_type) + attribute = models.Attribute(private=private, + attribute_of=obj, + attribute_type=attribute_type, + value=value) + attribute.save() + self.add_citation_list(attribute, citation_list) + self.add_note_list(attribute, note_list) + #obj.attributes.add(attribute) + #obj.save() + + def add_url(self, field, obj, url_data, order): + (private, path, desc, type) = url_data + url = models.Url(private=private, + path=path, + desc=desc, + order=order, + url_type=models.get_type(models.UrlType, type)) + if field == "person": + url.person = obj + elif field == "repository": + url.repository = obj + elif field == "place": + url.place = obj + else: + raise AttributeError("invalid field '%s' to attach to url" % + str(field)) + url.save() + #obj.url_list.add(url) + #obj.save() + + def add_place_ref_default(self, obj, place, date=None): + count = place.references.count() + object_type = ContentType.objects.get_for_model(obj) + count = models.PlaceRef.objects.filter(object_id=obj.id, + object_type=object_type).count() + place_ref = models.PlaceRef(referenced_by=obj, + ref_object=place, + order=count + 1) + self.add_date(obj, date) + place_ref.save() + + def add_place_ref(self, obj, data): + place_handle, date = data + if place_handle: + try: + place = models.Place.objects.get(handle=place_handle) + except: + print(("ERROR: Place does not exist: '%s'" % str(place_handle)), file=sys.stderr) + #from gramps.gen.utils.debug import format_exception + #print("".join(format_exception()), file=sys.stderr) + return + object_type = ContentType.objects.get_for_model(obj) + count = models.PlaceRef.objects.filter(object_id=obj.id,object_type=object_type).count() + place_ref = models.PlaceRef(referenced_by=obj, ref_object=place, order=count + 1) + place_ref.save() + self.add_date(place_ref, date) + + def add_parent_family(self, person, parent_family_handle): + try: + family = models.Family.objects.get(handle=parent_family_handle) + except: + print(("ERROR: Family does not exist: '%s'" % + str(parent_family_handle)), file=sys.stderr) + return + #person.parent_families.add(family) + pfo = models.MyParentFamilies( + person=person, + family=family, + order=len(models.MyParentFamilies.objects.filter(person=person)) + 1) + pfo.save() + person.save() + + def add_date(self, obj, date): + if date is None: + (calendar, modifier, quality, text, sortval, newyear) = \ + (0, 0, 0, "", 0, 0) + day1, month1, year1, slash1 = 0, 0, 0, 0 + day2, month2, year2, slash2 = 0, 0, 0, 0 + else: + (calendar, modifier, quality, dateval, text, sortval, newyear) = date + if len(dateval) == 4: + day1, month1, year1, slash1 = dateval + day2, month2, year2, slash2 = 0, 0, 0, 0 + elif len(dateval) == 8: + day1, month1, year1, slash1, day2, month2, year2, slash2 = dateval + else: + raise AttributeError("ERROR: dateval format '%s'" % str(dateval)) + obj.calendar = calendar + obj.modifier = modifier + obj.quality = quality + obj.text = text + obj.sortval = sortval + obj.newyear = newyear + obj.day1 = day1 + obj.month1 = month1 + obj.year1 = year1 + obj.slash1 = slash1 + obj.day2 = day2 + obj.month2 = month2 + obj.year2 = year2 + obj.slash2 = slash2 + + def add_name(self, person, data, preferred): + if data: + (private, citation_list, note_list, date, + first_name, surname_list, suffix, title, + name_type, group_as, sort_as, + display_as, call, nick, famnick) = data + + count = person.name_set.count() + name = models.Name() + name.order = count + 1 + name.preferred = preferred + name.private = private + name.first_name = first_name + name.suffix = suffix + name.title = title + name.name_type = models.get_type(models.NameType, name_type) + name.group_as = group_as + name.sort_as = models.get_type(models.NameFormatType, sort_as) + name.display_as = models.get_type(models.NameFormatType, display_as) + name.call = call + name.nick = nick + name.famnick = famnick + # we know person exists + # needs to have an ID for key + name.person = person + self.add_date(name, date) + name.save() + self.add_surname_list(name, surname_list) + self.add_note_list(name, note_list) + self.add_citation_list(name, citation_list) + #person.save() + + ## Export primary objects: + + def add_person(self, data): + # Unpack from the BSDDB: + (handle, # 0 + gid, # 1 + gender, # 2 + primary_name, # 3 + alternate_names, # 4 + death_ref_index, # 5 + birth_ref_index, # 6 + event_ref_list, # 7 + family_list, # 8 + parent_family_list, # 9 + media_list, # 10 + address_list, # 11 + attribute_list, # 12 + url_list, # 13 + lds_ord_list, # 14 + pcitation_list, # 15 + pnote_list, # 16 + change, # 17 + tag_list, # 18 + private, # 19 + person_ref_list, # 20 + ) = data + + person = models.Person(handle=handle, + gramps_id=gid, + last_changed=todate(change), + private=private, + gender_type=models.get_type(models.GenderType, gender)) + person.save(save_cache=False) + + def add_person_detail(self, data): + # Unpack from the BSDDB: + (handle, # 0 + gid, # 1 + gender, # 2 + primary_name, # 3 + alternate_names, # 4 + death_ref_index, # 5 + birth_ref_index, # 6 + event_ref_list, # 7 + family_list, # 8 + parent_family_list, # 9 + media_list, # 10 + address_list, # 11 + attribute_list, # 12 + url_list, # 13 + lds_ord_list, # 14 + pcitation_list, # 15 + pnote_list, # 16 + change, # 17 + tag_list, # 18 + private, # 19 + person_ref_list, # 20 + ) = data + + try: + person = models.Person.objects.get(handle=handle) + except: + print(("ERROR: Person does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + if primary_name: + self.add_name(person, primary_name, True) + self.add_alternate_name_list(person, alternate_names) + self.add_event_ref_list(person, event_ref_list) + self.add_family_ref_list(person, family_list) + self.add_parent_family_list(person, parent_family_list) + self.add_media_ref_list(person, media_list) + self.add_note_list(person, pnote_list) + self.add_attribute_list(person, attribute_list) + self.add_url_list("person", person, url_list) + self.add_person_ref_list(person, person_ref_list) + self.add_citation_list(person, pcitation_list) + self.add_address_list("person", person, address_list) + self.add_lds_list("person", person, lds_ord_list) + self.add_tag_list(person, tag_list) + # set person.birth and birth.death to correct events: + + obj_type = ContentType.objects.get_for_model(person) + events = models.EventRef.objects.filter( + object_id=person.id, + object_type=obj_type, + ref_object__event_type__val=models.EventType.BIRTH).order_by("order") + + all_events = self.get_event_ref_list(person) + if events: + person.birth = events[0].ref_object + person.birth_ref_index = lookup_role_index(models.EventType.BIRTH, all_events) + + events = models.EventRef.objects.filter( + object_id=person.id, + object_type=obj_type, + ref_object__event_type__val=models.EventType.DEATH).order_by("order") + if events: + person.death = events[0].ref_object + person.death_ref_index = lookup_role_index(models.EventType.DEATH, all_events) + person.save() + return person + + def save_note_markup(self, note, markup_list): + # delete any prexisting markup: + models.Markup.objects.filter(note=note).delete() + count = 1 + for markup in markup_list: + markup_code, value, start_stop_list = markup + m = models.Markup( + note=note, + order=count, + styled_text_tag_type=models.get_type(models.StyledTextTagType, + markup_code, + get_or_create=False), + string=value, + start_stop_list=str(start_stop_list)) + m.save() + + def add_note(self, data): + # Unpack from the BSDDB: + (handle, gid, styled_text, format, note_type, + change, tag_list, private) = data + text, markup_list = styled_text + n = models.Note(handle=handle, + gramps_id=gid, + last_changed=todate(change), + private=private, + preformatted=format, + text=text, + note_type=models.get_type(models.NoteType, note_type)) + n.save(save_cache=False) + self.save_note_markup(n, markup_list) + + def add_note_detail(self, data): + # Unpack from the BSDDB: + (handle, gid, styled_text, format, note_type, + change, tag_list, private) = data + note = models.Note.objects.get(handle=handle) + note.save(save_cache=False) + self.add_tag_list(note, tag_list) + note.save_cache() + + def add_family(self, data): + # Unpack from the BSDDB: + (handle, gid, father_handle, mother_handle, + child_ref_list, the_type, event_ref_list, media_list, + attribute_list, lds_seal_list, citation_list, note_list, + change, tag_list, private) = data + + family = models.Family(handle=handle, gramps_id=gid, + family_rel_type = models.get_type(models.FamilyRelType, the_type), + last_changed=todate(change), + private=private) + family.save(save_cache=False) + + def add_family_detail(self, data): + # Unpack from the BSDDB: + (handle, gid, father_handle, mother_handle, + child_ref_list, the_type, event_ref_list, media_list, + attribute_list, lds_seal_list, citation_list, note_list, + change, tag_list, private) = data + + try: + family = models.Family.objects.get(handle=handle) + except: + print(("ERROR: Family does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + # father_handle and/or mother_handle can be None + if father_handle: + try: + family.father = models.Person.objects.get(handle=father_handle) + except: + print(("ERROR: Father does not exist: '%s'" % + str(father_handle)), file=sys.stderr) + family.father = None + if mother_handle: + try: + family.mother = models.Person.objects.get(handle=mother_handle) + except: + print(("ERROR: Mother does not exist: '%s'" % + str(mother_handle)), file=sys.stderr) + family.mother = None + family.save(save_cache=False) + self.add_child_ref_list(family, child_ref_list) + self.add_note_list(family, note_list) + self.add_attribute_list(family, attribute_list) + self.add_citation_list(family, citation_list) + self.add_media_ref_list(family, media_list) + self.add_event_ref_list(family, event_ref_list) + self.add_lds_list("family", family, lds_seal_list) + self.add_tag_list(family, tag_list) + family.save_cache() + + def add_source(self, data): + (handle, gid, title, + author, pubinfo, + note_list, + media_list, + abbrev, + change, attribute_list, + reporef_list, + tag_list, + private) = data + source = models.Source(handle=handle, gramps_id=gid, title=title, + author=author, pubinfo=pubinfo, abbrev=abbrev, + last_changed=todate(change), private=private) + source.save(save_cache=False) + + def add_source_detail(self, data): + (handle, gid, title, + author, pubinfo, + note_list, + media_list, + abbrev, + change, attribute_list, + reporef_list, + tag_list, + private) = data + try: + source = models.Source.objects.get(handle=handle) + except: + print(("ERROR: Source does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + source.save(save_cache=False) + self.add_note_list(source, note_list) + self.add_media_ref_list(source, media_list) + self.add_source_attribute_list(source, attribute_list) + self.add_repository_ref_list(source, reporef_list) + self.add_tag_list(source, tag_list) + source.save_cache() + + def add_repository(self, data): + (handle, gid, the_type, name, note_list, + address_list, url_list, change, tag_list, private) = data + + repository = models.Repository(handle=handle, + gramps_id=gid, + last_changed=todate(change), + private=private, + repository_type=models.get_type(models.RepositoryType, the_type), + name=name) + repository.save(save_cache=False) + + def add_repository_detail(self, data): + (handle, gid, the_type, name, note_list, + address_list, url_list, change, tag_list, private) = data + try: + repository = models.Repository.objects.get(handle=handle) + except: + print(("ERROR: Repository does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + repository.save(save_cache=False) + self.add_note_list(repository, note_list) + self.add_url_list("repository", repository, url_list) + self.add_address_list("repository", repository, address_list) + self.add_tag_list(repository, tag_list) + repository.save_cache() + + def add_location(self, field, obj, location_data, order): + # location now has 8 items + # street, locality, city, county, state, + # country, postal, phone, parish + + if location_data == None: return + if len(location_data) == 8: + (street, locality, city, county, state, country, postal, phone) = location_data + parish = None + elif len(location_data) == 2: + ((street, locality, city, county, state, country, postal, phone), parish) = location_data + else: + print(("ERROR: unknown location: '%s'" % + str(location_data)), file=sys.stderr) + (street, locality, city, county, state, country, postal, phone, parish) = \ + ("", "", "", "", "", "", "", "", "") + location = models.Location(street = street, + locality = locality, + city = city, + county = county, + state = state, + country = country, + postal = postal, + phone = phone, + parish = parish, + order = order) + if field == "address": + location.address = obj + elif field == "place": + location.place = obj + else: + raise AttributeError("invalid field '%s' to attach to location" % + str(field)) + location.save() + #obj.locations.add(location) + #obj.save() + + def add_place(self, data): + ## ('cef246c95c132bcf6a0255d4d17', 'P0036', 'Santa Clara Co., CA, USA', '', '', [('cef243fb5634559442323368f63', None)], 'Santa Clara Co.', [], (3, ''), '', [], [], [], [], [], 1422124781, [], False) + (handle, gid, title, long, lat, + place_ref_list, + name, + alt_name_list, + place_type, + code, + alt_location_list, + url_list, + media_list, + citation_list, + note_list, + change, + tag_list, + private) = data + place = models.Place( + handle=handle, + gramps_id=gid, + title=title, + long=long, + lat=lat, + name=name, + place_type=models.get_type(models.PlaceType, place_type), + code=code, + last_changed=todate(change), + private=private) + try: + place.save(save_cache=False) + except: + print("FIXME: error in saving place") + + def add_place_detail(self, data): + (handle, gid, title, long, lat, + place_ref_list, + name, + alt_name_list, + place_type, + code, + alt_location_list, + url_list, + media_list, + citation_list, + note_list, + change, + tag_list, + private) = data + try: + place = models.Place.objects.get(handle=handle) + except: + print(("ERROR: Place does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + place.save(save_cache=False) + self.add_url_list("place", place, url_list) + self.add_media_ref_list(place, media_list) + self.add_citation_list(place, citation_list) + self.add_note_list(place, note_list) + self.add_tag_list(place, tag_list) + self.add_place_ref_list(place, place_ref_list) + self.add_alt_name_list(place, alt_name_list) + count = 1 + for loc_data in alt_location_list: + self.add_location("place", place, loc_data, count) + count + 1 + place.save_cache() + + def add_tag(self, data): + (handle, + name, + color, + priority, + change) = data + tag = models.Tag(handle=handle, + gramps_id=create_id(), + name=name, + color=color, + priority=priority, + last_changed=todate(change)) + tag.save(save_cache=False) + + def add_tag_detail(self, data): + (handle, + name, + color, + priority, + change) = data + tag = models.Tag.objects.get(handle=handle) + tag.save() + + def add_media(self, data): + (handle, gid, path, mime, desc, + checksum, + attribute_list, + citation_list, + note_list, + change, + date, + tag_list, + private) = data + media = models.Media(handle=handle, gramps_id=gid, + path=path, mime=mime, checksum=checksum, + desc=desc, last_changed=todate(change), + private=private) + self.add_date(media, date) + media.save(save_cache=False) + + def add_media_detail(self, data): + (handle, gid, path, mime, desc, + checksum, + attribute_list, + citation_list, + note_list, + change, + date, + tag_list, + private) = data + try: + media = models.Media.objects.get(handle=handle) + except: + print(("ERROR: Media does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + media.save(save_cache=False) + self.add_note_list(media, note_list) + self.add_citation_list(media, citation_list) + self.add_attribute_list(media, attribute_list) + self.add_tag_list(media, tag_list) + media.save_cache() + + def add_event(self, data): + (handle, gid, the_type, date, description, place_handle, + citation_list, note_list, media_list, attribute_list, + change, tag_list, private) = data + event = models.Event(handle=handle, + gramps_id=gid, + event_type=models.get_type(models.EventType, the_type), + private=private, + description=description, + last_changed=todate(change)) + self.add_date(event, date) + event.save(save_cache=False) + + def add_event_detail(self, data): + (handle, gid, the_type, date, description, place_handle, + citation_list, note_list, media_list, attribute_list, + change, tag_list, private) = data + try: + event = models.Event.objects.get(handle=handle) + except: + print(("ERROR: Event does not exist: '%s'" % + str(handle)), file=sys.stderr) + return + try: + place = models.Place.objects.get(handle=place_handle) + except: + place = None + print(("ERROR: Place does not exist: '%s'" % + str(place_handle)), file=sys.stderr) + event.place = place + event.save(save_cache=False) + self.add_note_list(event, note_list) + self.add_attribute_list(event, attribute_list) + self.add_media_ref_list(event, media_list) + self.add_citation_list(event, citation_list) + self.add_tag_list(event, tag_list) + event.save_cache() + + def get_raw(self, item): + """ + Build and return the raw, serialized data of an object. + """ + if isinstance(item, models.Person): + raw = self.get_person(item) + elif isinstance(item, models.Family): + raw = self.get_family(item) + elif isinstance(item, models.Place): + raw = self.get_place(item) + elif isinstance(item, models.Media): + raw = self.get_media(item) + elif isinstance(item, models.Source): + raw = self.get_source(item) + elif isinstance(item, models.Citation): + raw = self.get_citation(item) + elif isinstance(item, models.Repository): + raw = self.get_repository(item) + elif isinstance(item, models.Note): + raw = self.get_note(item) + elif isinstance(item, models.Event): + raw = self.get_event(item) + else: + raise Exception("Don't know how to get raw '%s'" % type(item)) + return raw + + def check_caches(self, callback=None): + """ + Call this to check the caches for all primary models. + """ + if not isinstance(callback, collections.Callable): + callback = lambda percent: None # dummy + + callback(0) + count = 0.0 + total = (self.Note.all().count() + + self.Person.all().count() + + self.Event.all().count() + + self.Family.all().count() + + self.Repository.all().count() + + self.Place.all().count() + + self.Media.all().count() + + self.Source.all().count() + + self.Citation.all().count() + + self.Tag.all().count()) + + for item in self.Note.all(): + raw = self.get_note(item) + check_diff(item, raw) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Person.all(): + raw = self.get_person(item) + check_diff(item, raw) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Family.all(): + raw = self.get_family(item) + check_diff(item, raw) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Source.all(): + raw = self.get_source(item) + check_diff(item, raw) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Event.all(): + raw = self.get_event(item) + check_diff(item, raw) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Repository.all(): + raw = self.get_repository(item) + check_diff(item, raw) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Place.all(): + raw = self.get_place(item) + check_diff(item, raw) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Media.all(): + raw = self.get_media(item) + check_diff(item, raw) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Citation.all(): + raw = self.get_citation(item) + check_diff(item, raw) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Tag.all(): + raw = self.get_tag(item) + check_diff(item, raw) + count += 1 + callback(100) + + def check_families(self): + """ + Check family structures. + """ + for family in self.Family.all(): + if family.mother: + if not family in family.mother.families.all(): + print("Mother not in family", mother, family) + if family.father: + if not family in family.father.families.all(): + print("Father not in family", mother, family) + for child in family.get_children(): + if family not in child.parent_families.all(): + print("Child not in family", child, family) + for person in self.Person.all(): + for family in person.families.all(): + if person not in [family.mother, family.father]: + print("Spouse not in family", person, family) + for family in person.parent_families.all(): + if person not in family.get_children(): + print("Child not in family", person, family) + + def is_public(self, obj, objref): + """ + Returns whether or not an item is "public", and the reason + why/why not. + + @param obj - an instance of any Primary object + @param objref - one of the PrimaryRef.objects + @return - a tuple containing a boolean (public?) and reason. + + There are three reasons why an item might not be public: + 1) The item itself is private. + 2) The item is referenced by a living Person. + 3) The item is referenced by some other private item. + """ + # If it is private, then no: + if obj.private: + return (False, "It is marked private.") + elif hasattr(obj, "probably_alive") and obj.probably_alive: + return (False, "It is marked probaby alive.") + elif hasattr(obj, "mother") and obj.mother: + public, reason = self.is_public(obj.mother, self.PersonRef) + if not public: + return public, reason + elif hasattr(obj, "father") and obj.father: + public, reason = self.is_public(obj.father, self.PersonRef) + if not public: + return public, reason + # FIXME: what about Associations... anything else? Check PrivateProxy + if objref: + if hasattr(objref.model, "ref_object"): + obj_ref_list = objref.filter(ref_object=obj) + elif hasattr(objref.model, "citation"): + obj_ref_list = objref.filter(citation=obj) + else: + raise Exception("objref '%s' needs a ref for '%s'" % (objref.model, obj)) + for reference in obj_ref_list: + ref_from_class = reference.object_type.model_class() + item = None + try: + item = ref_from_class.objects.get(id=reference.object_id) + except: + print("Warning: Corrupt reference: %s" % str(reference)) + continue + # If it is linked to by someone alive? public = False + if hasattr(item, "probably_alive") and item.probably_alive: + return (False, "It is referenced by someone who is probaby alive.") + # If it is linked to by something private? public = False + elif item.private: + return (False, "It is referenced by an item which is marked private.") + return (True, "It is visible to the public.") + + def update_public(self, obj, save=True): + """ + >>> dji.update_public(event) + + Given an Event or other instance, update the event's public + status, or any event referenced to by the instance. + + For example, if a person is found to be alive, then the + referenced events should be marked not public (public = False). + + """ + from gramps.webapp.utils import probably_alive + if obj.__class__.__name__ == "Event": + objref = self.EventRef + elif obj.__class__.__name__ == "Person": + objref = self.PersonRef + elif obj.__class__.__name__ == "Note": + objref = self.NoteRef + elif obj.__class__.__name__ == "Repository": + objref = self.RepositoryRef + elif obj.__class__.__name__ == "Citation": + objref = self.CitationRef + elif obj.__class__.__name__ == "Media": + objref = self.MediaRef + elif obj.__class__.__name__ == "Place": # no need for dependency + objref = None + elif obj.__class__.__name__ == "Source": # no need for dependency + objref = None + elif obj.__class__.__name__ == "Family": + objref = self.ChildRef # correct? + else: + raise Exception("Can't compute public of type '%s'" % str(obj)) + public, reason = self.is_public(obj, objref) # correct? + # Ok, update, if needed: + if obj.public != public: + obj.public = public + if save: + print("Updating public:", obj.__class__.__name__, obj.gramps_id) + obj.save() + #log = self.Log() + #log.referenced_by = obj + #log.object_id = obj.id + #log.object_type = obj_type + #log.log_type = "update public status" + #log.reason = reason + #log.order = 0 + #log.save() + + def update_publics(self, callback=None): + """ + Call this to update probably_alive for all primary models. + """ + if not isinstance(callback, collections.Callable): + callback = lambda percent: None # dummy + + callback(0) + count = 0.0 + total = (self.Note.all().count() + + self.Person.all().count() + + self.Event.all().count() + + self.Family.all().count() + + self.Repository.all().count() + + self.Place.all().count() + + self.Media.all().count() + + self.Source.all().count() + + self.Citation.all().count()) + + for item in self.Note.all(): + self.update_public(item) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Person.all(): + self.update_public(item) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Family.all(): + self.update_public(item) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Source.all(): + self.update_public(item) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Event.all(): + self.update_public(item) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Repository.all(): + self.update_public(item) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Place.all(): + self.update_public(item) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Media.all(): + self.update_public(item) + count += 1 + callback(100 * (count/total if total else 0)) + + for item in self.Citation.all(): + self.update_public(item) + count += 1 + callback(100 * (count/total if total else 0)) + + def update_probably_alive(self, callback=None): + """ + Call this to update primary_alive for people. + """ + from gramps.webapp.utils import probably_alive + if not isinstance(callback, collections.Callable): + callback = lambda percent: None # dummy + callback(0) + count = 0.0 + total = self.Person.all().count() + for item in self.Person.all(): + pa = probably_alive(item.handle) + if pa != item.probably_alive: + print("Updating probably_alive") + item.probably_alive = pa + item.save() + count += 1 + callback(100 * (count/total if total else 0)) diff --git a/gramps/plugins/database/djangodb.gpr.py b/gramps/plugins/database/djangodb.gpr.py new file mode 100644 index 000000000..57b30f2f5 --- /dev/null +++ b/gramps/plugins/database/djangodb.gpr.py @@ -0,0 +1,31 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2015 Douglas Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +plg = newplugin() +plg.id = 'djangodb' +plg.name = _("Django Database Backend") +plg.name_accell = _("_Django Database Backend") +plg.description = _("Django Object Relational Model Database Backend") +plg.version = '1.0' +plg.gramps_target_version = "4.2" +plg.status = STABLE +plg.fname = 'djangodb.py' +plg.ptype = DATABASE +plg.databaseclass = 'DbDjango' diff --git a/gramps/plugins/database/djangodb.py b/gramps/plugins/database/djangodb.py new file mode 100644 index 000000000..adb28dc54 --- /dev/null +++ b/gramps/plugins/database/djangodb.py @@ -0,0 +1,2036 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +""" Implements a Db interface """ + +#------------------------------------------------------------------------ +# +# Python Modules +# +#------------------------------------------------------------------------ +import sys +import time +import re +import base64 +import pickle +import os + +#------------------------------------------------------------------------ +# +# Gramps Modules +# +#------------------------------------------------------------------------ +import gramps +from gramps.gen.lib import (Person, Family, Event, Place, Repository, + Citation, Source, Note, MediaObject, Tag, + Researcher) +from gramps.gen.db import DbReadBase, DbWriteBase, DbTxn +from gramps.gen.utils.callback import Callback +from gramps.gen.updatecallback import UpdateCallback +from gramps.gen.db import (PERSON_KEY, + FAMILY_KEY, + CITATION_KEY, + SOURCE_KEY, + EVENT_KEY, + MEDIA_KEY, + PLACE_KEY, + REPOSITORY_KEY, + NOTE_KEY) +from gramps.gen.utils.id import create_id +from django.db import transaction + +class Environment(object): + """ + Implements the Environment API. + """ + def __init__(self, db): + self.db = db + + def txn_begin(self): + return DjangoTxn("DbDjango Transaction", self.db) + +class Table(object): + """ + Implements Table interface. + """ + def __init__(self, funcs): + self.funcs = funcs + + def cursor(self): + """ + Returns a Cursor for this Table. + """ + return self.funcs["cursor_func"]() + + def put(key, data, txn=None): + self[key] = data + +class Map(dict): + """ + Implements the map API for person_map, etc. + + Takes a Table() as argument. + """ + def __init__(self, tbl, *args, **kwargs): + super().__init__(*args, **kwargs) + self.db = tbl + +class MetaCursor(object): + def __init__(self): + pass + def __enter__(self): + return self + def __iter__(self): + return self.__next__() + def __next__(self): + yield None + def __exit__(self, *args, **kwargs): + pass + def iter(self): + yield None + def first(self): + self._iter = self.__iter__() + return self.next() + def next(self): + try: + return next(self._iter) + except: + return None + def close(self): + pass + +class Cursor(object): + def __init__(self, model, func): + self.model = model + self.func = func + def __enter__(self): + return self + def __iter__(self): + return self.__next__() + def __next__(self): + for item in self.model.all(): + yield (bytes(item.handle, "utf-8"), self.func(item.handle)) + def __exit__(self, *args, **kwargs): + pass + def iter(self): + for item in self.model.all(): + yield (bytes(item.handle, "utf-8"), self.func(item.handle)) + yield None + def first(self): + self._iter = self.__iter__() + return self.next() + def next(self): + try: + return next(self._iter) + except: + return None + def close(self): + pass + +class Bookmarks(object): + def __init__(self): + self.handles = [] + def get(self): + return self.handles + def append(self, handle): + self.handles.append(handle) + +class DjangoTxn(DbTxn): + def __init__(self, message, db, table=None): + DbTxn.__init__(self, message, db) + self.table = table + + def get(self, key, default=None, txn=None, **kwargs): + """ + Returns the data object associated with key + """ + try: + return self.table.objects(handle=key) + except: + if txn and key in txn: + return txn[key] + else: + return None + + def put(self, handle, new_data, txn): + """ + """ + txn[handle] = new_data + + def commit(self): + pass + +class DbDjango(DbWriteBase, DbReadBase, UpdateCallback, Callback): + """ + A Gramps Database Backend. This replicates the grampsdb functions. + """ + # Set up dictionary for callback signal handler + # --------------------------------------------- + # 1. Signals for primary objects + __signals__ = dict((obj+'-'+op, signal) + for obj in + ['person', 'family', 'event', 'place', + 'source', 'citation', 'media', 'note', 'repository', 'tag'] + for op, signal in zip( + ['add', 'update', 'delete', 'rebuild'], + [(list,), (list,), (list,), None] + ) + ) + + # 2. Signals for long operations + __signals__.update(('long-op-'+op, signal) for op, signal in zip( + ['start', 'heartbeat', 'end'], + [(object,), None, None] + )) + + # 3. Special signal for change in home person + __signals__['home-person-changed'] = None + + # 4. Signal for change in person group name, parameters are + __signals__['person-groupname-rebuild'] = (str, str) + + def __init__(self, directory=None): + DbReadBase.__init__(self) + DbWriteBase.__init__(self) + Callback.__init__(self) + self._tables = { + 'Person': + { + "handle_func": self.get_person_from_handle, + "gramps_id_func": self.get_person_from_gramps_id, + "class_func": gramps.gen.lib.Person, + "cursor_func": self.get_person_cursor, + "handles_func": self.get_person_handles, + "iter_func": self.iter_people, + }, + 'Family': + { + "handle_func": self.get_family_from_handle, + "gramps_id_func": self.get_family_from_gramps_id, + "class_func": gramps.gen.lib.Family, + "cursor_func": self.get_family_cursor, + "handles_func": self.get_family_handles, + "iter_func": self.iter_families, + }, + 'Source': + { + "handle_func": self.get_source_from_handle, + "gramps_id_func": self.get_source_from_gramps_id, + "class_func": gramps.gen.lib.Source, + "cursor_func": self.get_source_cursor, + "handles_func": self.get_source_handles, + "iter_func": self.iter_sources, + }, + 'Citation': + { + "handle_func": self.get_citation_from_handle, + "gramps_id_func": self.get_citation_from_gramps_id, + "class_func": gramps.gen.lib.Citation, + "cursor_func": self.get_citation_cursor, + "handles_func": self.get_citation_handles, + "iter_func": self.iter_citations, + }, + 'Event': + { + "handle_func": self.get_event_from_handle, + "gramps_id_func": self.get_event_from_gramps_id, + "class_func": gramps.gen.lib.Event, + "cursor_func": self.get_event_cursor, + "handles_func": self.get_event_handles, + "iter_func": self.iter_events, + }, + 'Media': + { + "handle_func": self.get_object_from_handle, + "gramps_id_func": self.get_object_from_gramps_id, + "class_func": gramps.gen.lib.MediaObject, + "cursor_func": self.get_media_cursor, + "handles_func": self.get_media_object_handles, + "iter_func": self.iter_media_objects, + }, + 'Place': + { + "handle_func": self.get_place_from_handle, + "gramps_id_func": self.get_place_from_gramps_id, + "class_func": gramps.gen.lib.Place, + "cursor_func": self.get_place_cursor, + "handles_func": self.get_place_handles, + "iter_func": self.iter_places, + }, + 'Repository': + { + "handle_func": self.get_repository_from_handle, + "gramps_id_func": self.get_repository_from_gramps_id, + "class_func": gramps.gen.lib.Repository, + "cursor_func": self.get_repository_cursor, + "handles_func": self.get_repository_handles, + "iter_func": self.iter_repositories, + }, + 'Note': + { + "handle_func": self.get_note_from_handle, + "gramps_id_func": self.get_note_from_gramps_id, + "class_func": gramps.gen.lib.Note, + "cursor_func": self.get_note_cursor, + "handles_func": self.get_note_handles, + "iter_func": self.iter_notes, + }, + 'Tag': + { + "handle_func": self.get_tag_from_handle, + "gramps_id_func": None, + "class_func": gramps.gen.lib.Tag, + "cursor_func": self.get_tag_cursor, + "handles_func": self.get_tag_handles, + "iter_func": self.iter_tags, + }, + } + # skip GEDCOM cross-ref check for now: + self.set_feature("skip-check-xref", True) + self.readonly = False + self.db_is_open = True + self.name_formats = [] + self.bookmarks = Bookmarks() + self.undo_callback = None + self.redo_callback = None + self.undo_history_callback = None + self.modified = 0 + self.txn = DjangoTxn("DbDjango Transaction", self) + self.transaction = None + # Import cache for gedcom import, uses transactions, and + # two step adding of objects. + self.import_cache = {} + self.use_import_cache = False + self.use_db_cache = True + self._directory = directory + if directory: + self.load(directory) + + def load(self, directory, pulse_progress=None, mode=None): + self._directory = directory + from django.conf import settings + default_settings = {} + settings_file = os.path.join(directory, "default_settings.py") + with open(settings_file) as f: + code = compile(f.read(), settings_file, 'exec') + exec(code, globals(), default_settings) + + class Module(object): + def __init__(self, dictionary): + self.dictionary = dictionary + def __getattr__(self, item): + return self.dictionary[item] + + try: + settings.configure(Module(default_settings)) + except RuntimeError: + # already configured; ignore + pass + + import django + django.setup() + + from django_support.libdjango import DjangoInterface + self.dji = DjangoInterface() + self.family_bookmarks = Bookmarks() + self.event_bookmarks = Bookmarks() + self.place_bookmarks = Bookmarks() + self.citation_bookmarks = Bookmarks() + self.source_bookmarks = Bookmarks() + self.repo_bookmarks = Bookmarks() + self.media_bookmarks = Bookmarks() + self.note_bookmarks = Bookmarks() + self.set_person_id_prefix('I%04d') + self.set_object_id_prefix('O%04d') + self.set_family_id_prefix('F%04d') + self.set_citation_id_prefix('C%04d') + self.set_source_id_prefix('S%04d') + self.set_place_id_prefix('P%04d') + self.set_event_id_prefix('E%04d') + self.set_repository_id_prefix('R%04d') + self.set_note_id_prefix('N%04d') + # ---------------------------------- + self.id_trans = DjangoTxn("ID Transaction", self, self.dji.Person) + self.fid_trans = DjangoTxn("FID Transaction", self, self.dji.Family) + self.pid_trans = DjangoTxn("PID Transaction", self, self.dji.Place) + self.cid_trans = DjangoTxn("CID Transaction", self, self.dji.Citation) + self.sid_trans = DjangoTxn("SID Transaction", self, self.dji.Source) + self.oid_trans = DjangoTxn("OID Transaction", self, self.dji.Media) + self.rid_trans = DjangoTxn("RID Transaction", self, self.dji.Repository) + self.nid_trans = DjangoTxn("NID Transaction", self, self.dji.Note) + self.eid_trans = DjangoTxn("EID Transaction", self, self.dji.Event) + self.cmap_index = 0 + self.smap_index = 0 + self.emap_index = 0 + self.pmap_index = 0 + self.fmap_index = 0 + self.lmap_index = 0 + self.omap_index = 0 + self.rmap_index = 0 + self.nmap_index = 0 + self.env = Environment(self) + self.person_map = Map(Table(self._tables["Person"])) + self.family_map = Map(Table(self._tables["Family"])) + self.place_map = Map(Table(self._tables["Place"])) + self.citation_map = Map(Table(self._tables["Citation"])) + self.source_map = Map(Table(self._tables["Source"])) + self.repository_map = Map(Table(self._tables["Repository"])) + self.note_map = Map(Table(self._tables["Note"])) + self.media_map = Map(Table(self._tables["Media"])) + self.event_map = Map(Table(self._tables["Event"])) + self.tag_map = Map(Table(self._tables["Tag"])) + self.metadata = Map(Table({"cursor_func": lambda: MetaCursor()})) + self.name_group = {} + self.event_names = set() + self.individual_attributes = set() + self.family_attributes = set() + self.source_attributes = set() + self.child_ref_types = set() + self.family_rel_types = set() + self.event_role_names = set() + self.name_types = set() + self.origin_types = set() + self.repository_types = set() + self.note_types = set() + self.source_media_types = set() + self.url_types = set() + self.media_attributes = set() + self.place_types = set() + + def prepare_import(self): + """ + DbDjango does not commit data on gedcom import, but saves them + for later commit. + """ + self.use_import_cache = True + self.import_cache = {} + + @transaction.atomic + def commit_import(self): + """ + Commits the items that were queued up during the last gedcom + import for two step adding. + """ + # First we add the primary objects: + for key in list(self.import_cache.keys()): + obj = self.import_cache[key] + if isinstance(obj, Person): + self.dji.add_person(obj.serialize()) + elif isinstance(obj, Family): + self.dji.add_family(obj.serialize()) + elif isinstance(obj, Event): + self.dji.add_event(obj.serialize()) + elif isinstance(obj, Place): + self.dji.add_place(obj.serialize()) + elif isinstance(obj, Repository): + self.dji.add_repository(obj.serialize()) + elif isinstance(obj, Citation): + self.dji.add_citation(obj.serialize()) + elif isinstance(obj, Source): + self.dji.add_source(obj.serialize()) + elif isinstance(obj, Note): + self.dji.add_note(obj.serialize()) + elif isinstance(obj, MediaObject): + self.dji.add_media(obj.serialize()) + elif isinstance(obj, Tag): + self.dji.add_tag(obj.serialize()) + # Next we add the links: + for key in list(self.import_cache.keys()): + obj = self.import_cache[key] + if isinstance(obj, Person): + self.dji.add_person_detail(obj.serialize()) + elif isinstance(obj, Family): + self.dji.add_family_detail(obj.serialize()) + elif isinstance(obj, Event): + self.dji.add_event_detail(obj.serialize()) + elif isinstance(obj, Place): + self.dji.add_place_detail(obj.serialize()) + elif isinstance(obj, Repository): + self.dji.add_repository_detail(obj.serialize()) + elif isinstance(obj, Citation): + self.dji.add_citation_detail(obj.serialize()) + elif isinstance(obj, Source): + self.dji.add_source_detail(obj.serialize()) + elif isinstance(obj, Note): + self.dji.add_note_detail(obj.serialize()) + elif isinstance(obj, MediaObject): + self.dji.add_media_detail(obj.serialize()) + elif isinstance(obj, Tag): + self.dji.add_tag_detail(obj.serialize()) + self.use_import_cache = False + self.import_cache = {} + self.dji.update_publics() + + def transaction_commit(self, txn): + pass + + def request_rebuild(self): + # caches are ok, but let's compute public's + self.dji.update_publics() + self.emit('person-rebuild') + self.emit('family-rebuild') + self.emit('place-rebuild') + self.emit('source-rebuild') + self.emit('citation-rebuild') + self.emit('media-rebuild') + self.emit('event-rebuild') + self.emit('repository-rebuild') + self.emit('note-rebuild') + self.emit('tag-rebuild') + + def get_undodb(self): + return None + + def transaction_abort(self, txn): + pass + + @staticmethod + def _validated_id_prefix(val, default): + if isinstance(val, str) and val: + try: + str_ = val % 1 + except TypeError: # missing conversion specifier + prefix_var = val + "%d" + except ValueError: # incomplete format + prefix_var = default+"%04d" + else: + prefix_var = val # OK as given + else: + prefix_var = default+"%04d" # not a string or empty string + return prefix_var + + @staticmethod + def __id2user_format(id_pattern): + """ + Return a method that accepts a Gramps ID and adjusts it to the users + format. + """ + pattern_match = re.match(r"(.*)%[0 ](\d+)[diu]$", id_pattern) + if pattern_match: + str_prefix = pattern_match.group(1) + nr_width = pattern_match.group(2) + def closure_func(gramps_id): + if gramps_id and gramps_id.startswith(str_prefix): + id_number = gramps_id[len(str_prefix):] + if id_number.isdigit(): + id_value = int(id_number, 10) + #if len(str(id_value)) > nr_width: + # # The ID to be imported is too large to fit in the + # # users format. For now just create a new ID, + # # because that is also what happens with IDs that + # # are identical to IDs already in the database. If + # # the problem of colliding import and already + # # present IDs is solved the code here also needs + # # some solution. + # gramps_id = id_pattern % 1 + #else: + gramps_id = id_pattern % id_value + return gramps_id + else: + def closure_func(gramps_id): + return gramps_id + return closure_func + + def set_person_id_prefix(self, val): + """ + Set the naming template for GRAMPS Person ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as I%d or I%04d. + """ + self.person_prefix = self._validated_id_prefix(val, "I") + self.id2user_format = self.__id2user_format(self.person_prefix) + + def set_citation_id_prefix(self, val): + """ + Set the naming template for GRAMPS Citation ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as C%d or C%04d. + """ + self.citation_prefix = self._validated_id_prefix(val, "C") + self.cid2user_format = self.__id2user_format(self.citation_prefix) + + def set_source_id_prefix(self, val): + """ + Set the naming template for GRAMPS Source ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as S%d or S%04d. + """ + self.source_prefix = self._validated_id_prefix(val, "S") + self.sid2user_format = self.__id2user_format(self.source_prefix) + + def set_object_id_prefix(self, val): + """ + Set the naming template for GRAMPS MediaObject ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as O%d or O%04d. + """ + self.mediaobject_prefix = self._validated_id_prefix(val, "O") + self.oid2user_format = self.__id2user_format(self.mediaobject_prefix) + + def set_place_id_prefix(self, val): + """ + Set the naming template for GRAMPS Place ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as P%d or P%04d. + """ + self.place_prefix = self._validated_id_prefix(val, "P") + self.pid2user_format = self.__id2user_format(self.place_prefix) + + def set_family_id_prefix(self, val): + """ + Set the naming template for GRAMPS Family ID values. The string is + expected to be in the form of a simple text string, or in a format + that contains a C/Python style format string using %d, such as F%d + or F%04d. + """ + self.family_prefix = self._validated_id_prefix(val, "F") + self.fid2user_format = self.__id2user_format(self.family_prefix) + + def set_event_id_prefix(self, val): + """ + Set the naming template for GRAMPS Event ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as E%d or E%04d. + """ + self.event_prefix = self._validated_id_prefix(val, "E") + self.eid2user_format = self.__id2user_format(self.event_prefix) + + def set_repository_id_prefix(self, val): + """ + Set the naming template for GRAMPS Repository ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as R%d or R%04d. + """ + self.repository_prefix = self._validated_id_prefix(val, "R") + self.rid2user_format = self.__id2user_format(self.repository_prefix) + + def set_note_id_prefix(self, val): + """ + Set the naming template for GRAMPS Note ID values. + + The string is expected to be in the form of a simple text string, or + in a format that contains a C/Python style format string using %d, + such as N%d or N%04d. + """ + self.note_prefix = self._validated_id_prefix(val, "N") + self.nid2user_format = self.__id2user_format(self.note_prefix) + + def __find_next_gramps_id(self, prefix, map_index, trans): + """ + Helper function for find_next__gramps_id methods + """ + index = prefix % map_index + while trans.get(str(index), txn=self.txn) is not None: + map_index += 1 + index = prefix % map_index + map_index += 1 + return (map_index, index) + + def find_next_person_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Person object based off the + person ID prefix. + """ + self.pmap_index, gid = self.__find_next_gramps_id(self.person_prefix, + self.pmap_index, self.id_trans) + return gid + + def find_next_place_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Place object based off the + place ID prefix. + """ + self.lmap_index, gid = self.__find_next_gramps_id(self.place_prefix, + self.lmap_index, self.pid_trans) + return gid + + def find_next_event_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Event object based off the + event ID prefix. + """ + self.emap_index, gid = self.__find_next_gramps_id(self.event_prefix, + self.emap_index, self.eid_trans) + return gid + + def find_next_object_gramps_id(self): + """ + Return the next available GRAMPS' ID for a MediaObject object based + off the media object ID prefix. + """ + self.omap_index, gid = self.__find_next_gramps_id(self.mediaobject_prefix, + self.omap_index, self.oid_trans) + return gid + + def find_next_citation_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Citation object based off the + citation ID prefix. + """ + self.cmap_index, gid = self.__find_next_gramps_id(self.citation_prefix, + self.cmap_index, self.cid_trans) + return gid + + def find_next_source_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Source object based off the + source ID prefix. + """ + self.smap_index, gid = self.__find_next_gramps_id(self.source_prefix, + self.smap_index, self.sid_trans) + return gid + + def find_next_family_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Family object based off the + family ID prefix. + """ + self.fmap_index, gid = self.__find_next_gramps_id(self.family_prefix, + self.fmap_index, self.fid_trans) + return gid + + def find_next_repository_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Respository object based + off the repository ID prefix. + """ + self.rmap_index, gid = self.__find_next_gramps_id(self.repository_prefix, + self.rmap_index, self.rid_trans) + return gid + + def find_next_note_gramps_id(self): + """ + Return the next available GRAMPS' ID for a Note object based off the + note ID prefix. + """ + self.nmap_index, gid = self.__find_next_gramps_id(self.note_prefix, + self.nmap_index, self.nid_trans) + return gid + + def get_mediapath(self): + return None + + def get_name_group_keys(self): + return [] + + def get_name_group_mapping(self, key): + return None + + def get_researcher(self): + obj = Researcher() + return obj + + def get_tag_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Tag.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Tag.all()] + + def get_person_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Person.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Person.all()] + + def get_family_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Family.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Family.all()] + + def get_event_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Event.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Event.all()] + + def get_citation_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Citation.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Citation.all()] + + def get_source_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Source.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Source.all()] + + def get_place_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Place.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Place.all()] + + def get_repository_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Repository.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Repository.all()] + + def get_media_object_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Media.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Media.all()] + + def get_note_handles(self, sort_handles=False): + if sort_handles: + return [item.handle for item in self.dji.Note.all().order_by("handle")] + else: + return [item.handle for item in self.dji.Note.all()] + + def get_media_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + media = self.dji.Media.get(handle=handle) + except: + return None + return self.make_media(media) + + def get_event_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + event = self.dji.Event.get(handle=handle) + except: + return None + return self.make_event(event) + + def get_family_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + family = self.dji.Family.get(handle=handle) + except: + return None + return self.make_family(family) + + def get_repository_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + repository = self.dji.Repository.get(handle=handle) + except: + return None + return self.make_repository(repository) + + def get_person_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + person = self.dji.Person.get(handle=handle) + except: + return None + return self.make_person(person) + + def get_tag_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + tag = self.dji.Tag.get(handle=handle) + except: + return None + return self.make_tag(tag) + + def make_repository(self, repository): + if self.use_db_cache and repository.cache: + data = repository.from_cache() + else: + data = self.dji.get_repository(repository) + return Repository.create(data) + + def make_citation(self, citation): + if self.use_db_cache and citation.cache: + data = citation.from_cache() + else: + data = self.dji.get_citation(citation) + return Citation.create(data) + + def make_source(self, source): + if self.use_db_cache and source.cache: + data = source.from_cache() + else: + data = self.dji.get_source(source) + return Source.create(data) + + def make_family(self, family): + if self.use_db_cache and family.cache: + data = family.from_cache() + else: + data = self.dji.get_family(family) + return Family.create(data) + + def make_person(self, person): + if self.use_db_cache and person.cache: + data = person.from_cache() + else: + data = self.dji.get_person(person) + return Person.create(data) + + def make_event(self, event): + if self.use_db_cache and event.cache: + data = event.from_cache() + else: + data = self.dji.get_event(event) + return Event.create(data) + + def make_note(self, note): + if self.use_db_cache and note.cache: + data = note.from_cache() + else: + data = self.dji.get_note(note) + return Note.create(data) + + def make_tag(self, tag): + data = self.dji.get_tag(tag) + return Tag.create(data) + + def make_place(self, place): + if self.use_db_cache and place.cache: + data = place.from_cache() + else: + data = self.dji.get_place(place) + return Place.create(data) + + def make_media(self, media): + if self.use_db_cache and media.cache: + data = media.from_cache() + else: + data = self.dji.get_media(media) + return MediaObject.create(data) + + def get_place_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + place = self.dji.Place.get(handle=handle) + except: + return None + return self.make_place(place) + + def get_citation_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + citation = self.dji.Citation.get(handle=handle) + except: + return None + return self.make_citation(citation) + + def get_source_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + source = self.dji.Source.get(handle=handle) + except: + return None + return self.make_source(source) + + def get_note_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + note = self.dji.Note.get(handle=handle) + except: + return None + return self.make_note(note) + + def get_object_from_handle(self, handle): + if handle in self.import_cache: + return self.import_cache[handle] + try: + media = self.dji.Media.get(handle=handle) + except: + return None + return self.make_media(media) + + def get_default_person(self): + people = self.dji.Person.all() + if people.count() > 0: + return self.make_person(people[0]) + return None + + def iter_people(self): + return (self.get_person_from_handle(person.handle) + for person in self.dji.Person.all()) + + def iter_person_handles(self): + return (person.handle for person in self.dji.Person.all()) + + def iter_families(self): + return (self.get_family_from_handle(family.handle) + for family in self.dji.Family.all()) + + def iter_family_handles(self): + return (family.handle for family in self.dji.Family.all()) + + def iter_notes(self): + return (self.get_note_from_handle(note.handle) + for note in self.dji.Note.all()) + + def iter_note_handles(self): + return (note.handle for note in self.dji.Note.all()) + + def iter_events(self): + return (self.get_event_from_handle(event.handle) + for event in self.dji.Event.all()) + + def iter_event_handles(self): + return (event.handle for event in self.dji.Event.all()) + + def iter_places(self): + return (self.get_place_from_handle(place.handle) + for place in self.dji.Place.all()) + + def iter_place_handles(self): + return (place.handle for place in self.dji.Place.all()) + + def iter_repositories(self): + return (self.get_repository_from_handle(repository.handle) + for repository in self.dji.Repository.all()) + + def iter_repository_handles(self): + return (repository.handle for repository in self.dji.Repository.all()) + + def iter_sources(self): + return (self.get_source_from_handle(source.handle) + for source in self.dji.Source.all()) + + def iter_source_handles(self): + return (source.handle for source in self.dji.Source.all()) + + def iter_citations(self): + return (self.get_citation_from_handle(citation.handle) + for citation in self.dji.Citation.all()) + + def iter_citation_handles(self): + return (citation.handle for citation in self.dji.Citation.all()) + + def iter_tags(self): + return (self.get_tag_from_handle(tag.handle) + for tag in self.dji.Tag.all()) + + def iter_tag_handles(self): + return (tag.handle for tag in self.dji.Tag.all()) + + def iter_media_objects(self): + return (self.get_media_from_handle(media.handle) + for media in self.dji.Media.all()) + + def get_tag_from_name(self, name): + try: + tag = self.dji.Tag.filter(name=name) + return self.make_tag(tag[0]) + except: + return None + + def get_person_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Person.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_person(match_list[0]) + else: + return None + + def get_family_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + try: + family = self.dji.Family.get(gramps_id=gramps_id) + except: + return None + return self.make_family(family) + + def get_source_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Source.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_source(match_list[0]) + else: + return None + + def get_citation_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Citation.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_citation(match_list[0]) + else: + return None + + def get_event_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Event.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_event(match_list[0]) + else: + return None + + def get_object_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Media.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_media(match_list[0]) + else: + return None + + def get_place_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Place.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_place(match_list[0]) + else: + return None + + def get_repository_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Repsoitory.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_repository(match_list[0]) + else: + return None + + def get_note_from_gramps_id(self, gramps_id): + if self.import_cache: + for handle in self.import_cache: + if self.import_cache[handle].gramps_id == gramps_id: + return self.import_cache[handle] + match_list = self.dji.Note.filter(gramps_id=gramps_id) + if match_list.count() > 0: + return self.make_note(match_list[0]) + else: + return None + + def get_number_of_people(self): + return self.dji.Person.count() + + def get_number_of_events(self): + return self.dji.Event.count() + + def get_number_of_places(self): + return self.dji.Place.count() + + def get_number_of_tags(self): + return self.dji.Tag.count() + + def get_number_of_families(self): + return self.dji.Family.count() + + def get_number_of_notes(self): + return self.dji.Note.count() + + def get_number_of_citations(self): + return self.dji.Citation.count() + + def get_number_of_sources(self): + return self.dji.Source.count() + + def get_number_of_media_objects(self): + return self.dji.Media.count() + + def get_number_of_repositories(self): + return self.dji.Repository.count() + + def get_place_cursor(self): + return Cursor(self.dji.Place, self.get_raw_place_data) + + def get_person_cursor(self): + return Cursor(self.dji.Person, self.get_raw_person_data) + + def get_family_cursor(self): + return Cursor(self.dji.Family, self.get_raw_family_data) + + def get_event_cursor(self): + return Cursor(self.dji.Event, self.get_raw_event_data) + + def get_citation_cursor(self): + return Cursor(self.dji.Citation, self.get_raw_citation_data) + + def get_source_cursor(self): + return Cursor(self.dji.Source, self.get_raw_source_data) + + def get_note_cursor(self): + return Cursor(self.dji.Note, self.get_raw_note_data) + + def get_tag_cursor(self): + return Cursor(self.dji.Tag, self.get_raw_tag_data) + + def get_repository_cursor(self): + return Cursor(self.dji.Repository, self.get_raw_repository_data) + + def get_media_cursor(self): + return Cursor(self.dji.Media, self.get_raw_object_data) + + def has_gramps_id(self, obj_key, gramps_id): + key2table = { + PERSON_KEY: self.dji.Person, + FAMILY_KEY: self.dji.Family, + SOURCE_KEY: self.dji.Source, + CITATION_KEY: self.dji.Citation, + EVENT_KEY: self.dji.Event, + MEDIA_KEY: self.dji.Media, + PLACE_KEY: self.dji.Place, + REPOSITORY_KEY: self.dji.Repository, + NOTE_KEY: self.dji.Note, + } + table = key2table[obj_key] + return table.filter(gramps_id=gramps_id).count() > 0 + + def has_person_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Person.filter(handle=handle).count() == 1 + + def has_family_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Family.filter(handle=handle).count() == 1 + + def has_citation_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Citation.filter(handle=handle).count() == 1 + + def has_source_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Source.filter(handle=handle).count() == 1 + + def has_repository_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Repository.filter(handle=handle).count() == 1 + + def has_note_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Note.filter(handle=handle).count() == 1 + + def has_place_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Place.filter(handle=handle).count() == 1 + + def has_event_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Event.filter(handle=handle).count() == 1 + + def has_tag_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Tag.filter(handle=handle).count() == 1 + + def has_object_handle(self, handle): + if handle in self.import_cache: + return True + return self.dji.Media.filter(handle=handle).count() == 1 + + def has_name_group_key(self, key): + # FIXME: + return False + + def set_name_group_mapping(self, key, value): + # FIXME: + pass + + def set_default_person_handle(self, handle): + pass + + def set_mediapath(self, mediapath): + pass + + def get_raw_person_data(self, handle): + try: + return self.dji.get_person(self.dji.Person.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_family_data(self, handle): + try: + return self.dji.get_family(self.dji.Family.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_citation_data(self, handle): + try: + return self.dji.get_citation(self.dji.Citation.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_source_data(self, handle): + try: + return self.dji.get_source(self.dji.Source.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_repository_data(self, handle): + try: + return self.dji.get_repository(self.dji.Repository.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_note_data(self, handle): + try: + return self.dji.get_note(self.dji.Note.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_place_data(self, handle): + try: + return self.dji.get_place(self.dji.Place.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_object_data(self, handle): + try: + return self.dji.get_media(self.dji.Media.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_tag_data(self, handle): + try: + return self.dji.get_tag(self.dji.Tag.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def get_raw_event_data(self, handle): + try: + return self.dji.get_event(self.dji.Event.get(handle=handle)) + except: + if handle in self.import_cache: + return self.import_cache[handle].serialize() + else: + return None + + def add_person(self, person, trans, set_gid=True): + if not person.handle: + person.handle = create_id() + if not person.gramps_id and set_gid: + person.gramps_id = self.find_next_person_gramps_id() + self.commit_person(person, trans) + self.emit("person-add", ([person.handle],)) + return person.handle + + def add_family(self, family, trans, set_gid=True): + if not family.handle: + family.handle = create_id() + if not family.gramps_id and set_gid: + family.gramps_id = self.find_next_family_gramps_id() + self.commit_family(family, trans) + self.emit("family-add", ([family.handle],)) + return family.handle + + def add_citation(self, citation, trans, set_gid=True): + if not citation.handle: + citation.handle = create_id() + if not citation.gramps_id and set_gid: + citation.gramps_id = self.find_next_citation_gramps_id() + self.commit_citation(citation, trans) + self.emit("citation-add", ([citation.handle],)) + return citation.handle + + def add_source(self, source, trans, set_gid=True): + if not source.handle: + source.handle = create_id() + if not source.gramps_id and set_gid: + source.gramps_id = self.find_next_source_gramps_id() + self.commit_source(source, trans) + self.emit("source-add", ([source.handle],)) + return source.handle + + def add_repository(self, repository, trans, set_gid=True): + if not repository.handle: + repository.handle = create_id() + if not repository.gramps_id and set_gid: + repository.gramps_id = self.find_next_repository_gramps_id() + self.commit_repository(repository, trans) + self.emit("repository-add", ([repository.handle],)) + return repository.handle + + def add_note(self, note, trans, set_gid=True): + if not note.handle: + note.handle = create_id() + if not note.gramps_id and set_gid: + note.gramps_id = self.find_next_note_gramps_id() + self.commit_note(note, trans) + self.emit("note-add", ([note.handle],)) + return note.handle + + def add_place(self, place, trans, set_gid=True): + if not place.handle: + place.handle = create_id() + if not place.gramps_id and set_gid: + place.gramps_id = self.find_next_place_gramps_id() + self.commit_place(place, trans) + return place.handle + + def add_event(self, event, trans, set_gid=True): + if not event.handle: + event.handle = create_id() + if not event.gramps_id and set_gid: + event.gramps_id = self.find_next_event_gramps_id() + self.commit_event(event, trans) + return event.handle + + def add_tag(self, tag, trans): + if not tag.handle: + tag.handle = create_id() + self.commit_event(tag, trans) + return tag.handle + + def add_object(self, obj, transaction, set_gid=True): + """ + Add a MediaObject to the database, assigning internal IDs if they have + not already been defined. + + If not set_gid, then gramps_id is not set. + """ + if not obj.handle: + obj.handle = create_id() + if not obj.gramps_id and set_gid: + obj.gramps_id = self.find_next_object_gramps_id() + self.commit_media_object(obj, transaction) + return obj.handle + + def commit_person(self, person, trans, change_time=None): + if self.use_import_cache: + self.import_cache[person.handle] = person + else: + raw = person.serialize() + items = self.dji.Person.filter(handle=person.handle) + if items.count() > 0: + # Hack, for the moment: delete and re-add + items[0].delete() + self.dji.add_person(person.serialize()) + self.dji.add_person_detail(person.serialize()) + if items.count() > 0: + self.emit("person-update", ([person.handle],)) + else: + self.emit("person-add", ([person.handle],)) + + def commit_family(self, family, trans, change_time=None): + if self.use_import_cache: + self.import_cache[family.handle] = family + else: + raw = family.serialize() + items = self.dji.Family.filter(handle=family.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_family(family.serialize()) + self.dji.add_family_detail(family.serialize()) + if items.count() > 0: + self.emit("family-update", ([family.handle],)) + else: + self.emit("family-add", ([family.handle],)) + + def commit_citation(self, citation, trans, change_time=None): + if self.use_import_cache: + self.import_cache[citation.handle] = citation + else: + raw = citation.serialize() + items = self.dji.Citation.filter(handle=citation.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_citation(citation.serialize()) + self.dji.add_citation_detail(citation.serialize()) + if items.count() > 0: + self.emit("citation-update", ([citation.handle],)) + else: + self.emit("citation-add", ([citation.handle],)) + + def commit_source(self, source, trans, change_time=None): + if self.use_import_cache: + self.import_cache[source.handle] = source + else: + raw = source.serialize() + items = self.dji.Source.filter(handle=source.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_source(source.serialize()) + self.dji.add_source_detail(source.serialize()) + if items.count() > 0: + self.emit("source-update", ([source.handle],)) + else: + self.emit("source-add", ([source.handle],)) + + def commit_repository(self, repository, trans, change_time=None): + if self.use_import_cache: + self.import_cache[repository.handle] = repository + else: + raw = repository.serialize() + items = self.dji.Repository.filter(handle=repository.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_repository(repository.serialize()) + self.dji.add_repository_detail(repository.serialize()) + if items.count() > 0: + self.emit("repository-update", ([repository.handle],)) + else: + self.emit("repository-add", ([repository.handle],)) + + def commit_note(self, note, trans, change_time=None): + if self.use_import_cache: + self.import_cache[note.handle] = note + else: + raw = note.serialize() + items = self.dji.Note.filter(handle=note.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_note(note.serialize()) + self.dji.add_note_detail(note.serialize()) + if items.count() > 0: + self.emit("note-update", ([note.handle],)) + else: + self.emit("note-add", ([note.handle],)) + + def commit_place(self, place, trans, change_time=None): + if self.use_import_cache: + self.import_cache[place.handle] = place + else: + raw = place.serialize() + items = self.dji.Place.filter(handle=place.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_place(place.serialize()) + self.dji.add_place_detail(place.serialize()) + if items.count() > 0: + self.emit("place-update", ([place.handle],)) + else: + self.emit("place-add", ([place.handle],)) + + def commit_event(self, event, trans, change_time=None): + if self.use_import_cache: + self.import_cache[event.handle] = event + else: + raw = event.serialize() + items = self.dji.Event.filter(handle=event.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_event(event.serialize()) + self.dji.add_event_detail(event.serialize()) + if items.count() > 0: + self.emit("event-update", ([event.handle],)) + else: + self.emit("event-add", ([event.handle],)) + + def commit_tag(self, tag, trans, change_time=None): + if self.use_import_cache: + self.import_cache[tag.handle] = tag + else: + raw = tag.serialize() + items = self.dji.Tag.filter(handle=tag.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_tag(tag.serialize()) + self.dji.add_tag_detail(tag.serialize()) + if items.count() > 0: + self.emit("tag-update", ([tag.handle],)) + else: + self.emit("tag-add", ([tag.handle],)) + + def commit_media_object(self, media, transaction, change_time=None): + """ + Commit the specified MediaObject to the database, storing the changes + as part of the transaction. + """ + if self.use_import_cache: + self.import_cache[obj.handle] = media + else: + raw = media.serialize() + items = self.dji.Media.filter(handle=media.handle) + if items.count() > 0: + items[0].delete() + self.dji.add_media(media.serialize()) + self.dji.add_media_detail(media.serialize()) + if items.count() > 0: + self.emit("media-update", ([media.handle],)) + else: + self.emit("media-add", ([media.handle],)) + + def get_gramps_ids(self, obj_key): + key2table = { + PERSON_KEY: self.id_trans, + FAMILY_KEY: self.fid_trans, + CITATION_KEY: self.cid_trans, + SOURCE_KEY: self.sid_trans, + EVENT_KEY: self.eid_trans, + MEDIA_KEY: self.oid_trans, + PLACE_KEY: self.pid_trans, + REPOSITORY_KEY: self.rid_trans, + NOTE_KEY: self.nid_trans, + } + + table = key2table[obj_key] + return list(table.keys()) + + def transaction_begin(self, transaction): + return + + def set_researcher(self, owner): + pass + + def copy_from_db(self, db): + """ + A (possibily) implementation-specific method to get data from + db into this database. + """ + # First we add the primary objects: + for key in db._tables.keys(): + cursor = db._tables[key]["cursor_func"] + for (handle, data) in cursor(): + if key == "Person": + self.dji.add_person(data) + elif key == "Family": + self.dji.add_family(data) + elif key == "Event": + self.dji.add_event(data) + elif key == "Place": + self.dji.add_place(data) + elif key == "Repository": + self.dji.add_repository(data) + elif key == "Citation": + self.dji.add_citation(data) + elif key == "Source": + self.dji.add_source(data) + elif key == "Note": + self.dji.add_note(data) + elif key == "Media": + self.dji.add_media(data) + elif key == "Tag": + self.dji.add_tag(data) + for key in db._tables.keys(): + cursor = db._tables[key]["cursor_func"] + for (handle, data) in cursor(): + if key == "Person": + self.dji.add_person_detail(data) + elif key == "Family": + self.dji.add_family_detail(data) + elif key == "Event": + self.dji.add_event_detail(data) + elif key == "Place": + self.dji.add_place_detail(data) + elif key == "Repository": + self.dji.add_repository_detail(data) + elif key == "Citation": + self.dji.add_citation_detail(data) + elif key == "Source": + self.dji.add_source_detail(data) + elif key == "Note": + self.dji.add_note_detail(data) + elif key == "Media": + self.dji.add_media_detail(data) + elif key == "Tag": + self.dji.add_tag_detail(data) + # Next we add the links: + self.dji.update_publics() + + def get_from_name_and_handle(self, table_name, handle): + """ + Returns a gen.lib object (or None) given table_name and + handle. + + Examples: + + >>> self.get_from_name_and_handle("Person", "a7ad62365bc652387008") + >>> self.get_from_name_and_handle("Media", "c3434653675bcd736f23") + """ + if table_name in self._tables: + return self._tables[table_name]["handle_func"](handle) + return None + + def is_empty(self): + """ + Is the database empty? + """ + return (self.get_number_of_people() == 0 and + self.get_number_of_events() == 0 and + self.get_number_of_places() == 0 and + self.get_number_of_tags() == 0 and + self.get_number_of_families() == 0 and + self.get_number_of_notes() == 0 and + self.get_number_of_citations() == 0 and + self.get_number_of_sources() == 0 and + self.get_number_of_media_objects() == 0 and + self.get_number_of_repositories() == 0) + + __callback_map = {} + + def set_prefixes(self, person, media, family, source, citation, + place, event, repository, note): + self.set_person_id_prefix(person) + self.set_object_id_prefix(media) + self.set_family_id_prefix(family) + self.set_source_id_prefix(source) + self.set_citation_id_prefix(citation) + self.set_place_id_prefix(place) + self.set_event_id_prefix(event) + self.set_repository_id_prefix(repository) + self.set_note_id_prefix(note) + + def has_changed(self): + return False + + def find_backlink_handles(self, handle, include_classes=None): + ## FIXME: figure out how to get objects that refer + ## to this handle + return [] + + def get_note_bookmarks(self): + return self.note_bookmarks + + def get_media_bookmarks(self): + return self.media_bookmarks + + def get_repo_bookmarks(self): + return self.repo_bookmarks + + def get_citation_bookmarks(self): + return self.citation_bookmarks + + def get_source_bookmarks(self): + return self.source_bookmarks + + def get_place_bookmarks(self): + return self.place_bookmarks + + def get_event_bookmarks(self): + return self.event_bookmarks + + def get_bookmarks(self): + return self.bookmarks + + def get_family_bookmarks(self): + return self.family_bookmarks + + def get_save_path(self): + return "/tmp/" + + ## Get types: + def get_event_attribute_types(self): + """ + Return a list of all Attribute types assocated with Event instances + in the database. + """ + return list(self.event_attributes) + + def get_event_types(self): + """ + Return a list of all event types in the database. + """ + return list(self.event_names) + + def get_person_event_types(self): + """ + Deprecated: Use get_event_types + """ + return list(self.event_names) + + def get_person_attribute_types(self): + """ + Return a list of all Attribute types assocated with Person instances + in the database. + """ + return list(self.individual_attributes) + + def get_family_attribute_types(self): + """ + Return a list of all Attribute types assocated with Family instances + in the database. + """ + return list(self.family_attributes) + + def get_family_event_types(self): + """ + Deprecated: Use get_event_types + """ + return list(self.event_names) + + def get_media_attribute_types(self): + """ + Return a list of all Attribute types assocated with Media and MediaRef + instances in the database. + """ + return list(self.media_attributes) + + def get_family_relation_types(self): + """ + Return a list of all relationship types assocated with Family + instances in the database. + """ + return list(self.family_rel_types) + + def get_child_reference_types(self): + """ + Return a list of all child reference types assocated with Family + instances in the database. + """ + return list(self.child_ref_types) + + def get_event_roles(self): + """ + Return a list of all custom event role names assocated with Event + instances in the database. + """ + return list(self.event_role_names) + + def get_name_types(self): + """ + Return a list of all custom names types assocated with Person + instances in the database. + """ + return list(self.name_types) + + def get_origin_types(self): + """ + Return a list of all custom origin types assocated with Person/Surname + instances in the database. + """ + return list(self.origin_types) + + def get_repository_types(self): + """ + Return a list of all custom repository types assocated with Repository + instances in the database. + """ + return list(self.repository_types) + + def get_note_types(self): + """ + Return a list of all custom note types assocated with Note instances + in the database. + """ + return list(self.note_types) + + def get_source_attribute_types(self): + """ + Return a list of all Attribute types assocated with Source/Citation + instances in the database. + """ + return list(self.source_attributes) + + def get_source_media_types(self): + """ + Return a list of all custom source media types assocated with Source + instances in the database. + """ + return list(self.source_media_types) + + def get_url_types(self): + """ + Return a list of all custom names types assocated with Url instances + in the database. + """ + return list(self.url_types) + + def get_place_types(self): + """ + Return a list of all custom place types assocated with Place instances + in the database. + """ + return list(self.place_types) + + def get_default_handle(self): + people = self.dji.Person.all() + if people.count() > 0: + return people[0].handle + return None + + def close(self): + pass + + def get_surname_list(self): + return [] + + def is_open(self): + return True + + def get_table_names(self): + """Return a list of valid table names.""" + return list(self._tables.keys()) + + def find_initial_person(self): + return self.get_default_person() + + # Removals: + def remove_person(self, handle, txn): + self.dji.Person.filter(handle=handle)[0].delete() + self.emit("person-delete", ([handle],)) + + def remove_source(self, handle, transaction): + self.dji.Source.filter(handle=handle)[0].delete() + self.emit("source-delete", ([handle],)) + + def remove_citation(self, handle, transaction): + self.dji.Citation.filter(handle=handle)[0].delete() + self.emit("citation-delete", ([handle],)) + + def remove_event(self, handle, transaction): + self.dji.Event.filter(handle=handle)[0].delete() + self.emit("event-delete", ([handle],)) + + def remove_object(self, handle, transaction): + self.dji.Media.filter(handle=handle)[0].delete() + self.emit("media-delete", ([handle],)) + + def remove_place(self, handle, transaction): + self.dji.Place.filter(handle=handle)[0].delete() + self.emit("place-delete", ([handle],)) + + def remove_family(self, handle, transaction): + self.dji.Family.filter(handle=handle)[0].delete() + self.emit("family-delete", ([handle],)) + + def remove_repository(self, handle, transaction): + self.dji.Repository.filter(handle=handle)[0].delete() + self.emit("repository-delete", ([handle],)) + + def remove_note(self, handle, transaction): + self.dji.Note.filter(handle=handle)[0].delete() + self.emit("note-delete", ([handle],)) + + def remove_tag(self, handle, transaction): + self.dji.Tag.filter(handle=handle)[0].delete() + self.emit("tag-delete", ([handle],)) + + def remove_from_surname_list(self, person): + ## FIXME + pass + + def get_dbname(self): + return "Django Database" + + ## missing + + def find_place_child_handles(self, handle): + pass + + def get_cursor(self, table, txn=None, update=False, commit=False): + pass + + def get_from_name_and_handle(self, table_name, handle): + """ + Returns a gen.lib object (or None) given table_name and + handle. + + Examples: + + >>> self.get_from_name_and_handle("Person", "a7ad62365bc652387008") + >>> self.get_from_name_and_handle("Media", "c3434653675bcd736f23") + """ + if table_name in self._tables: + return self._tables[table_name]["handle_func"](handle) + return None + + def get_number_of_records(self, table): + pass + + def get_place_parent_cursor(self): + pass + + def get_place_tree_cursor(self): + pass + + def get_table_metadata(self, table_name): + """Return the metadata for a valid table name.""" + if table_name in self._tables: + return self._tables[table_name] + return None + + def get_transaction_class(self): + pass + + def undo(self, update_history=True): + # FIXME: + return self.undodb.undo(update_history) + + def redo(self, update_history=True): + # FIXME: + return self.undodb.redo(update_history) + + def backup(self): + pass + + def restore(self): + pass