def match(self, lat, lon): """ coordinates matching. """ rds = float(self.radius) self.places = [] # place for entry in self.place_list: if (math.hypot(lat-float(entry[3]), lon-float(entry[4])) <= rds) == True: # Do we already have this place ? avoid duplicates (country, state, county, place, other) = self.get_location(entry[9]) if not [country, state, county, place, other] in self.places: self.places.append([country, state, county, place, other]) self.warning = False for place in self.dbstate.db.iter_places(): latn = place.get_latitude() lonn = place.get_longitude() if latn and lonn: latn, ignore = conv_lat_lon(latn, "0", "D.D8") if not latn: if not self.warning: self.close() warn1 = _("you have a wrong latitude for:") warn2 = _pd.display(self.dbstate.db, place) + "\n\n<b>" warn2 += _("Please, correct this before linking") + "</b>" WarningDialog(warn1, warn2, parent=self.uistate.window) self.warning = True continue ignore, lonn = conv_lat_lon("0", lonn, "D.D8") if not lonn: if not self.warning: self.close() warn1 = _("you have a wrong longitude for:") + "\n" warn2 = _pd.display(self.dbstate.db, place) + "\n\n<b>" warn2 += _("Please, correct this before linking") + "</b>" WarningDialog(warn1, warn2, parent=self.uistate.window) self.warning = True continue if (math.hypot(lat-float(latn), lon-float(lonn)) <= rds) == True: (country, state, county, place, other) = self.get_location(place.get_gramps_id()) if not [country, state, county, place, other] in self.places: self.places.append([country, state, county, place, other])
def copy_file(self, from_fname, to_fname, to_dir=''): """ Copy a file from a source to a (report) destination. If to_dir is not present, then the destination directory will be created. Normally 'to_fname' will be just a filename, without directory path. 'to_dir' is the relative path name in the destination root. It will be prepended before 'to_fname'. """ #build absolute path dest = os.path.join(self._backend.datadirfull(), to_dir, to_fname) destdir = os.path.dirname(dest) if not os.path.isdir(destdir): os.makedirs(destdir) if from_fname != dest: shutil.copyfile(from_fname, dest) elif self.warn_dir: from gramps.gui.dialog import WarningDialog WarningDialog( _("Possible destination error") + "\n" + _("You appear to have set your target directory " "to a directory used for data storage. This " "could create problems with file management. " "It is recommended that you consider using " "a different directory to store your generated " "web pages.")) self.warn_dir = False
def run(self): """Run function of Remove Tag Tool.""" self.db = self.dbstate.get_database() if not self.__opt_by_name('add_remove'): # when the database is empty, prevent further tool processing # 'add_remove' menu option is not generated when db is empty txt = _("Unable to run the tool. Please check if your database " "contains tags, filters and objects.") WarningDialog(_("WARNING"), txt, parent=self.window) return # stop the tool self.remove = bool(self.__opt_by_name('add_remove').get_value()) tag_info = self.__get_tag_info() tag_value = self.options.handler.options_dict['tag_name'] for info in tag_info: if info[0] == tag_value: self.tag_handle = info[1] self.tag_name = info[2] lst = [ 'Person', 'Family', 'Event', 'Place', 'Source', 'Citation', 'Repository', 'Media', 'Note' ] category_value = self.__opt_by_name('category').get_value() self.__menu_opt_handling(lst[category_value].lower())
def write_family(self, family_handle, person = None): family = self.dbstate.db.get_family_from_handle(family_handle) if family is None: from gramps.gui.dialog import WarningDialog WarningDialog( _('Broken family detected'), _('Please run the Check and Repair Database tool'), parent=self.uistate.window) return father_handle = family.get_father_handle() mother_handle = family.get_mother_handle() if self.get_handle() == father_handle: handle = mother_handle else: handle = father_handle vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) heading = self.write_label(_('Family'), family, False) vbox.pack_start(heading, False, False, 1) if handle or family.get_relationship() != FamilyRelType.UNKNOWN: box = self.write_person(_('Spouse'), handle) if not self.write_relationship_events(box, family): self.write_relationship(box, family) ebox = self.make_dragbox(box, 'Person', handle) vbox.pack_start(ebox, False, False, 1) count = len(family.get_child_ref_list()) ex2 = Gtk.Expander(label='%s (%s):' % (_('Children'), count)) ex2.set_expanded(True) ex2.set_margin_start(24) vbox.pack_start(ex2, False, False, 6) vbox2 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box() addchild = widgets.IconButton(self.add_child_to_fam, family.handle, 'list-add') addchild.set_tooltip_text(_('Add new child to family')) selchild = widgets.IconButton(self.sel_child_to_fam, family.handle, 'gtk-index') selchild.set_tooltip_text(_('Add existing child to family')) hbox.pack_start(addchild, False, True, 0) hbox.pack_start(selchild, False, True, 0) vbox2.pack_start(hbox, False, False, 0) i = 1 child_list = family.get_child_ref_list() for child_ref in child_list: widget = self.write_child(child_ref.ref, i, True) vbox2.pack_start(widget, True, True, 1) i += 1 ex2.add(vbox2) self.vbox2.pack_start(vbox, False, True, 0)
def export_results(self, _button): """ Export the results to a text file. """ chooser = Gtk.FileChooserDialog( _("Export results to a text file"), self.uistate.window, Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK)) chooser.set_do_overwrite_confirmation(True) while True: value = chooser.run() filename = chooser.get_filename() if value == Gtk.ResponseType.OK: if filename: chooser.destroy() break else: chooser.destroy() return try: with io.open(filename, 'w') as report_file: for title, model in zip(self.titles, self.models): self.export_page(report_file, title, model) except IOError as err: WarningDialog(self.window_name, _('Error when writing the report: %s') % err.strerror, self.window)
def link_place(self, menu, event, lat, lon): """ Link an existing place using longitude and latitude of location centered on the map If we have a place history, we must show all places to avoid an empty place selection in the PlaceSelection. """ if self.uistate.get_active('Place'): self._createmap(None) selector = SelectPlace(self.dbstate, self.uistate, []) place = selector.run() if place: parent_list = place.get_placeref_list() if len(parent_list) > 0: parent = parent_list[0].ref else: parent = None places_handle = self.dbstate.db.iter_place_handles() nb_places = 0 gids = "" place_title = _pd.display(self.dbstate.db, place) for place_hdl in places_handle: plce = self.dbstate.db.get_place_from_handle(place_hdl) plce_title = _pd.display(self.dbstate.db, plce) if plce_title == place_title: nb_places += 1 if gids == "": gids = plce.gramps_id else: # TODO for Arabic, should the next comma be translated? gids = gids + ", " + plce.gramps_id if nb_places > 1: from gramps.gui.dialog import WarningDialog WarningDialog( _('You have at least two places with the same title.'), _("The title of the places is:\n%(title)s\n" "The following places are similar: %(gid)s\n" "You should eiher rename the places or merge them.\n\n" "%(bold_start)s" "I can't proceed with your request" "%(bold_end)s.\n") % { 'bold_start' : '<b>', 'bold_end' : '</b>', 'title': '<b>' + place_title + '</b>', 'gid': gids}, parent=self.uistate.window ) else: self.mark = [None, None, None, None, None, None, None, None, None, place.gramps_id, None, None] self.select_fct = PlaceSelection(self.uistate, self.dbstate, self.osm, self.selection_layer, self.place_list, lat, lon, self.__edit_place, parent)
def add_bookmark(self, *obj): mlist = self.selected_handles() if mlist: self.bookmarks.add(mlist[0]) else: from gramps.gui.dialog import WarningDialog WarningDialog(_("Could Not Set a Bookmark"), _("A bookmark could not be set because " "no one was selected."), parent=self.uistate.window)
def __menu_opt_handling(self, category): """General menu option handling.""" iter_ = list(self.db.method('iter_%s_handles', category)()) if iter_ == []: txt = _("No %s objects were found in database." % category) WarningDialog(_("WARNING"), txt, parent=self.window) return # stop the tool filter_opt = self.__opt_by_name(category) filter_ = filter_opt.get_filter() objects = filter_.apply(self.dbstate.db, iter_) self.__remove_from(objects, category)
def add_bookmark(self, menu, handle): if handle: self.uistate.set_active(handle, self.navigation_type()) self.bookmarks.add(handle) self.bookmarks.redraw() else: from gramps.gui.dialog import WarningDialog WarningDialog( _("Could Not Set a Bookmark"), _("A bookmark could not be set because " "no one was selected."))
def link_place(self, menu, event, lat, lon): """ Link an existing place using longitude and latitude of location centered on the map If we have a place history, we must show all places to avoid an empty place selection in the PlaceSelection. """ if self.uistate.get_active('Place'): self._createmap(None) selector = SelectPlace(self.dbstate, self.uistate, []) place = selector.run() if place: parent_list = place.get_placeref_list() if len(parent_list) > 0: parent = parent_list[0].ref else: parent = None places_handle = self.dbstate.db.iter_place_handles() nb_places = 0 gids = "" for place_hdl in places_handle: plce = self.dbstate.db.get_place_from_handle(place_hdl) if plce.get_title() == place.get_title(): nb_places += 1 if gids == "": gids = plce.gramps_id else: gids = gids + ", " + plce.gramps_id if nb_places > 1: from gramps.gui.dialog import WarningDialog WarningDialog( _('You have at least two places with the same title.'), _("The title of the places is :\n" "<b>%(title)s</b>\n" "The following places are similar : %(gid)s\n" "Eiher you rename the places either you merge them." "\n\n<b>I can't proceed your request</b>.\n") % { 'title': place.get_title(), 'gid': gids} ) else: self.mark = [None, None, None, None, None, None, None, None, None, place.gramps_id, None, None] self.select_fct = PlaceSelection(self.uistate, self.dbstate, self.osm, self.selection_layer, self.place_list, lat, lon, self.__edit_place, parent)
def add_bookmark(self, menu): """ Add the place to the bookmark """ mlist = self.selected_handles() if mlist: self.bookmarks.add(mlist[0]) else: from gramps.gui.dialog import WarningDialog WarningDialog( _("Could Not Set a Bookmark"), _("A bookmark could not be set because " "no one was selected."))
def time_str_to_sec(self, time_str): time_sec = None iso_date_time = self.add_time(time_str) try: time_tup = time.strptime(iso_date_time, "%Y-%m-%d %H:%M:%S") time_sec = time.mktime(time_tup) except ValueError: from gramps.gui.dialog import WarningDialog WarningDialog(_("Wrong format of date-time"), _("Only date-times in the iso format of yyyy-mm-dd " "hh:mm:ss, where the time part is optional, are " "accepted. %s does not satisfy.") % iso_date_time) return time_sec
def add_bookmark_from_popup(self, menu, handle): """ Add the place to the bookmark from the popup menu """ if handle: self.uistate.set_active(handle, self.navigation_type()) self.bookmarks.add(handle) self.bookmarks.redraw() else: from gramps.gui.dialog import WarningDialog WarningDialog(_("Could Not Set a Bookmark"), _("A bookmark could not be set because " "no one was selected."), parent=self.uistate.window)
def printview(self, obj): """ Print or save the view that is currently shown """ if Gtk.MAJOR_VERSION == 3 and Gtk.MINOR_VERSION < 11: from gramps.gui.dialog import WarningDialog WarningDialog(_("You can't use the print functionality"), _("Your Gtk version is too old."), parent=self.uistate.window) return req = self.osm.get_allocation() widthpx = req.width heightpx = req.height prt = CairoPrintSave(widthpx, heightpx, self.osm.do_draw, self.osm) prt.run()
def __init__(self, dbstate, user, options_class, name, callback=None): set_det_id(True) uistate = user.uistate if not uistate: return tool.Tool.__init__(self, dbstate, options_class, name) self.window_name = _('Deterministic ID Tool') ManagedWindow.__init__(self, uistate, [], self.__class__) window = MyWindow(dbstate, self.uistate, []) self.set_window(window, None, self.window_name) WarningDialog(self.window_name, _("The ID and handles now start at 0x00000000, and increment by 0x100000001"), self.window) self.close()
def home(self, *obj): """ Move to the default person. """ defperson = self.dbstate.db.get_default_person() if defperson: self.change_active(('Person', defperson.get_handle())) else: from ..dialog import WarningDialog WarningDialog( _("No Home Person"), _("You need to set a 'default person' to go to. " "Select the People View, select the person you want as " "'Home Person', then confirm your choice " "via the menu Edit -> Set Home Person."), parent=self.uistate.window)
def find_an_incomplete_place(self): """ in our db. Will return with a place (and active set to place) or None if no incomplete places, in which case active will be the same. Will also find unused places, and offer to delete.""" p_hndls = self.dbstate.db.get_place_handles() if not p_hndls: return None # in case there aren't any # keep handles in an order to avoid inconsistant # results when db returns them in different orders. p_hndls.sort() # try to find the handle after the previously scanned handle in the # list. found = False for indx, hndl in enumerate(p_hndls): if hndl > self.incomp_hndl: found = True break if not found: indx = 0 # now, starting from previous place, look for incomplete place start = indx while True: hndl = p_hndls[indx] place_data = self.dbstate.db.get_raw_place_data(hndl) p_type = place_data[8][0] # place_type refs = list(self.dbstate.db.find_backlink_handles(hndl)) if(p_type == PlaceType.UNKNOWN or not refs or p_type != PlaceType.COUNTRY and not place_data[5]): # placeref_list # need to get view to this place... self.set_active("Place", hndl) self.incomp_hndl = hndl if not refs: WarningDialog( _('This Place is not used!'), msg2=_('You should delete it, or, if it contains ' 'useful notes or other data, use the Find to ' 'merge it into a valid place.'), parent=self.uistate.window) return self.dbstate.db.get_place_from_handle(hndl) indx += 1 if indx == len(p_hndls): indx = 0 if indx == start: break return None
def on_apply_clicked(self, obj): cfilter = self.filter_model[self.filters.get_active()][1] progress_bar = ProgressMeter(_('Comparing events'), '') progress_bar.set_pass(_('Selecting people'), 1) plist = cfilter.apply(self.db, self.db.iter_person_handles()) progress_bar.step() progress_bar.close() self.options.handler.options_dict['filter'] = self.filters.get_active() # Save options self.options.handler.save_options() if len(plist) == 0: WarningDialog(_("No matches were found")) else: DisplayChart(self.dbstate, self.uistate, plist, self.track)
def add(self, handle): """Append the citation to the bottom of the bookmarks.""" if self.dbstate.db.get_citation_from_handle(handle): ListBookmarks.add(self, handle) else: # Probably trying to bookmark a source when the navigation type is # citation. This can occur when in the Citation Tree View and we # bookmark a source. # FIXME: See http://www.gramps-project.org/bugs/view.php?id=6352 a # more comprehensive solution is needed in the long term. See also # change_active in CitatinTreeView from gramps.gui.dialog import WarningDialog WarningDialog(_("Cannot bookmark this reference"), "Only Citations can be bookmarked in this view. " "You are probably trying to bookmark a Source in the " "Citation Tree View. In this view, only Citations " "can be bookmarked. To bookmark a Source, switch to " "the Source View")
def share(self, obj): """ share: Add a new citation to an existing source (when a source is selected) """ for handle in self.selected_handles(): # The handle will either be a Source handle or a Citation handle source, citation = self.get_source_or_citation(handle) if not source: source = self.dbstate.db.get_source_from_handle( citation.get_reference_handle()) try: EditCitation(self.dbstate, self.uistate, [], Citation(), source) except WindowActiveError: from gramps.gui.dialog import WarningDialog WarningDialog(_("Cannot share this reference"), self.__blocked_text(), parent=self.uistate.window)
def add_bookmark(self, *obj): """ Add a bookmark to the list. """ from gramps.gen.display.name import displayer as name_displayer active_handle = self.uistate.get_active('Person') active_person = self.dbstate.db.get_person_from_handle(active_handle) if active_person: self.bookmarks.add(active_handle) name = name_displayer.display(active_person) self.uistate.push_message(self.dbstate, _("%s has been bookmarked") % name) else: from gramps.gui.dialog import WarningDialog WarningDialog(_("Could Not Set a Bookmark"), _("A bookmark could not be set because " "no one was selected."), parent=self.uistate.window)
def edit(self, obj): """ Edit either a Source or a Citation, depending on user selection """ for handle in self.selected_handles(): # The handle will either be a Source handle or a Citation handle source, citation = self.get_source_or_citation(handle) if citation: try: EditCitation(self.dbstate, self.uistate, [], citation) except WindowActiveError: pass else: try: EditSource(self.dbstate, self.uistate, [], source) except WindowActiveError: from gramps.gui.dialog import WarningDialog WarningDialog(_("Cannot share this reference"), self.__blocked_text2(), parent=self.uistate.window)
def new_clicked(self, obj): """ Create a new To Do note. """ nav_type = self.uistate.viewmanager.active_page.navigation_type() active_handle = self.get_active(nav_type) if active_handle: from gramps.gui.editors import EditNote note = Note() note.set_type(NoteType.TODO) try: EditNote(self.gui.dbstate, self.gui.uistate, [], note, self.created) except WindowActiveError: pass else: WarningDialog( _("No active object"), _("First select the object to which you want to attach a note") + _(":") + _(nav_type), parent=self.uistate.window)
def edit(self, obj): """ Edit either a Source or a Citation, depending on user selection """ for handle in self.selected_handles(): # The handle will either be a Source handle or a Citation handle source = self.dbstate.db.get_source_from_handle(handle) citation = self.dbstate.db.get_citation_from_handle(handle) if (not source and not citation) or (source and citation): raise ValueError("selection must be either source or citation") if citation: try: EditCitation(self.dbstate, self.uistate, [], citation) except WindowActiveError: pass else: # FIXME need try block here try: EditSource(self.dbstate, self.uistate, [], source) except WindowActiveError: from gramps.gui.dialog import WarningDialog WarningDialog(_("Cannot share this reference"), self.__blocked_text2())
def save(self): """ save action """ doc = ODSTab(len(self.stats_list)) doc.creator(self.db.get_researcher().get_name()) name = self.dbstate.db.get_default_person().get_handle() + '.ods' if self.path != '.': name = os.path.join(self.path, name) try: import io io.open(name, "w", encoding='utf8') except PermissionError or IsADirectoryError: WarningDialog(_("You do not have write rights on this folder")) return spreadsheet = TableReport(name, doc) new_titles = [] skip_columns = [] index = 0 for title in self.titles: if title == 'sort': skip_columns.append(index) else: new_titles.append(title) index += 1 spreadsheet.initialize(len(new_titles)) spreadsheet.write_table_head(new_titles) index = 0 for top in self.stats_list: spreadsheet.set_row(index % 2) index += 1 spreadsheet.write_table_data(top, skip_columns) spreadsheet.finalize()
def share(self, obj): """ share: Add a new citation to an existing source (when a source is selected) """ for handle in self.selected_handles(): # The handle will either be a Source handle or a Citation handle source = self.dbstate.db.get_source_from_handle(handle) citation = self.dbstate.db.get_citation_from_handle(handle) if (not source and not citation) or (source and citation): raise ValueError("selection must be either source or citation") if source: try: EditCitation(self.dbstate, self.uistate, [], Citation(), source) except WindowActiveError: from gramps.gui.dialog import WarningDialog WarningDialog(_("Cannot share this reference"), self.__blocked_text()) else: msg = _("Cannot add citation.") msg2 = _("In order to add a citation to an existing source, " " you must select a source.") ErrorDialog(msg, msg2)
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) self.window_name = _('Note Cleanup Tool') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.trans = None self.moved_files = [] self.titles = [_('Cleaned Notes'), _('Links Only'), _('Issues')] self.models = [] self.views = [] self.changelist = [] self.changelistidx = 0 window = MyWindow(self.dbstate, self.uistate, []) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) hbox.set_homogeneous(True) rvbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2, width_request=400) vbox.pack_start(hbox, True, True, 5) self.notebook = Gtk.Notebook() self.notebook.set_scrollable(True) self.notebook.connect('switch-page', self.pagesw) for title in self.titles: self.create_tab(title) hbox.pack_start(self.notebook, True, True, 3) hbox.pack_start(rvbox, True, True, 3) bbox = Gtk.ButtonBox(orientation=Gtk.Orientation.HORIZONTAL) vbox.pack_start(bbox, False, False, 5) close = Gtk.Button(label=_('Close')) close.set_tooltip_text(_('Close the Note Cleanup Tool')) close.connect('clicked', self.close) save = Gtk.Button(label=_('Save All')) save.set_tooltip_text(_('Save All Changes')) save.connect('clicked', self.saveit) search = Gtk.Button(label=_('Search')) search.set_tooltip_text(_('Search for Untidy Notes')) search.connect('clicked', self.cleanup) testnote = Gtk.Button(label=_('Generate Test Notes')) testnote.set_tooltip_text(_( 'Generate Test notes in range N99996-N99999.\n' 'These are added to your database, so you may want to work with' ' a test database or delete them later.')) testnote.connect('clicked', self.gentest) export = Gtk.Button(label=_('Export')) export.set_tooltip_text(_('Export the results to a text file')) export.connect('clicked', self.export_results) bbox.add(search) bbox.add(testnote) bbox.add(export) bbox.add(save) bbox.add(close) self.tb = StyledTextEditor() self.tb.set_editable(False) self.tb.set_wrap_mode(Gtk.WrapMode.WORD) tbw = Gtk.ScrolledWindow() tbw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) tbw.add(self.tb) rvbox.pack_start(tbw, True, True, 0) self.ta = StyledTextEditor() self.ta.set_transient_parent(window) self.ta.set_editable(True) self.ta.set_wrap_mode(Gtk.WrapMode.WORD) taw = Gtk.ScrolledWindow() taw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) taw.add(self.ta) # tat=self.ta.get_toolbar() tat, self.action_group = self.ta.create_toolbar( uistate.uimanager, window) tat.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR) tatb = tat.get_nth_item(5) tat.remove(tatb) tatb = tat.get_nth_item(5) tat.remove(tatb) rvbox.pack_start(tat, False, False, 0) rvbox.pack_start(taw, True, True, 0) self.clear_models() vbox.show_all() window.add(vbox) window.set_size_request(800, 400) self.set_window(window, None, self.window_name) self.show() self.show_tabs() WarningDialog( self.window_name, _("Please back up your database before running this tool.\n\n" "Start the tool by pressing the 'Search' button, then review" " the results.\n" "When satisifed press the 'Save All' button to save your work.\n" "You may export a summary list of the notes that" " were found using the 'Export' button."), self.window)
def calc_url(self): """ Determine the url to use on maps.google.com Logic: valid for places within Sweden and Denmark, only if lat lon avalible use lat lon if present otherwise use city and country if present otherwise use description of the place """ place = self._get_first_place()[0] path = "" # First see if we are in or near Sweden or Denmark # Change country to upper case location = get_main_location(self.database, place) country = location.get(PlaceType.COUNTRY, '').upper().strip() country_given = (country in MAP_NAMES_SWEDEN or \ country in MAP_NAMES_DENMARK) and (country != "") # if no country given, check if we might be in the vicinity defined by # 54 33' 0" < lat < 66 9' 0", 54.55 and 69.05 # 8 3' 0" < long < 24 9' 0", 8.05 and 24.15 latitude, longitude = self._lat_lon(place) if latitude is None or longitude is None: coord_ok = False else: latitude = float(latitude) longitude = float(longitude) # Check if coordinates are inside Sweden and Denmark if (54.55 < latitude < 69.05) and (8.05 < longitude < 24.15): coord_ok = True else: msg2 = _("Latitude not within '54.55' to '69.05'\n") + \ _("Longitude not within '8.05' to '24.15'") WarningDialog(_("Eniro map not available"), msg2 ) return if coord_ok: place_title = _build_title(self.database, place) place_city = _build_city(self.database, place) x_coord, y_coord = self._lat_lon(place, format="RT90") # Set zoom level to 5 if Sweden/Denmark, others 3 zoom = 5 if not country_given: zoom = 3 path = "http://www.eniro.se/partner.fcgi?pis=1&x=%s&y=%s" \ "&zoom_level=%i&map_size=0&title=%s&city=%s&partner=gramps" # Note x and y are swapped! path = path % (y_coord , x_coord, zoom, place_title, place_city) self.url = path.replace(" ","%20") return place_area = _build_area(self.database, place) if country_given and place_area: if country in MAP_NAMES_SWEDEN: path = "http://kartor.eniro.se/query?&what=map_adr&mop=aq" \ "&geo_area=%s&partner=gramps" path = path % (place_area) self.url = path.replace(" ","%20") return else: WarningDialog(_("Eniro map not available"), \ _("Coordinates needed in Denmark") ) self.url = "" return WarningDialog(_("Eniro map not available"), _("Latitude and longitude,\n" \ "or street and city needed") ) return
def verify_media(self, button): """ Verify media objects have the correct path to files in the media directory. List missing files, duplicate files, and files that do not yet have a media file in Gramps. """ self.clear_models() self.moved_files = [] media_path = self.db.get_mediapath() if media_path is None: WarningDialog( self.window_name, _('Media path not set. You must set the "Base path ' 'for relative media paths" in the Preferences.'), self.window) return progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = 0 for root, dirs, files in os.walk(media_path): length += len(files) progress.set_pass(_('Finding files'), length) all_files = {} for root, dirs, files in os.walk(media_path): for file_name in files: full_path = os.path.join(root, file_name) try: with io.open(full_path, 'rb') as media_file: md5sum = hashlib.md5(media_file.read()).hexdigest() except IOError as err: error_msg = '%s: %s' % (err.strerror, full_path) self.models[5].append((error_msg, None)) progress.step() continue rel_path = relative_path(full_path, media_path) if md5sum in all_files: all_files[md5sum].append(rel_path) else: all_files[md5sum] = [rel_path] progress.step() if progress.get_cancelled(): break length = self.db.get_number_of_media() progress.set_pass(_('Checking paths'), length) in_gramps = [] for handle in self.db.get_media_handles(): media = self.db.get_media_from_handle(handle) md5sum = media.get_checksum() in_gramps.append(md5sum) # Moved files gramps_path = media.get_path() if md5sum in all_files: file_path = all_files[md5sum] if gramps_path not in file_path: if len(file_path) == 1: self.moved_files.append((handle, file_path[0])) text = '%s -> %s' % (gramps_path, file_path[0]) self.models[0].append((text, handle)) else: gramps_name = os.path.basename(gramps_path) for path in file_path: if os.path.basename(path) == gramps_name: self.moved_files.append((handle, path)) text = '%s -> %s' % (gramps_path, path) self.models[0].append((text, handle)) elif md5sum is None: text = '[%s] %s' % (media.get_gramps_id(), gramps_path) self.models[4].append((text, str(handle))) else: self.models[1].append((gramps_path, handle)) progress.step() if progress.get_cancelled(): break # Duplicate files or files not in Gramps for md5sum in all_files: if len(all_files[md5sum]) > 1: text = ', '.join(all_files[md5sum]) self.models[2].append((text, all_files[md5sum][0])) if md5sum not in in_gramps: text = ', '.join(all_files[md5sum]) self.models[3].append((text, all_files[md5sum][0])) self.show_tabs() progress.close()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _("Relation and distances with root") self.dbstate = dbstate FilterClass = GenericFilterFactory('Person') self.path = '.' filter = FilterClass() tool.Tool.__init__(self, dbstate, options_class, name) if uistate: window = Gtk.Window() window.set_default_size(880, 600) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) window.add(box) # dirty work-around for Gtk.HeaderBar() and FolderChooser chooser = Gtk.FileChooserDialog( _("Folder Chooser"), parent=uistate.window, action=Gtk.FileChooserAction.SELECT_FOLDER, buttons=(_('_Cancel'), Gtk.ResponseType.CANCEL, _('_Select'), Gtk.ResponseType.OK)) chooser.set_tooltip_text(_("Please, select a folder")) status = chooser.run() if status == Gtk.ResponseType.OK: # work-around 'IsADirectoryError' with self() # TypeError: invalid file: gi.FunctionInfo() self.path = chooser.get_current_folder() chooser.destroy() ManagedWindow.__init__(self, uistate, [], self.__class__) self.titles = [ (_('Rel_id'), 0, 40, INTEGER), # would be INTEGER (_('Relation'), 1, 300, str), (_('Name'), 2, 200, str), (_('up'), 3, 35, INTEGER), (_('down'), 4, 35, INTEGER), (_('Common MRA'), 5, 40, INTEGER), (_('Rank'), 6, 40, INTEGER), (_('Period'), 7, 40, str), ] treeview = Gtk.TreeView() model = ListModel(treeview, self.titles) s = Gtk.ScrolledWindow() s.add(treeview) box.pack_start(s, True, True, 0) button = Gtk.Button(label=_("Save")) button.connect("clicked", self.button_clicked) box.pack_end(button, False, True, 0) self.stats_list = [] # behavior can be different according to CPU and generation depth max_level = config.get('behavior.generation-depth') # compact and interlinked tree # single core 2.80 Ghz needs +/- 0.1 second per person if max_level >= 15: var = max_level * 0.01 elif 10 <= max_level < 15: var = max_level * 0.02 else: var = max_level * 0.025 plist = self.dbstate.db.iter_person_handles() length = self.dbstate.db.get_number_of_people() default_person = self.dbstate.db.get_default_person() if uistate: self.progress = ProgressMeter(self.label, can_cancel=True, parent=window) else: self.progress = ProgressMeter(self.label) if default_person: # rather designed for run via GUI... root_id = default_person.get_gramps_id() ancestors = rules.person.IsAncestorOf([str(root_id), True]) descendants = rules.person.IsDescendantOf([str(root_id), True]) related = rules.person.IsRelatedWith([str(root_id)]) # filtering people can be useful on some large data set # counter on filtering pass was not efficient # Not the proper solution, but a lazy one providing expected message filter.add_rule(related) self.progress.set_pass(_('Please wait, filtering...')) filtered_list = filter.apply(self.dbstate.db, plist) relationship = get_relationship_calculator() else: # TODO: provide selection widget for CLI and GUI WarningDialog(_("No default_person")) return count = 0 filtered_people = len(filtered_list) self.progress.set_pass(_('Generating relation map...'), filtered_people) if self.progress.get_cancelled(): self.progress.close() return step_one = time.clock() # init for counters for handle in filtered_list: nb = len(self.stats_list) count += 1 self.progress.step() step_two = time.clock() start = 99 if count > start: # provide a basic interface for counters need = (step_two - step_one) / count wait = need * filtered_people remain = int(wait) - int(step_two - step_one) # sorry, lazy header = _("%d/%d \n %d/%d seconds \n %d/%d \n%f|\t%f" % (count, filtered_people, remain, int(wait), nb, length, float(need), float(var))) self.progress.set_header(header) if self.progress.get_cancelled(): self.progress.close() return person = dbstate.db.get_person_from_handle(handle) timeout_one = time.clock() # for delta and timeout estimations dist = relationship.get_relationship_distance_new(dbstate.db, default_person, person, only_birth=True) timeout_two = time.clock() rank = dist[0][0] if rank == -1 or rank > max_level: # not related and ignored people continue limit = timeout_two - timeout_one expect = (limit - var) / max_level if limit > var: n = name_displayer.display(person) _LOG.debug("Sorry! '{0}' needs {1} second, \ variation = '{2}'".format(n, limit, expect)) continue else: _LOG.debug("variation = '{}'".format( limit)) # delta, see above max_level 'wall' section rel = relationship.get_one_relationship( dbstate.db, default_person, person) rel_a = dist[0][2] Ga = len(rel_a) rel_b = dist[0][4] Gb = len(rel_b) mra = 1 # m: mother; f: father if Ga > 0: for letter in rel_a: if letter == 'm': mra = mra * 2 + 1 if letter == 'f': mra = mra * 2 # design: mra gender will be often female (m: mother) if rel_a[-1] == "f" and Gb != 0: # male gender, look at spouse mra = mra + 1 name = name_displayer.display(person) # pseudo privacy; sample for DNA stuff and mapping import hashlib no_name = hashlib.sha384(name.encode() + handle.encode()).hexdigest() _LOG.info(no_name) # own internal password via handle kekule = number.get_number(Ga, Gb, rel_a, rel_b) # workaround - possible unique ID and common numbers uuid = str(uuid4()) _LOG.info("Random UUID: {}".format(uuid)) if kekule == "u": # TODO: cousin(e)s need a key kekule = 0 if kekule == "nb": # non-birth kekule = -1 try: test = int(kekule) except: # 1: related to mother; 0.x : no more girls lineage kekule = 1 period = get_timeperiod(self.dbstate.db, handle) # sometimes 'iterator' (generator) is more faster #handle_list = map(handle, filtered_list) iterator = (handle for handle in filtered_list) # experimentations; not used yet new_list = [int(kekule), int(Ga), int(Gb), int(mra), int(rank)] line = (iterator, array('b', new_list)) self.stats_list.append( (int(kekule), rel, name, int(Ga), int(Gb), int(mra), int(rank), str(period))) self.progress.close() from itertools import groupby for key, items in groupby(self.stats_list, lambda x: x[0]): for subitem in items: _LOG.info(subitem) _LOG.debug("total: {}".format(nb)) for entry in self.stats_list: if uistate: model.add(entry, entry[0]) else: print(entry) if uistate: window.show() self.set_window(window, None, self.label) self.show()