diff --git a/D3Charts/DescendantIndentedTree.py b/D3Charts/DescendantIndentedTree.py index 8fab67fb5..ba8248125 100644 --- a/D3Charts/DescendantIndentedTree.py +++ b/D3Charts/DescendantIndentedTree.py @@ -62,6 +62,7 @@ # #------------------------------------------------------------------------ from gramps.gen.display.name import displayer as global_name_display +from gramps.gen.display.place import displayer as place_displayer from gramps.gen.errors import ReportError from gramps.gen.lib import ChildRefType from gramps.gen.plug.menu import (ColorOption, NumberOption, PersonOption, @@ -317,9 +318,8 @@ def get_date_place(self,event): date = get_date(event) place_handle = event.get_place_handle() if place_handle: - place = self.database.get_place_from_handle( - place_handle).get_title() - + place = place_displayer.display_event(self.database, event) + return("%(event_abbrev)s %(date)s %(place)s" % { 'event_abbrev': event.type.get_abbreviation(), 'date' : date, diff --git a/DescendantBooks/DescendantBookReport.py b/DescendantBooks/DescendantBookReport.py index 8994f91ab..3531a8bd2 100644 --- a/DescendantBooks/DescendantBookReport.py +++ b/DescendantBooks/DescendantBookReport.py @@ -40,6 +40,7 @@ from gramps.gen.plug.menu import (NumberOption, PersonOption, BooleanOption, EnumeratedListOption, FilterOption) from gramps.gen.display.name import displayer as global_name_display +from gramps.gen.display.place import displayer as place_displayer from gramps.gen.errors import ReportError from gramps.gen.plug.report import Report from gramps.gen.plug.report import utils as ReportUtils @@ -158,8 +159,7 @@ def __date_place(self,event): date = gramps.gen.datehandler.get_date(event) place_handle = event.get_place_handle() if place_handle: - place = self.database.get_place_from_handle( - place_handle).get_title() + place = place_displayer.display_event(self.database, event) return("%(event_abbrev)s %(date)s - %(place)s" % { 'event_abbrev': event.type.get_abbreviation(), 'date' : date, diff --git a/DescendantBooks/DetailedDescendantBookReport.py b/DescendantBooks/DetailedDescendantBookReport.py index c6660141b..bb3b1fd11 100644 --- a/DescendantBooks/DetailedDescendantBookReport.py +++ b/DescendantBooks/DetailedDescendantBookReport.py @@ -38,6 +38,7 @@ # #------------------------------------------------------------------------ from gramps.gen.display.name import displayer as global_name_display +from gramps.gen.display.place import displayer as place_displayer from gramps.gen.errors import ReportError from gramps.gen.lib import FamilyRelType, Person, NoteType from gramps.gen.plug.menu import (BooleanOption, NumberOption, PersonOption, @@ -779,12 +780,7 @@ def append_event(self, event_ref, family = False): event = self.database.get_event_from_handle(event_ref.ref) date = self._get_date(event.get_date_object()) - - ph = event.get_place_handle() - if ph: - place = self.database.get_place_from_handle(ph).get_title() - else: - place = '' + place = place_displayer.display_event(self.database, event) event_name = self._get_type(event.get_type()) @@ -823,12 +819,7 @@ def write_event(self, event_ref): else: date = event.get_date_object().get_year() - ph = event.get_place_handle() - if ph: - place = self.database.get_place_from_handle(ph).get_title() - else: - place = '' - + place = place_displayer.display_event(self.database, event) self.doc.start_paragraph('DDR-EventHeader') #BOOK event_name = self._get_type(event.get_type()) diff --git a/DescendantsLines/substkw.py b/DescendantsLines/substkw.py index aab4f2f4c..2993a986a 100644 --- a/DescendantsLines/substkw.py +++ b/DescendantsLines/substkw.py @@ -51,11 +51,6 @@ # Gramps modules # #------------------------------------------------------------------------ -from gramps.gen.display.place import displayer as _pd -from gramps.gen.lib import EventType, PlaceType, Location -from gramps.gen.utils.db import get_birth_or_fallback, get_death_or_fallback -from gramps.gen.utils.location import get_main_location -from gramps.gen.const import GRAMPS_LOCALE as glocale from gramps.plugins.lib.libsubstkeyword import * import logging @@ -624,67 +619,6 @@ def replace_and_clean(self, lines, event): return new -class PlaceFormat(GenericFormat): - """ The place format class. - If no format string, the place is displayed as per preference options - otherwise, parse through a format string and put the place parts in - """ - - def __init__(self, database, _in): - self.database = database - GenericFormat.__init__(self, _in) - self.date = None - - def get_place(self, database, event): - """ A helper method for retrieving a place from an event """ - if event: - bplace_handle = event.get_place_handle() - self.date = event.date - if bplace_handle: - return database.get_place_from_handle(bplace_handle) - return None - - def _default_format(self, place): - return _pd.display(self.database, place, date=self.date) - - def parse_format(self, database, place): - """ Parse the place """ - - if self.is_blank(place): - return - - code = "elcuspn" + "oitxy" - upper = code.upper() - - main_loc = get_main_location(database, place, date=self.date) - location = Location() - location.set_street(main_loc.get(PlaceType.STREET, '')) - location.set_locality(main_loc.get(PlaceType.LOCALITY, '')) - location.set_parish(main_loc.get(PlaceType.PARISH, '')) - location.set_city(main_loc.get(PlaceType.CITY, '')) - location.set_county(main_loc.get(PlaceType.COUNTY, '')) - location.set_state(main_loc.get(PlaceType.STATE, '')) - location.set_postal_code(main_loc.get(PlaceType.STREET, '')) - location.set_country(main_loc.get(PlaceType.COUNTRY, '')) - - function = [location.get_street, - location.get_locality, - location.get_city, - location.get_county, - location.get_state, - place.get_code, - location.get_country, - - location.get_phone, - location.get_parish, - place.get_title, - place.get_longitude, - place.get_latitude - ] - - return self.generic_format(place, code, upper, function) - - # # if __name__ == '__main__': #------------------------------------------------------------------------- diff --git a/DynamicWeb/dynamicweb.py b/DynamicWeb/dynamicweb.py index 9340e0c77..f6d4377f7 100644 --- a/DynamicWeb/dynamicweb.py +++ b/DynamicWeb/dynamicweb.py @@ -167,6 +167,8 @@ DWR_VERSION_412 = (VERSION_TUPLE[0] >= 5) or ((VERSION_TUPLE[0] >= 4) and (VERSION_TUPLE[1] >= 1) and (VERSION_TUPLE[2] >= 2)) DWR_VERSION_420 = (VERSION_TUPLE[0] >= 5) or ((VERSION_TUPLE[0] >= 4) and (VERSION_TUPLE[1] >= 2)) DWR_VERSION_500 = (VERSION_TUPLE[0] >= 5) +DWR_VERSION_520 = True # TODO adjust when we have the real 5.2.x out with enhanced places + from gramps.gen.lib import (ChildRefType, Date, EventType, FamilyRelType, Name, NameType, Person, UrlType, NoteType, EventRoleType, Family, Event, Place, Source, @@ -226,6 +228,8 @@ from gramps.gen.relationship import get_relationship_calculator if (DWR_VERSION_410): from gramps.gen.utils.location import get_main_location +if DWR_VERSION_520: + from gramps.gen.utils.location import get_code if (DWR_VERSION_500): @@ -1518,13 +1522,19 @@ def _export_places(self): if (not self.inc_places): jdatas.append(jdata) continue + #if DWR_VERSION_520: # TODO + # Enhanced places support multiple types with dates + # Enhanced places support multiple attributes + # Enhanced places support multiple events + # we may want to display some of these... if DWR_VERSION_410: jdata['type'] = str(place.get_type()) else: jdata['type'] = '' jdata['names'] = [] if DWR_VERSION_410: - for pn in place.get_all_names(): + for pn in (place.get_names() if DWR_VERSION_520 else + place.get_all_names()): lang = pn.get_language() if lang != '' and pref_lang!= '' and lang != pref_lang: continue date = format_date(pn.get_date_object()) @@ -1583,7 +1593,8 @@ def _export_places(self): else: coords = ("", "") jdata['coords'] = coords - jdata['code'] = place.get_code() + jdata['code'] = (get_code(place) if DWR_VERSION_520 else + place.get_code()) # Get place notes jdata['note'] = self.get_notes_text(place) # Get place media diff --git a/ExtractCity/extractcity.py b/ExtractCity/extractcity.py index d7e4a61ce..fce45b0b1 100644 --- a/ExtractCity/extractcity.py +++ b/ExtractCity/extractcity.py @@ -51,7 +51,7 @@ from gramps.plugins.lib.libplaceimport import PlaceImport from gramps.gen.utils.location import get_main_location from gramps.gen.display.place import displayer as place_displayer -from gramps.gen.lib import PlaceType, PlaceName +from gramps.gen.lib import PlaceType, PlaceName, Attribute, AttributeType from gramps.gui.plug import tool from gramps.gui.utils import ProgressMeter @@ -610,7 +610,7 @@ def on_help_clicked(self, obj): display_help() def on_ok_clicked(self, obj): - with DbTxn(_("Extract Place data"), self.db, batch=True) as self.trans: + with DbTxn(_("Extract Place data"), self.db, batch=False) as self.trans: self.db.disable_signals() changelist = [node for node in self.iter_list if self.model.get_value(node, 0)] @@ -624,7 +624,10 @@ def on_ok_clicked(self, obj): place.set_name(PlaceName(value=row[2])) place.set_type(PlaceType.CITY) if row[4]: - place.set_code(row[4]) + attr = Attribute() + attr.set_type(AttributeType.POSTAL) + attr.set_value(row[4]) + place.add_attribute(attr) self.db.commit_place(place, self.trans) self.place_import.generate_hierarchy(self.trans) diff --git a/GetGOV/getgov.py b/GetGOV/getgov.py index bf5fdb354..a5b2706b0 100644 --- a/GetGOV/getgov.py +++ b/GetGOV/getgov.py @@ -44,7 +44,8 @@ #------------------------------------------------------------------------ from gramps.gen.plug import Gramplet from gramps.gen.db import DbTxn -from gramps.gen.lib import Place, PlaceName, PlaceType, PlaceRef, Url, UrlType +from gramps.gen.lib import (Place, PlaceName, PlaceType, PlaceRef, + PlaceHierType, Url, UrlType) from gramps.gen.datehandler import parser from gramps.gen.config import config from gramps.gen.display.place import displayer as _pd @@ -68,210 +69,211 @@ #------------------------------------------------------------------------ ISO_CODE_LOOKUP = { -"aar": "aa", -"abk": "ab", -"afr": "af", -"aka": "ak", -"alb": "sq", -"amh": "am", -"ara": "ar", -"arg": "an", -"arm": "hy", -"asm": "as", -"ava": "av", -"ave": "ae", -"aym": "ay", -"aze": "az", -"bak": "ba", -"bam": "bm", -"baq": "eu", -"bel": "be", -"ben": "bn", -"bih": "bh", -"bis": "bi", -"bod": "bo", -"bos": "bs", -"bre": "br", -"bul": "bg", -"bur": "my", -"cat": "ca", -"ces": "cs", -"cha": "ch", -"che": "ce", -"chi": "zh", -"chu": "cu", -"chv": "cv", -"cor": "kw", -"cos": "co", -"cre": "cr", -"cym": "cy", -"cze": "cs", -"dan": "da", -"deu": "de", -"div": "dv", -"dut": "nl", -"dzo": "dz", -"ell": "el", -"eng": "en", -"epo": "eo", -"est": "et", -"eus": "eu", -"ewe": "ee", -"fao": "fo", -"fas": "fa", -"fij": "fj", -"fin": "fi", -"fra": "fr", -"fre": "fr", -"fry": "fy", -"ful": "ff", -"geo": "ka", -"ger": "de", -"gla": "gd", -"gle": "ga", -"glg": "gl", -"glv": "gv", -"gre": "el", -"grn": "gn", -"guj": "gu", -"hat": "ht", -"hau": "ha", -"heb": "he", -"her": "hz", -"hin": "hi", -"hmo": "ho", -"hrv": "hr", -"hun": "hu", -"hye": "hy", -"ibo": "ig", -"ice": "is", -"ido": "io", -"iii": "ii", -"iku": "iu", -"ile": "ie", -"ina": "ia", -"ind": "id", -"ipk": "ik", -"isl": "is", -"ita": "it", -"jav": "jv", -"jpn": "ja", -"kal": "kl", -"kan": "kn", -"kas": "ks", -"kat": "ka", -"kau": "kr", -"kaz": "kk", -"khm": "km", -"kik": "ki", -"kin": "rw", -"kir": "ky", -"kom": "kv", -"kon": "kg", -"kor": "ko", -"kua": "kj", -"kur": "ku", -"lao": "lo", -"lat": "la", -"lav": "lv", -"lim": "li", -"lin": "ln", -"lit": "lt", -"ltz": "lb", -"lub": "lu", -"lug": "lg", -"mac": "mk", -"mah": "mh", -"mal": "ml", -"mao": "mi", -"mar": "mr", -"may": "ms", -"mkd": "mk", -"mlg": "mg", -"mlt": "mt", -"mon": "mn", -"mri": "mi", -"msa": "ms", -"mya": "my", -"nau": "na", -"nav": "nv", -"nbl": "nr", -"nde": "nd", -"ndo": "ng", -"nep": "ne", -"nld": "nl", -"nno": "nn", -"nob": "nb", -"nor": "no", -"nya": "ny", -"oci": "oc", -"oji": "oj", -"ori": "or", -"orm": "om", -"oss": "os", -"pan": "pa", -"per": "fa", -"pli": "pi", -"pol": "pl", -"por": "pt", -"pus": "ps", -"que": "qu", -"roh": "rm", -"ron": "ro", -"rum": "ro", -"run": "rn", -"rus": "ru", -"sag": "sg", -"san": "sa", -"sin": "si", -"slk": "sk", -"slo": "sk", -"slv": "sl", -"sme": "se", -"smo": "sm", -"sna": "sn", -"snd": "sd", -"som": "so", -"sot": "st", -"spa": "es", -"sqi": "sq", -"srd": "sc", -"srp": "sr", -"ssw": "ss", -"sun": "su", -"swa": "sw", -"swe": "sv", -"tah": "ty", -"tam": "ta", -"tat": "tt", -"tel": "te", -"tgk": "tg", -"tgl": "tl", -"tha": "th", -"tib": "bo", -"tir": "ti", -"ton": "to", -"tsn": "tn", -"tso": "ts", -"tuk": "tk", -"tur": "tr", -"twi": "tw", -"uig": "ug", -"ukr": "uk", -"urd": "ur", -"uzb": "uz", -"ven": "ve", -"vie": "vi", -"vol": "vo", -"wel": "cy", -"wln": "wa", -"wol": "wo", -"xho": "xh", -"yid": "yi", -"yor": "yo", -"zha": "za", -"zho": "zh", -"zul": "zu"} + "aar": "aa", + "abk": "ab", + "afr": "af", + "aka": "ak", + "alb": "sq", + "amh": "am", + "ara": "ar", + "arg": "an", + "arm": "hy", + "asm": "as", + "ava": "av", + "ave": "ae", + "aym": "ay", + "aze": "az", + "bak": "ba", + "bam": "bm", + "baq": "eu", + "bel": "be", + "ben": "bn", + "bih": "bh", + "bis": "bi", + "bod": "bo", + "bos": "bs", + "bre": "br", + "bul": "bg", + "bur": "my", + "cat": "ca", + "ces": "cs", + "cha": "ch", + "che": "ce", + "chi": "zh", + "chu": "cu", + "chv": "cv", + "cor": "kw", + "cos": "co", + "cre": "cr", + "cym": "cy", + "cze": "cs", + "dan": "da", + "deu": "de", + "div": "dv", + "dut": "nl", + "dzo": "dz", + "ell": "el", + "eng": "en", + "epo": "eo", + "est": "et", + "eus": "eu", + "ewe": "ee", + "fao": "fo", + "fas": "fa", + "fij": "fj", + "fin": "fi", + "fra": "fr", + "fre": "fr", + "fry": "fy", + "ful": "ff", + "geo": "ka", + "ger": "de", + "gla": "gd", + "gle": "ga", + "glg": "gl", + "glv": "gv", + "gre": "el", + "grn": "gn", + "guj": "gu", + "hat": "ht", + "hau": "ha", + "heb": "he", + "her": "hz", + "hin": "hi", + "hmo": "ho", + "hrv": "hr", + "hun": "hu", + "hye": "hy", + "ibo": "ig", + "ice": "is", + "ido": "io", + "iii": "ii", + "iku": "iu", + "ile": "ie", + "ina": "ia", + "ind": "id", + "ipk": "ik", + "isl": "is", + "ita": "it", + "jav": "jv", + "jpn": "ja", + "kal": "kl", + "kan": "kn", + "kas": "ks", + "kat": "ka", + "kau": "kr", + "kaz": "kk", + "khm": "km", + "kik": "ki", + "kin": "rw", + "kir": "ky", + "kom": "kv", + "kon": "kg", + "kor": "ko", + "kua": "kj", + "kur": "ku", + "lao": "lo", + "lat": "la", + "lav": "lv", + "lim": "li", + "lin": "ln", + "lit": "lt", + "ltz": "lb", + "lub": "lu", + "lug": "lg", + "mac": "mk", + "mah": "mh", + "mal": "ml", + "mao": "mi", + "mar": "mr", + "may": "ms", + "mkd": "mk", + "mlg": "mg", + "mlt": "mt", + "mon": "mn", + "mri": "mi", + "msa": "ms", + "mya": "my", + "nau": "na", + "nav": "nv", + "nbl": "nr", + "nde": "nd", + "ndo": "ng", + "nep": "ne", + "nld": "nl", + "nno": "nn", + "nob": "nb", + "nor": "no", + "nya": "ny", + "oci": "oc", + "oji": "oj", + "ori": "or", + "orm": "om", + "oss": "os", + "pan": "pa", + "per": "fa", + "pli": "pi", + "pol": "pl", + "por": "pt", + "pus": "ps", + "que": "qu", + "roh": "rm", + "ron": "ro", + "rum": "ro", + "run": "rn", + "rus": "ru", + "sag": "sg", + "san": "sa", + "sin": "si", + "slk": "sk", + "slo": "sk", + "slv": "sl", + "sme": "se", + "smo": "sm", + "sna": "sn", + "snd": "sd", + "som": "so", + "sot": "st", + "spa": "es", + "sqi": "sq", + "srd": "sc", + "srp": "sr", + "ssw": "ss", + "sun": "su", + "swa": "sw", + "swe": "sv", + "tah": "ty", + "tam": "ta", + "tat": "tt", + "tel": "te", + "tgk": "tg", + "tgl": "tl", + "tha": "th", + "tib": "bo", + "tir": "ti", + "ton": "to", + "tsn": "tn", + "tso": "ts", + "tuk": "tk", + "tur": "tr", + "twi": "tw", + "uig": "ug", + "ukr": "uk", + "urd": "ur", + "uzb": "uz", + "ven": "ve", + "vie": "vi", + "vol": "vo", + "wel": "cy", + "wln": "wa", + "wol": "wo", + "xho": "xh", + "yid": "yi", + "yor": "yo", + "zha": "za", + "zho": "zh", + "zul": "zu"} + #------------------------------------------------------------------------ # @@ -292,7 +294,6 @@ def init(self): root.show_all() self.type_dic = dict() - def __create_gui(self): """ Create and display the GUI components of the gramplet. @@ -324,7 +325,7 @@ def main(self): """ pass - def __get_places(self, obj): + def __get_places(self, _obj): gov_id = self.entry.get_text() to_do = [gov_id] try: @@ -334,13 +335,14 @@ def __get_places(self, obj): pf = _pd.get_formats()[fmt] preferred_lang = pf.language if len(preferred_lang) != 2: - preferred_lang = 'de' + preferred_lang = glocale.lang visited = {} if not self.type_dic: self.__get_types() - with DbTxn(_('Add GOV-id place %s') % gov_id, self.dbstate.db) as trans: + with DbTxn(_('Add GOV-id place %s') % gov_id, + self.dbstate.db) as trans: while to_do: gov_id = to_do.pop() place = self.dbstate.db.get_place_from_gramps_id(gov_id) @@ -363,10 +365,37 @@ def __get_places(self, obj): place_ref = PlaceRef() place_ref.ref = handle place_ref.set_date_object(date) + place_ref.set_type(PlaceHierType.ADMIN) # TODO deal with other hierarchies place.add_placeref(place_ref) self.dbstate.db.commit_place(place, trans) + self.dbstate.db.save_place_types() def __get_types(self): + groups = { + 1: _("Administrative"), + 2: _("Civil"), + 3: _("Religious"), + 4: _("Geographical"), + 5: _("Cultural"), + 6: _("Judicial"), + 8: _("Places"), + 9: _("Transportation"), + 10: _("Unpopulated Places"), + 13: _("Other"), + 26: _("Countries"), + 27: _("Regions"), + 28: _("Regions"), + 29: _("Regions"), + 30: _("Regions"), + 31: _("Places"), + 32: _("Places"), + } + self.groups_cnv = {} + for grp_num, grp_name in groups.items(): + for grp, tup in PlaceType.GROUPMAP.items(): + if grp_name.lower() == tup[0].lower(): + self.groups_cnv[grp_num] = grp + self.type_groups = {} type_url = 'http://gov.genealogy.net/types.owl/' response = urlopen(type_url) data = response.read() @@ -374,22 +403,30 @@ def __get_types(self): for group in dom.getElementsByTagName('owl:Class') : url_value = group.attributes['rdf:about'].value group_number = url_value.split('#')[1] + g_num = self.groups_cnv.get( + int(group_number.replace('group_', '')), 0) for element in dom.getElementsByTagNameNS("http://gov.genealogy." "net/types.owl#", group_number): - type_number = element.attributes['rdf:about'].value.split('#')[1] - for pname in element.getElementsByTagName('rdfs:label'): - type_lang = pname.attributes['xml:lang'].value - type_text = pname.childNodes[0].data - self.type_dic[type_number,type_lang] = type_text + self.__do_type(dom, element, g_num) for element in dom.getElementsByTagNameNS("http://gov.genealogy." "net/ontology.owl#", 'Type'): - type_number = element.attributes['rdf:about'].value.split('#')[1] - for pname in element.getElementsByTagName('rdfs:label'): - type_lang = pname.attributes['xml:lang'].value - type_text = pname.childNodes[0].data - self.type_dic[type_number,type_lang] = type_text + self.__do_type(dom, element, g_num) + + def __do_type(self, dom, element, g_num): + type_number = element.attributes['rdf:about'].value.split('#')[1] + for pname in element.getElementsByTagName('rdfs:label'): + type_lang = pname.attributes['xml:lang'].value + type_text = pname.childNodes[0].data + self.type_dic[type_number, type_lang] = type_text + groups = g_num + for res in element.getElementsByTagName('rdf:type'): + gx_num = res.attributes['rdf:resource'].value.split('#')[1] + if gx_num == 'Type' or 'group_' not in gx_num: + continue + groups += self.groups_cnv.get(int(gx_num.replace('group_', '')), 0) + self.type_groups[int(type_number)] = groups def __get_place(self, gov_id, type_dic, preferred_lang): gov_url = 'http://gov.genealogy.net/semanticWeb/about/' + quote(gov_id) @@ -405,22 +442,16 @@ def __get_place(self, gov_id, type_dic, preferred_lang): if not len(top) : return place, [] - count = 0 + types = [] for element in top[0].getElementsByTagName('gov:hasName'): - count += 1 place_name = self.__get_hasname(element) - if count == 1: - place.set_name(place_name) - else: - if place_name.lang == preferred_lang: - place.add_alternative_name(place.get_name()) - place.set_name(place_name) - else: - place.add_alternative_name(place_name) + place.add_name(place_name) for element in top[0].getElementsByTagName('gov:hasType'): - curr_lang = place.get_name().get_language() - place_type = self.__get_hastype(element,curr_lang, type_dic, preferred_lang) - place.set_type(place_type) + place_type = self.__get_hastype(element, type_dic, + preferred_lang) + types.append(place_type) + types.sort(key=lambda typ: typ.date.get_sort_value(), reverse=True) + place.set_types(types) for element in top[0].getElementsByTagName('gov:position'): latitude, longitude = self.__get_position(element) place.set_latitude(latitude) @@ -441,15 +472,16 @@ def __get_hasname(self, element): if len(pname): value = pname[0].getElementsByTagName('gov:value') if len(value): - name.set_value(value[0].childNodes[0].data) + name.set_value(value[0].childNodes[0].data) language = pname[0].getElementsByTagName('gov:language') if len(language): - name.set_language(ISO_CODE_LOOKUP.get(language[0].childNodes[0].data)) + name.set_language( + ISO_CODE_LOOKUP.get(language[0].childNodes[0].data)) date = self.__get_date_range(pname[0]) name.set_date_object(date) return name - def __get_hastype(self, element, curr_lang, type_dic, preferred_lang): + def __get_hastype(self, element, type_dic, preferred_lang): place_type = PlaceType() ptype = element.getElementsByTagName('gov:PropertyType') if len(ptype): @@ -457,14 +489,16 @@ def __get_hastype(self, element, curr_lang, type_dic, preferred_lang): if len(value): type_url = value[0].attributes['rdf:resource'].value type_code = type_url.split('#')[1] - if tuple([type_code, curr_lang]) in type_dic: - place_type.set_from_xml_str(type_dic.get(tuple([type_code,curr_lang]),'No Type')) - elif tuple([type_code, preferred_lang]) in type_dic: - place_type.set_from_xml_str(type_dic.get(tuple([type_code,preferred_lang]),'No Type')) - elif tuple([type_code, 'de']) in type_dic: - place_type.set_from_xml_str(type_dic.get(tuple([type_code,'de']),'No Type')) - elif tuple([type_code, 'en']) in type_dic: - place_type.set_from_xml_str(type_dic.get(tuple([type_code,'en']),'No Type')) + for lang in (preferred_lang, 'de', 'en'): + t_nam = type_dic.get((type_code, lang), None) + if not t_nam: + continue + place_type.set((-int(type_code), t_nam, + self.type_groups[int(type_code)])) + break + date = self.__get_date_range(ptype[0]) + if date: + place_type.set_date_object(date) return place_type def __get_position(self, element): @@ -500,8 +534,8 @@ def __get_hasurl(self, element): if len(pobj): value = pobj[0].getElementsByTagName('gov:value') if len(value): - url.set_path(value[0].childNodes[0].data) - url.set_type(UrlType.WEB_HOME) + url.set_path(value[0].childNodes[0].data) + url.set_type(UrlType.WEB_HOME) return url def __get_date_range(self, element): diff --git a/PersonEverything/PersonEverything.py b/PersonEverything/PersonEverything.py index 5852793cf..3a40a5845 100644 --- a/PersonEverything/PersonEverything.py +++ b/PersonEverything/PersonEverything.py @@ -593,13 +593,9 @@ def print_object(self, level, o): self.doc.write_text(" " + _("Type") + " : ") self.doc.end_bold() self.doc.write_text(str(place.get_type())) - self.doc.start_bold() - self.doc.write_text(" " + _("Code") + " : ") - self.doc.end_bold() - self.doc.write_text(place.get_code()) self.doc.end_paragraph() - for name in place.get_alternative_names(): + for name in place.get_names()[1:]: self.doc.start_paragraph("PE-Level%d" % min(level+1, 32)) self.doc.start_bold() self.doc.write_text(_("Alternative Name") + " : ") diff --git a/PlaceCleanup/placecleanup.py b/PlaceCleanup/placecleanup.py index f76d823b2..92704ff34 100644 --- a/PlaceCleanup/placecleanup.py +++ b/PlaceCleanup/placecleanup.py @@ -30,7 +30,6 @@ from urllib.request import urlopen, URLError, quote from xml.dom.minidom import parseString import os -import sys import ctypes import locale import socket @@ -51,13 +50,15 @@ from gramps.gui.dialog import ErrorDialog, WarningDialog from gramps.gen.plug import Gramplet from gramps.gen.db import DbTxn -from gramps.gen.lib import Citation +from gramps.gen.lib import Attribute, AttributeType, Citation from gramps.gen.lib import Place, PlaceName, PlaceType, PlaceRef, Url, UrlType +from gramps.gen.lib import PlaceAbbrev, PlaceAbbrevType from gramps.gen.lib import Note, NoteType, Repository, RepositoryType, RepoRef from gramps.gen.lib import StyledText, StyledTextTag, StyledTextTagType from gramps.gen.lib import Source, SourceMediaType from gramps.gen.datehandler import get_date from gramps.gen.config import config +from gramps.gen.lib.const import IDENTICAL, EQUAL from gramps.gen.constfunc import win from gramps.gui.display import display_url from gramps.gui.autocomp import StandardCustomSelector @@ -205,7 +206,7 @@ def __create_gui(self): # ====================================================== # gramplet event handlers # ====================================================== - def on_help_clicked(self, dummy): + def on_help_clicked(self, _dummy): ''' Button: Display the relevant portion of GRAMPS manual''' display_url(WIKI_PAGE) @@ -214,7 +215,7 @@ def on_res_sel_changed(self, res_sel): self.top.get_object("select_but").set_sensitive( res_sel.get_selected()) - def on_title_entry_changed(self, dummy): + def on_title_entry_changed(self, _dummy): ''' Occurs during edits of the Title box on the main screen. we use this to reset the GeoNames search row, as the user may be trying another search term.''' @@ -269,7 +270,7 @@ def reset_main(self): self.geo_stage = False self.top.get_object("select_but").set_sensitive(False) - def on_find_clicked(self, dummy): + def on_find_clicked(self, _dummy): """ find a matching place. First try in the db, then try in the GeoNames. """ self.res_store.clear() @@ -288,7 +289,7 @@ def on_find_clicked(self, dummy): self.dbstate.db, place.handle, self.place.handle): title = _pd.display(self.dbstate.db, place) self.res_store.append(row=(index, title, - str(place.place_type))) + str(place.get_type()))) if len(self.res_store) > 0: self.res_lbl.set_text(_('%s\nLocal\nMatches') % len(self.res_store)) @@ -406,7 +407,7 @@ def search_geo(self): def get_geo_data(self, geo_url): """ Get GeoNames data from web with error checking """ - print(geo_url) + # print(geo_url) try: with urlopen(geo_url, timeout=20) as response: data = response.read() @@ -416,7 +417,7 @@ def get_geo_data(self, geo_url): except: txt = '' ErrorDialog(_('Problem getting data from web'), - msg2=str(err) +'\n' + txt, + msg2=str(err) + '\n' + txt, parent=self.uistate.window) return None except socket.timeout: @@ -435,7 +436,7 @@ def get_geo_data(self, geo_url): return None return dom - def on_next_clicked(self, dummy): + def on_next_clicked(self, _dummy): """ find a incomplete place in the db, if possible """ self.reset_main() place = self.find_an_incomplete_place() @@ -481,7 +482,8 @@ def on_select_clicked(self, *dummy): parent=self.uistate.window) return # lets clean up the place name - self.place.name.value = self.place.name.value.split(',')[0].strip() + name = self.place.get_name() + name.value = name.value.split(',')[0].strip() place_merge = MergePlaceQuery(self.dbstate, place, self.place) place_merge.execute() # after merge we should select merged result @@ -526,23 +528,28 @@ def geoparse(self, geoid, title, h_geoid_list, h_name_list, *dummy): self.newplace.long = str(value[0].childNodes[0].data) value = g_name.getElementsByTagName('toponymName') topname = value[0].childNodes[0].data - new_place = PlaceName() - new_place.set_value(topname) - new_place.set_language("") + pl_name = PlaceName() + pl_name.set_value(topname) + pl_name.set_language("") # make sure we have the topname in the names list and default to # primary - self.newplace.add_name(new_place) - self.newplace.name = new_place + self.newplace.add_name(pl_name) + self.newplace.name = pl_name # lets parse the alternative names alt_names = g_name.getElementsByTagName('alternateName') for a_name in alt_names: pattr = a_name.getAttribute("lang") value = a_name.childNodes[0].data if pattr == "post": - if self.newplace.code: - self.newplace.code += " " + value - else: - self.newplace.code = value + attr = Attribute() + attr.set_type(AttributeType.POSTAL) + attr.set_value(value) + self.newplace.postals.append(attr) + elif pattr == "abbr": + # deal with abbreviation + abbr = PlaceAbbrev(value=value) + abbr.set_type(PlaceAbbrevType.ABBR) + self.newplace.abbrs.append(abbr) elif pattr == "link": url = Url() url.set_path(value) @@ -550,15 +557,15 @@ def geoparse(self, geoid, title, h_geoid_list, h_name_list, *dummy): url.set_type(UrlType(UrlType.WEB_HOME)) self.newplace.links.append(url) elif pattr not in ['iata', 'iaco', 'faac', 'wkdt', 'unlc']: - new_place = PlaceName() - new_place.set_language(pattr) - new_place.set_value(value) - self.newplace.add_name(new_place) + pl_name = PlaceName() + pl_name.set_language(pattr) + pl_name.set_value(value) + self.newplace.add_name(pl_name) if a_name.hasAttribute('isPreferredName') and ( pattr and pattr == self.lang): # if not preferred lang, we use topo name, otherwise # preferred name for lang - self.newplace.name = new_place + self.newplace.name = pl_name # Try to deduce PlaceType: # If populated place, set as City. Long description could over-ride # Parse long description, looking for keyword (Region, County, ...) @@ -571,24 +578,25 @@ def geoparse(self, geoid, title, h_geoid_list, h_name_list, *dummy): value = g_name.getElementsByTagName('fcode') fcode = value[0].childNodes[0].data value = g_name.getElementsByTagName('countryCode') - countrycode = value[0].childNodes[0].data + if value[0].childNodes: + countrycode = value[0].childNodes[0].data + else: + countrycode = '' self.newplace.place_type = PlaceType(PlaceType.UNKNOWN) ptype = PlaceType() + # make a dict of translated names to types + tmap = {val[0]: key for key, val in ptype.DATAMAP.items()} # scan thorough names looking for name portion that matches a Placetype for name in self.newplace.names: for tname in name.value.split(' '): - ptype.set_from_xml_str(tname.capitalize()) - if ptype != PlaceType.CUSTOM: + tname = tname.capitalize() + if tname in ptype._E2IMAP: # is it English (XML) name? + ptype.set_from_xml_str(tname) self.newplace.place_type = ptype break # see if it is a translated PlaceType - ptype.set(tname.capitalize()) - if ptype != PlaceType.CUSTOM: - self.newplace.place_type = ptype - break - # see if it is an already added custom type - cust_types = self.dbstate.db.get_place_types() - if tname.capitalize() in cust_types: + if tname in tmap: + ptype.set(tname) self.newplace.place_type = ptype break else: @@ -602,12 +610,23 @@ def geoparse(self, geoid, title, h_geoid_list, h_name_list, *dummy): self.newplace.place_type = PlaceType(PlaceType.PARISH) elif 'PCL' in fcode: self.newplace.place_type = PlaceType(PlaceType.COUNTRY) + abbrev = PlaceAbbrev(value=countrycode) + abbrev.set_type(PlaceAbbrevType.ISO3166) + self.newplace.name.add_abbrev(abbrev) elif 'ADM' in fcode: if countrycode in self.adm_table: _ptype = self.adm_table[countrycode].get(fcode[:4]) if _ptype and (_ptype[1] or - self.newplace.place_type.is_default()): + int(self.newplace.place_type) == + PlaceType.UNKNOWN): self.newplace.place_type = PlaceType(_ptype[0]) + # store abbreviations on the preferred place name + self.newplace.name.get_abbrevs().extend(self.newplace.abbrs) + if self.newplace.name.get_abbrevs(): + for name in self.newplace.names: + lang = name.get_language() + if not lang or self.lang == lang: + name.set_abbrevs(self.newplace.name.get_abbrevs()) # save a parent for enclosing if len(h_geoid_list) > 1: # we have a parent @@ -621,7 +640,7 @@ def on_edit_clicked(self, dummy): # if ',' in self.place.name.value: # name = self.place.name.value # else: - name = self.place.name.value + name = self.place.get_names()[0].value self.newplace = NewPlace(name) names = name.split(',') names = [name.strip() for name in names] @@ -630,32 +649,29 @@ def on_edit_clicked(self, dummy): self.newplace.gramps_id = self.place.gramps_id self.newplace.lat = self.place.lat self.newplace.long = self.place.long - self.newplace.code = self.place.code - if self.place.place_type == PlaceType.UNKNOWN: + self.newplace.code = self.place.code # TODO + if int(self.place.get_type()) == PlaceType.UNKNOWN: self.newplace.place_type = PlaceType(PlaceType.UNKNOWN) if any(i.isdigit() for i in self.newplace.name.value): self.newplace.place_type = PlaceType(PlaceType.STREET) ptype = PlaceType() + # make a dict of translated names to types + tmap = {val[0]: key for key, val in ptype.DATAMAP.items()} for tname in self.newplace.name.value.split(' '): - # see if it is an English PlaceType - ptype.set_from_xml_str(tname.capitalize()) - if ptype != PlaceType.CUSTOM: + tname = tname.capitalize() + if tname in ptype._E2IMAP: # is it English (XML) name? + ptype.set_from_xml_str(tname) self.newplace.place_type = ptype break # see if it is a translated PlaceType - ptype.set(tname.capitalize()) - if ptype != PlaceType.CUSTOM: + if tname in tmap: + ptype.set(tname) self.newplace.place_type = ptype break - # see if it is an already added custom type - cust_types = self.dbstate.db.get_place_types() - if tname.capitalize() in cust_types: - self.newplace.place_type = ptype else: - self.newplace.place_type = self.place.place_type + self.newplace.place_type = self.place.get_type() self.newplace.add_name(self.newplace.name) - self.newplace.add_name(self.place.name) - self.newplace.add_names(self.place.alt_names) + self.newplace.add_names(self.place.get_names()) if self.place.placeref_list: # If we already have an enclosing place, use it. parent = self.dbstate.db.get_place_from_handle( @@ -676,9 +692,7 @@ def res_gui(self): # Setup sort on 'Inc" column so Primary is a top with checks next self.alt_store.set_sort_func(0, inc_sort, None) self.alt_store.set_sort_column_id(0, 0) - # Merge old name and alt names into new set - self.newplace.add_name(self.place.name) - self.newplace.add_names(self.place.alt_names) + self.newplace.add_names(self.place.get_names()) # Fill in ohter fields self.top.get_object('res_title').set_text(self.newplace.title) self.top.get_object('primary').set_text(self.newplace.name.value) @@ -690,7 +704,7 @@ def res_gui(self): for index, name in enumerate(self.newplace.names): if self.newplace.name == name: inc = 'P' - elif name.lang in self.allowed_languages or ( + elif name.lang in self.allowed_languages or ( # TODO name.lang == 'abbr' or name.lang == 'en' or not name.lang): inc = '\u2714' # Check mark else: @@ -707,16 +721,28 @@ def on_res_ok_clicked(self, dummy): namelist = [] for row in self.alt_store: if row[0] == 'P': - self.place.name = self.newplace.names[row[4]] + namelist.insert(0, self.newplace.names[row[4]]) elif row[0] == '\u2714': namelist.append(self.newplace.names[row[4]]) - self.place.alt_names = namelist + self.place.set_names(namelist) # Lat/lon/ID/code/type self.place.lat = self.top.get_object('latitude').get_text() self.place.long = self.top.get_object('longitude').get_text() self.place.gramps_id = self.top.get_object('grampsid').get_text() - self.place.code = self.top.get_object('postal').get_text() - self.place.place_type.set(self.type_combo.get_values()) + attrs = self.place.get_attribute_list()[:] + for addendum in self.newplace.postals: + for attr in attrs: + equi = attr.is_equivalent(addendum) + if equi == IDENTICAL: + break + elif equi == EQUAL: + attr.merge(addendum) + break + else: + self.place.add_attribute(addendum) + p_type = PlaceType() + p_type.set(self.type_combo.get_values()) + self.place.set_type(p_type) # Add in URLs if wanted if self.keepweb: for url in self.newplace.links: @@ -735,8 +761,9 @@ def on_res_ok_clicked(self, dummy): parent.title = ', '.join(self.newplace.parent_names) name = PlaceName() name.value = parent.title - parent.name = name + parent.add_name(name) parent.gramps_id = self.newplace.parent_ids[0] + parent.set_type(PlaceType()) with DbTxn(_("Add Place (%s)") % parent.title, self.dbstate.db) as trans: self.dbstate.db.add_place(parent, trans) @@ -761,6 +788,7 @@ def on_res_ok_clicked(self, dummy): if not already_there: placeref = PlaceRef() placeref.set_reference_handle(parent.handle) + placeref.set_type_for_place(self.place) self.place.set_placeref_list([placeref]) # Add in Citation/Source if wanted if self.addcitation and self.newplace.geoid: @@ -869,39 +897,43 @@ def on_postalcheck(self, *dummy): # inititlization obj.set_sensitive(True) obj.set_active(False) - place = self.newplace - if self.place.code: + attrs = self.newplace.postals + if self.get_postals(self.place.get_attribute_list()): if obj.get_active(): - place = self.place + attrs = self.place.get_attribute_list() obj.set_sensitive(True) else: obj.set_sensitive(False) - self.top.get_object('postal').set_text(place.code) + self.top.get_object('postal').set_text(self.get_postals(attrs)) + + def get_postals(self, attrs): + """ Create a postal codes string from attributes of place """ + postals = '' + for attr in attrs: + if attr.type == AttributeType.POSTAL: + postals += (', ' if postals else '') + attr.value + return postals def on_typecheck(self, *dummy): """ Check toggled; if active, load type from original place, else use type from gazetteer """ obj = self.top.get_object("typecheck") combo = self.top.get_object('place_type') - additional = sorted(self.dbstate.db.get_place_types(), - key=lambda s: s.lower()) self.type_combo = StandardCustomSelector(PlaceType().get_map(), combo, PlaceType.CUSTOM, - PlaceType.UNKNOWN, - additional) + PlaceType.UNKNOWN) if not dummy: # inititlization obj.set_sensitive(True) obj.set_active(False) - place = self.newplace - if(self.place.place_type and - self.place.place_type != PlaceType.UNKNOWN): + p_type = self.newplace.place_type + if(int(self.place.get_type()) != PlaceType.UNKNOWN): if obj.get_active(): - place = self.place + p_type = self.place.get_type() else: obj.set_sensitive(False) - self.type_combo.set_values((int(place.place_type), - str(place.place_type))) + self.type_combo.set_values((int(p_type), + str(p_type))) def on_idcheck(self, *dummy): """ Check toggled; if active, load gramps_id from original place, else @@ -1012,7 +1044,9 @@ def lookup_places_by_name(self, search_name): """ In local db. Only completed places are matched. We may want to try some better matching algorithms, possibly something from difflib""" - search_name = search_name.lower().split(',') + search_name = search_name.lower() + if ',' in search_name: + search_name = search_name.split(',')[0] places = [] for place in self.dbstate.db.iter_places(): if (place.get_type() != PlaceType.UNKNOWN and @@ -1020,8 +1054,8 @@ def lookup_places_by_name(self, search_name): (place.get_type() != PlaceType.COUNTRY and place.get_placeref_list()))): # valid place, get all its names - for name in place.get_all_names(): - if name.get_value().lower() == search_name[0]: + for name in place.get_names(): + if name.get_value().lower() == search_name: places.append(place) break return places @@ -1050,7 +1084,11 @@ def find_an_incomplete_place(self): while True: hndl = p_hndls[indx] place_data = self.dbstate.db.get_raw_place_data(hndl) - p_type = place_data[8][0] # place_type + p_type = place_data[7] # place_types + if p_type: + p_type = p_type[0] + else: + p_type = PlaceType.UNKNOWN refs = list(self.dbstate.db.find_backlink_handles(hndl)) if(p_type == PlaceType.UNKNOWN or not refs or @@ -1082,14 +1120,15 @@ def __init__(self, title): self.gramps_id = '' self.lat = '' self.long = '' - self.code = '' + self.postals = [] self.place_type = None self.names = [] # all names, including alternate, acts like a set self.name = PlaceName() + self.abbrs = [] self.links = [] self.geoid = '' - self.parent_ids = [] # list of gramps_ids in hierarchical order - self.parent_names = [] # list of names in hierarchical order + self.parent_ids = [] # list of gramps_ids in hierarchical order + self.parent_names = [] # list of names in hierarchical order def add_name(self, name): """ Add a name to names list without repeats """ diff --git a/PlaceCompletion/PlaceCompletion.gpr.py b/PlaceCompletion/PlaceCompletion.gpr.py index 86f86610d..9c987a93c 100644 --- a/PlaceCompletion/PlaceCompletion.gpr.py +++ b/PlaceCompletion/PlaceCompletion.gpr.py @@ -27,6 +27,7 @@ version = '0.0.35', gramps_target_version = "5.1", status = STABLE, +include_in_listing = False, fname = 'PlaceCompletion.py', authors = ["B. Malengier", "Mathieu MD"], diff --git a/Sqlite/Sqlite.gpr.py b/Sqlite/Sqlite.gpr.py index c0ec5baa1..e707bff92 100644 --- a/Sqlite/Sqlite.gpr.py +++ b/Sqlite/Sqlite.gpr.py @@ -5,6 +5,7 @@ version = '1.0.35', gramps_target_version = "5.1", status = STABLE, # tested with python 3, need to review unicode usage + include_in_listing = False, fname = 'ImportSql.py', import_function = 'importData', extension = "sql" @@ -17,6 +18,7 @@ version = '1.0.34', gramps_target_version = "5.1", status = STABLE, # tested with python 3 but still gives errors + include_in_listing = False, fname = 'ExportSql.py', export_function = 'exportData', extension = "sql",